From dd7612b7deb9dcccbe26064610999445df19d6ae Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Thu, 11 Apr 2013 11:20:00 +0200 Subject: [PATCH] big changes in the way queries are exposed and triggered one can now specify an optional publish_uuid to asynchroneous_exec updater starts to do real things --- manifold/js/manifold.js | 45 ++++++---- plugins/updater/updater.js | 138 ++++++++++++++++--------------- trash/dashboard.py | 2 +- trash/pluginview.py | 10 ++- trash/sampleviews.py | 2 +- trash/sliceview.py | 2 +- unfold/page.py | 45 ++++++---- unfold/templates/page-queries.js | 9 +- 8 files changed, 143 insertions(+), 110 deletions(-) diff --git a/manifold/js/manifold.js b/manifold/js/manifold.js index 6209085b..4d005d09 100644 --- a/manifold/js/manifold.js +++ b/manifold/js/manifold.js @@ -31,7 +31,7 @@ var manifold = { }, debug_all_queries : function (msg) { for (var query_uuid in manifold.all_queries) { - $.publish("messages:debug","manifold.debug " + msg + " " + query_uuid + " -> " + manifold.all_queries[query_uuid]); + $.publish("/messages/debug","manifold.debug " + msg + " " + query_uuid + " -> " + manifold.all_queries[query_uuid]); } }, @@ -42,34 +42,45 @@ var manifold = { // Executes all async. queries // input queries are specified as a list of {'query_uuid': , 'id': } - asynchroneous_exec : function (query_uuid_domids) { + asynchroneous_exec : function (query_publish_dom_tuples) { // start spinners - if (manifold.asynchroneous_debug) - $.publish("messages.debug","Turning on spin with " + jQuery(".need-spin").length + " matches for .need-spin"); - jQuery('.need-spin').spin(spin_presets); + // in case the spin stuff was not loaded, let's make sure we proceed to the exit + try { + if (manifold.asynchroneous_debug) + $.publish("/messages/debug","Turning on spin with " + jQuery(".need-spin").length + " matches for .need-spin"); + jQuery('.need-spin').spin(spin_presets); + } catch (err) { console.log("Cannot turn on spins " + err); } // We use js function closure to be able to pass the query (array) to the // callback function used when data is received - var success_closure = function(query, id) { - return function(data, textStatus) {manifold.asynchroneous_success(data, query, id);}}; + var success_closure = function(query, publish_uuid, domid) { + return function(data, textStatus) {manifold.asynchroneous_success(data, query, publish_uuid, domid);}}; - // Loop through query array and use ajax to send back query_uuid_domids (to frontend) with json - jQuery.each(query_uuid_domids, function(index, tuple) { + // Loop through input array, and use publish_uuid to publish back results + jQuery.each(query_publish_dom_tuples, function(index, tuple) { var query=manifold.find_query(tuple.query_uuid); var query_json=JSON.stringify (query); + var publish_uuid=tuple.publish_uuid; + // by default we publish using the same uuid of course + if (publish_uuid==undefined) publish_uuid=query.query_uuid; if (manifold.asynchroneous_debug) { - $.publish("messages:debug","sending POST on " + manifold.proxy_url + " with query= " + query.__repr()); + $.publish("/messages/debug","sending POST on " + manifold.proxy_url + " to be published on " + publish_uuid); + $.publish("/messages/debug","... ctd... with actual query= " + query.__repr()); } // not quite sure what happens if we send a string directly, as POST data is named.. // this gets reconstructed on the proxy side with ManifoldQuery.fill_from_POST - jQuery.post(manifold.proxy_url, {'json':query_json} , success_closure(query, tuple.id)); + jQuery.post(manifold.proxy_url, {'json':query_json} , success_closure(query, publish_uuid, tuple.domid)); }) }, - asynchroneous_success : function (data, query, id) { + // if set domid allows the result to be directed to just one plugin + // most of the time publish_uuid will be query.query_uuid + // however in some cases we wish to publish the results under a different uuid + // e.g. an updater wants to publish its results as if from the original (get) query + asynchroneous_success : function (data, query, publish_uuid, domid) { if (manifold.asynchroneous_debug) - $.publish("messages:debug","received manifold result with code " + data.code); + $.publish("/messages/debug","received manifold result with code " + data.code); // xxx should have a nicer declaration of that enum in sync with the python code somehow if (data.code == 1) { alert("Your session has expired, please log in again"); @@ -82,12 +93,14 @@ var manifold = { // once everything is checked we can use the 'value' part of the manifoldresult data=data.value; if (data) { - if (!!id) { + if (!!domid) { /* Directly inform the requestor */ - jQuery('#' + id).trigger('results', [data]); + if (manifold.asynchroneous_debug) $.publish("/messages/debug","directing results to " + domid); + jQuery('#' + domid).trigger('results', [data]); } else { /* Publish an update announce */ - jQuery.publish("/results/" + query.query_uuid + "/changed", [data, query]); + if (manifold.asynchroneous_debug) $.publish("/messages/debug","publishing results on " + publish_uuid); + jQuery.publish("/results/" + publish_uuid + "/changed", [data, query]); } } diff --git a/plugins/updater/updater.js b/plugins/updater/updater.js index 8102c4d6..26390a89 100644 --- a/plugins/updater/updater.js +++ b/plugins/updater/updater.js @@ -28,7 +28,6 @@ /* Subscribe to query updates */ var results_channel = '/results/' + options.query_uuid + '/changed'; $.subscribe(results_channel, function (e,rows) { updater.update_slice (e,rows); } ); - updater.arm_button(); }); }, destroy : function( ) { @@ -52,6 +51,7 @@ // implementation wouldn't fly // we keep this for a later improvement var query=manifold.find_query (options.query_uuid); + console.log("retrieved query " + query.__repr()); // very rough way of filling this for now this.update_query = new ManifoldQuery ("update", query.subject, null, query.filters, @@ -60,91 +60,93 @@ undefined, /* unique */ query.query_uuid, /* tmp */ undefined, undefined /* maybe some day I'll get that one */); + // arm button once document is loaded + (function(updater) {$(document).ready(function(){updater.arm_button()})})(this); this.arm_button = function () { + console.log("arm_button"); $('#updater-' + this.options.plugin_uuid).click(this, this.submit_update_request); }, this.submit_update_request = function (e) { + console.log("submit_update_request"); + var query_uuid = e.data.options.query_uuid; var update_query = e.data.update_query; - $.publish("messages:debug","Updater.submit_update_request " + update_query.__repr()); - // xxx here - we need a valid query_uuid so the results will make it - manifold.asynchroneous_exec ( [ {'query_uuid': xxx, 'id': null}]); + $.publish("/messages/debug","Updater.submit_update_request " + update_query.__repr()); + // publish results as if coming from the original query + manifold.asynchroneous_exec ( [ {'query_uuid': query_uuid, 'publish_uuid' : update_query.query_uuid} ]); // looks like a previous attempt to disable the button while the query is flying //$('#updateslice-' + options.plugin_uuid).prop('disabled', true); - } - }; + }, - /* Private methods */ + update_resources = function (e, resources, change) { + data = e.data.instance.data().Slices; - function update_resources(e, resources, change) { - data = e.data.instance.data().Slices; - - data.update_query.params['resource'] = resources - $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); - } + data.update_query.params['resource'] = resources + $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); + }, - function update_leases(e, leases, change) { - data = e.data.instance.data().Slices; - - data.update_query.params['lease'] = leases - $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); - } + update_leases = function (e, leases, change) { + data = e.data.instance.data().Slices; + + data.update_query.params['lease'] = leases + $.publish('/update/' + data.options.query_uuid, [data.update_query, true]); + }, - function update_slice(e, rows, query) { - /* This function is called twice : get and update */ + update_slice = function (e, rows, query) { + /* This function is called twice : get and update */ - var data = e.data.instance.data().Slices; + var data = e.data.instance.data().Slices; - /* Update placeholders and trigger subqueries updates */ - if (rows.length == 0) { - alert("no result"); - return; - } - var slice = rows[0]; + /* Update placeholders and trigger subqueries updates */ + if (rows.length == 0) { + alert("no result"); + return; + } + var slice = rows[0]; - /* for get */ - if (data.update_query == null) { - data.update_query = new Query('update','slice', 'now', query.filter, {"resource": null, "lease": null}, query.fields, 0, data.options.query_uuid); - } - /* In case of update the list of resources and leases should be updated accordingly */ + /* for get */ + if (data.update_query == null) { + data.update_query = new Query('update','slice', 'now', query.filter, {"resource": null, "lease": null}, query.fields, 0, data.options.query_uuid); + } + /* In case of update the list of resources and leases should be updated accordingly */ - /* only for get ? */ - $.each(slice, function(key, value) { - if (typeof value == 'string') { - $('#myslice__' + key).html(value); - } - }); - - /* TODO avoid repetitions + made this code generic and plugin-independent */ + /* only for get ? */ + $.each(slice, function(key, value) { + if (typeof value == 'string') { + $('#myslice__' + key).html(value); + } + }); - if (query.method == 'update') { - // XXX NON, les uuid doivent etre les memes que dans la query Get, cet appel devrait etre fait avant. - query.analyzed_subqueries(); - } + /* TODO avoid repetitions + made this code generic and plugin-independent */ + + if (query.method == 'update') { + // XXX NON, les uuid doivent etre les memes que dans la query Get, cet appel devrait etre fait avant. + query.analyzed_subqueries(); + } - /* NOTE: Dans le cadre d'un update, on n'a pas besoin de refaire tout - * le query plan et obtenir toutes les infos, par contre on ne peut pas - * savoir d'avance quels parametres ont été accordés, changés, etc. - * Dans le cas général, ca pourrait affecter le query plan... - * Par contre on n'a pas d'information sur toutes les resources, mais - * uniquement celles dans la liste. Comment gérer ? - */ - - /* Inform child plugins about their respective parts of the results */ - /* Only for get */ - var r_subq = query.analyzed_query.subqueries['resource']; - var l_subq = query.analyzed_query.subqueries['lease']; - $.publish('/results/' + r_subq.uuid + '/changed', [slice['resource'], r_subq]); - $.publish('/results/' + l_subq.uuid + '/changed', [slice['lease'], l_subq]); - - /* Subscribe to get notifications from child plugins */ - if (!data.child_subscribe) { - $.subscribe('/update-set/' + r_subq.uuid, {instance: e.data.instance}, update_resources); - $.subscribe('/update-set/' + l_subq.uuid, {instance: e.data.instance}, update_leases); - data.child_subscribe = true - } - + /* NOTE: Dans le cadre d'un update, on n'a pas besoin de refaire tout + * le query plan et obtenir toutes les infos, par contre on ne peut pas + * savoir d'avance quels parametres ont été accordés, changés, etc. + * Dans le cas général, ca pourrait affecter le query plan... + * Par contre on n'a pas d'information sur toutes les resources, mais + * uniquement celles dans la liste. Comment gérer ? + */ + + /* Inform child plugins about their respective parts of the results */ + /* Only for get */ + var r_subq = query.analyzed_query.subqueries['resource']; + var l_subq = query.analyzed_query.subqueries['lease']; + $.publish('/results/' + r_subq.uuid + '/changed', [slice['resource'], r_subq]); + $.publish('/results/' + l_subq.uuid + '/changed', [slice['lease'], l_subq]); + + /* Subscribe to get notifications from child plugins */ + if (!data.child_subscribe) { + $.subscribe('/update-set/' + r_subq.uuid, {instance: e.data.instance}, update_resources); + $.subscribe('/update-set/' + l_subq.uuid, {instance: e.data.instance}, update_leases); + data.child_subscribe = true + } + + } } - })( jQuery ); diff --git a/trash/dashboard.py b/trash/dashboard.py index 6f97a0a7..6d6de77b 100644 --- a/trash/dashboard.py +++ b/trash/dashboard.py @@ -96,7 +96,7 @@ def dashboard_view (request): page.add_css_files ( 'css/dashboard.css') # don't forget to run the requests - page.exec_queue_asynchroneously () + page.expose_queries () # xxx create another plugin with the same query and a different layout (with_datatables) # show that it worls as expected, one single api call to backend and 2 refreshed views diff --git a/trash/pluginview.py b/trash/pluginview.py index 190533b0..f9c96635 100644 --- a/trash/pluginview.py +++ b/trash/pluginview.py @@ -16,6 +16,7 @@ from plugins.lists.staticlist import StaticList from plugins.quickfilter.quickfilter import QuickFilter from plugins.raw.raw import Raw from plugins.messages.messages import Messages +from plugins.hazelnut.hazelnut import Hazelnut from plugins.updater.updater import Updater from myslice.viewutils import topmenu_items, the_user @@ -36,6 +37,7 @@ def test_plugin_view (request): fields=['network','type','hrn','hostname'], filters= [ [ 'slice_hrn', '=', slicename, ] ], ) + page.enqueue_query (main_query, run_it=False) main_plugin = \ Stack ( @@ -43,10 +45,14 @@ def test_plugin_view (request): title='thestack', togglable=False, sons=[ \ +# Hazelnut (page=page, +# query=main_query, +# ), Messages ( page=page, title="Runtime messages", domid="msgs-pre", + levels='ALL', ), Updater ( page=page, @@ -64,8 +70,8 @@ def test_plugin_view (request): template_env [ 'topmenu_items' ] = topmenu_items('plugin', request) template_env [ 'username' ] = the_user (request) - # we don't have anythong asynchroneous, and manifold.js is not loaded -# page.exec_queue_asynchroneously () + # run queries when we have any + page.expose_queries () # the prelude object in page contains a summary of the requirements() for all plugins # define {js,css}_{files,chunks} diff --git a/trash/sampleviews.py b/trash/sampleviews.py index f0324ec0..81ad313c 100644 --- a/trash/sampleviews.py +++ b/trash/sampleviews.py @@ -100,7 +100,7 @@ def test_plugin_view (request): template_env [ 'username' ] = the_user (request) # we don't have anythong asynchroneous, and manifold.js is not loaded -# page.exec_queue_asynchroneously () +# page.expose_queries () # the prelude object in page contains a summary of the requirements() for all plugins # define {js,css}_{files,chunks} diff --git a/trash/sliceview.py b/trash/sliceview.py index 7345e626..456d635d 100644 --- a/trash/sliceview.py +++ b/trash/sliceview.py @@ -152,7 +152,7 @@ if I keep this active, so for now it's disabled template_env [ 'username' ] = the_user (request) # don't forget to run the requests - page.exec_queue_asynchroneously () + page.expose_queries () # xxx create another plugin with the same query and a different layout (with_datatables) # show that it worls as expected, one single api call to backend and 2 refreshed views diff --git a/unfold/page.py b/unfold/page.py index 43ad76ea..fe9412a7 100644 --- a/unfold/page.py +++ b/unfold/page.py @@ -41,29 +41,40 @@ class Page: def get_plugin (self, domid): return self._plugins.get(domid,None) - - def reset_queue (self): - self._queries = set() - self._queue = [] - - # the js async methods (see manifold.asynchroneous_success) - # offer the option to deliver the result to a specific DOM elt - # otherwise (i.e. if domid not provided) - # it goes through the pubsub using query's uuid - def enqueue_query (self, query, domid=None): - self._queries = self._queries.union(set( [ query, ] )) - self._queue.append ( (query.query_uuid,domid,) ) - # return the javascript that triggers all the queries - # xxx could fruitfully be renamed expose_queries_to_javascript or something - def exec_queue_asynchroneously (self): + # not sure this is useful at all +# def reset_queue (self): +# self._queries = set() +# self._queue = [] + + # this method adds a query to the page + # the query will be exposed to js when calling expose_queries + # additionally if exec is set to True, this query will be asynchroneously triggered on page load + # in this case (exec=True) the js async callback (see manifold.asynchroneous_success) + # offers the option to deliver the result to a specific DOM elt (in this case, set domid) + # otherwise (i.e. if domid not provided), it goes through the pubsub system (so all plugins can receive it) + def enqueue_query (self, query, run_it=True, domid=None): + # _queries is the set of all known queries + self._queries = self._queries.union(set( [ query, ] )) + # _queue is the list of queries that need to be triggered, with an optional domid + # we only do this if run_it is set + if run_it: self._queue.append ( (query.query_uuid,domid) ) + + # return the javascript code for exposing queries + # all queries are inserted in the global manifold object + # in addition, the ones enqueued with 'run_it=True' are triggered + def expose_queries (self): # compute variables to expose to the template env = {} # expose the json definition of all queries env['queries_json'] = [ query.to_json() for query in self._queries ] - env['query_uuid_domids'] = [ {'query_uuid' : a, 'domid': '"%s"'%b if b else 'null'} for (a,b) in self._queue ] + def query_publish_dom_tuple (a,b): + result={'query_uuid':a} + if b: result['domid']=b + return result + env['query_publish_dom_tuples'] = [ query_publish_dom_tuple (a,b) for (a,b) in self._queue ] javascript = render_to_string ("page-queries.js",env) - self.reset_queue() +# self.reset_queue() self.add_js_chunks (javascript) diff --git a/unfold/templates/page-queries.js b/unfold/templates/page-queries.js index d4e29a6e..1df8d9bd 100644 --- a/unfold/templates/page-queries.js +++ b/unfold/templates/page-queries.js @@ -1,8 +1,9 @@ -{% for json in queries_json %} manifold.insert_query({{ json|safe }}); +{% for json in queries_json %}manifold.insert_query({{ json|safe }}); {% endfor %} $(document).ready(function () { - var query_uuid_domids = new Array(); -{% for d in query_uuid_domids %} query_uuid_domids.push({'query_uuid':"{{ d.query_uuid }}", 'id':{{ d.domid }}}); +var query_publish_dom_tuples = new Array(); +{% for d in query_publish_dom_tuples %}try {query_publish_dom_tuples.push({'query_uuid':"{{ d.query_uuid }}"{%if d.domid %},'domid':"{{ d.domid }}"{% endif %}}) } +catch(err){console.log ("Could not expose query {{ d.query_uuid }}")} {% endfor %} - manifold.asynchroneous_exec(query_uuid_domids); +manifold.asynchroneous_exec(query_publish_dom_tuples); }) -- 2.43.0