Merge remote-tracking branch 'origin/devel' into devel

This commit is contained in:
Gina Häußge 2016-10-04 12:28:11 +02:00
commit ad21bbb2ff
8 changed files with 248 additions and 25 deletions

View file

@ -102,7 +102,7 @@
Instructs the server to decrease the message rate by 500ms.
.. sec-jsclient-socket-throttling:
.. _sec-jsclient-socket-throttling:
Communication Throttling
========================

View file

@ -3,26 +3,87 @@
:mod:`OctoPrint.timelapse`
--------------------------
.. todo::
.. js:function:: OctoPrint.timelapse.get(unrendered, opts)
Needs to be documented
Get a list of all timelapses and the current timelapse config.
.. js:function:: OctoPrint.timelapse.get(opts)
If ``unrendered`` is true, also retrieve the list of unrendered
timelapses.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.list(opts)
Get the lists of rendered and unrendered timelapses. The returned promis
will be resolved with an object containing the properties ``rendered``
which will have the list of rendered timelapses, and ``unrendered`` which
will have the list of unrendered timelapses.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.listRendered(opts)
Get the list of rendered timelapses.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.listUnrendered(opts)
Get the list of unrendered timelapses.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.download(filename, opts)
Download the rendered timelapse ``filename``.
:param string filename: The name of the rendered timelapse to download
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.delete(filename, opts)
Delete the rendered timelapse ``filename``.
:param string filename: The name of the rendered timelapse to delete
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.deleteUnrendered(name, opts)
Delete the unrendered timelapse ``name``.
:param string name: The name of the unrendered timelapse to delete
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.renderUnrendered(name, opts)
Render the unrendered timelapse ``name``.
:param string name: The name of the unrendered timelapse to render
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.getConfig(opts)
Get the current timelapse configuration.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.timelapse.saveConfig(config, opts)
Save the timelapse configuration.
:param object config: The config to save
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. seealso::
:ref:`Timelapse API <sec-api-timelapse>`

View file

@ -3,31 +3,104 @@
:mod:`OctoPrint.users`
----------------------
.. todo::
.. note::
Needs to be documented
Most methods here require that the used API token or a the existing browser session
has admin rights *or* corresponds to the user to be modified. Some methods
definitely require admin rights.
.. js:function:: OctoPrint.users.list(opts)
Get a list of all registered users.
Requires admin rights.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.get(name, opts)
Get information about a specific user.
:param string name: The user's name
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.add(user, opts)
Add a new user.
Requires admin rights.
:param object user: The new user
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.update(name, active, admin, opts)
Update an existing user.
Requires admin rights.
:param string name: The user's name
:param bool active: The new ``active`` state of the user
:param bool admin: The new ``admin`` state of the user
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.delete(name, opts)
Delete an existing user.
Requires admin rights.
:param string name: The user's name
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.changePassword(name, password, opts)
Change the password for a user.
:param string name: The user's name
:param string password: The new password
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.generateApiKey(name, opts)
Generate a new API key for a user.
:param string name: The user's name
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.resetApiKey(name, opts)
Reset the API key for a user to being unset.
:param string name: The user's name
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.getSettings(name, opts)
Get the settings for a user.
:param string name: The user's name
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.users.saveSettings(name, settings, opts)
Save the settings for a user.
:param string name: The user's name
:param object settings: The new settings, may be a partial set of settings which will be merged unto the current ones
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. seealso::
:ref:`User API <sec-api-users>`
:ref:`User API <sec-api-user>`
The documentation of the underlying user API.

View file

@ -3,10 +3,27 @@
:mod:`OctoPrint.wizard`
-----------------------
.. todo::
.. note::
Needs to be documented
All methods here require that the used API token or a the existing browser session
has admin rights.
.. js:function:: OctoPrint.wizard.get(opts)
Retrieve additional data about registered wizards.
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. js:function:: OctoPrint.wizard.finish(handled, opts)
Inform wizards that the wizard dialog has been finished.
:param list handled: List of identifiers of handled wizards
:param object opts: Additional options for the request
:returns Promise: A `jQuery Promise <http://api.jquery.com/Types/#Promise>`_ for the request's response
.. seealso::
:ref:`Wizard API <sec-api-wizard>`
The documentation of the underlying wizard API.

View file

@ -473,7 +473,9 @@ class LessSimpleCache(BaseCache):
def __init__(self, threshold=500, default_timeout=300):
BaseCache.__init__(self, default_timeout=default_timeout)
self._mutex = threading.RLock()
self._cache = {}
self._bypassed = set()
self.clear = self._cache.clear
self._threshold = threshold
@ -482,27 +484,35 @@ class LessSimpleCache(BaseCache):
now = time.time()
for idx, (key, (expires, _)) in enumerate(self._cache.items()):
if expires is not None and expires <= now or idx % 3 == 0:
self._cache.pop(key, None)
with self._mutex:
self._cache.pop(key, None)
def get(self, key):
import pickle
now = time.time()
expires, value = self._cache.get(key, (0, None))
with self._mutex:
expires, value = self._cache.get(key, (0, None))
if expires is None or expires > now:
return pickle.loads(value)
def set(self, key, value, timeout=None):
import pickle
self._prune()
self._cache[key] = (self.calculate_timeout(timeout=timeout),
pickle.dumps(value, pickle.HIGHEST_PROTOCOL))
with self._mutex:
self._prune()
self._cache[key] = (self.calculate_timeout(timeout=timeout),
pickle.dumps(value, pickle.HIGHEST_PROTOCOL))
if key in self._bypassed:
self._bypassed.remove(key)
def add(self, key, value, timeout=None):
self.set(key, value, timeout=None)
self._cache.setdefault(key, self._cache[key])
with self._mutex:
self.set(key, value, timeout=None)
self._cache.setdefault(key, self._cache[key])
def delete(self, key):
self._cache.pop(key, None)
with self._mutex:
self._cache.pop(key, None)
def calculate_timeout(self, timeout=None):
if timeout is None:
@ -514,7 +524,8 @@ class LessSimpleCache(BaseCache):
def over_threshold(self):
if self._threshold is None:
return False
return len(self._cache) > self._threshold
with self._mutex:
return len(self._cache) > self._threshold
def __getitem__(self, key):
return self.get(key)
@ -526,7 +537,16 @@ class LessSimpleCache(BaseCache):
return self.delete(key)
def __contains__(self, key):
return key in self._cache
with self._mutex:
return key in self._cache
def set_bypassed(self, key):
with self._mutex:
self._bypassed.add(key)
def is_bypassed(self, key):
with self._mutex:
return key in self._bypassed
_cache = LessSimpleCache()
@ -552,11 +572,13 @@ def cached(timeout=5 * 60, key=lambda: "view:%s" % flask.request.path, unless=No
# bypass the cache if "unless" condition is true
if callable(unless) and unless():
logger.debug("Cache for {path} bypassed, calling wrapped function".format(path=flask.request.path))
_cache.set_bypassed(cache_key)
return f_with_duration(*args, **kwargs)
# also bypass the cache if it's disabled completely
if not settings().getBoolean(["devel", "cache", "enabled"]):
logger.debug("Cache for {path} disabled, calling wrapped function".format(path=flask.request.path))
_cache.set_bypassed(cache_key)
return f_with_duration(*args, **kwargs)
rv = _cache.get(cache_key)
@ -575,6 +597,7 @@ def cached(timeout=5 * 60, key=lambda: "view:%s" % flask.request.path, unless=No
# do not store if the "unless_response" condition is true
if callable(unless_response) and unless_response(rv):
logger.debug("Not caching result for {path} (key: {key}), bypassed".format(path=flask.request.path, key=cache_key))
_cache.set_bypassed(cache_key)
return rv
# store it in the cache
@ -591,6 +614,11 @@ def is_in_cache(key=lambda: "view:%s" % flask.request.path):
key = key()
return key in _cache
def is_cache_bypassed(key=lambda: "view:%s" % flask.request.path):
if callable(key):
key = key()
return _cache.is_bypassed(key)
def cache_check_headers():
return "no-cache" in flask.request.cache_control or "no-cache" in flask.request.pragma

View file

@ -146,6 +146,9 @@ def in_cache():
elif util.flask.is_in_cache(key):
_logger.info("Found path {} in cache (key: {}), signaling as cached".format(path, key))
return response
elif util.flask.is_cache_bypassed(key):
_logger.info("Path {} was bypassed from cache (key: {}), signaling as cached".format(path, key))
return response
else:
_logger.debug("Path {} not yet cached (key: {}), signaling as missing".format(path, key))
return abort(404)

View file

@ -7,25 +7,52 @@
})(window || this, function(OctoPrint, $) {
var url = "api/timelapse";
var downloadUrl = "downloads/timelapse";
var timelapseUrl = function(filename) {
return url + "/" + filename;
};
var timelapseDownloadUrl = function(filename) {
return downloadUrl + "/" + filename;
};
var unrenderedTimelapseUrl = function(name) {
return url + "/unrendered/" + name;
};
var getTimelapseData = function (opts) {
var getTimelapseData = function (unrendered, opts) {
if (unrendered) {
opts = opts || {};
opts.data = {unrendered: unrendered};
}
return OctoPrint.get(url, opts);
};
OctoPrint.timelapse = {
get: getTimelapseData,
list: function (opts) {
list: function(opts) {
var deferred = $.Deferred();
getTimelapseData(opts)
getTimelapseData(true, opts)
.done(function (response, status, request) {
deferred.resolve({
rendered: response.files,
unrendered: response.unrendered
}, status, request);
})
.fail(function () {
deferred.reject.apply(null, arguments);
});
return deferred.promise();
},
listRendered: function (opts) {
var deferred = $.Deferred();
getTimelapseData(false, opts)
.done(function (response, status, request) {
deferred.resolve(response.files, status, request);
})
@ -36,8 +63,22 @@
return deferred.promise();
},
listUnrendered: function (opts) {
var deferred = $.Deferred();
getTimelapseData(true, opts)
.done(function (response, status, request) {
deferred.resolve(response.unrendered, status, request);
})
.fail(function () {
deferred.reject.apply(null, arguments);
});
return deferred.promise();
},
download: function (filename, opts) {
return OctoPrint.download(timelapseUrl(filename), opts);
return OctoPrint.download(timelapseDownloadUrl(filename), opts);
},
delete: function (filename, opts) {
@ -54,7 +95,7 @@
getConfig: function (opts) {
var deferred = $.Deferred();
getTimelapseData(opts)
getTimelapseData(false, opts)
.done(function (response, status, request) {
deferred.resolve(response.config, status, request);
})

View file

@ -125,7 +125,7 @@ $(function() {
);
self.requestData = function() {
OctoPrint.timelapse.get({ data: { unrendered: true} })
OctoPrint.timelapse.get(true)
.done(self.fromResponse);
};