From 64f989e3ca09aed5d64b84bf7355cdc12b1aa9b9 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Thu, 1 May 2014 11:33:29 -0700 Subject: [PATCH] Support public flag for StateEntry --- api.py | 29 ++++------------------------- lib/models.py | 11 ++++++++--- lib/utils.py | 10 +++++++++- static/cosmopolite.js | 17 ++++++++++++----- static/debug.html | 37 ++++++++++++++++++++++++++----------- 5 files changed, 59 insertions(+), 45 deletions(-) diff --git a/api.py b/api.py index ab75616..9b0f8e3 100644 --- a/api.py +++ b/api.py @@ -51,6 +51,7 @@ class SetValue(webapp2.RequestHandler): def post(self): entry_key = self.request.get('key') entry_value = self.request.get('value') + public = (self.request.get('public') == 'true') entries = (models.StateEntry.all() .ancestor(self.client.parent_key()) @@ -59,11 +60,13 @@ class SetValue(webapp2.RequestHandler): if entries: entry = entries[0] entry.entry_value = entry_value + entry.public = public else: entry = models.StateEntry( parent=self.client.parent_key(), entry_key=entry_key, - entry_value=entry_value) + entry_value=entry_value, + public=public) entry.put() msg = entry.ToMessage() @@ -75,29 +78,6 @@ class SetValue(webapp2.RequestHandler): return {} -class GetValue(webapp2.RequestHandler): - @utils.chaos_monkey - @utils.returns_json - @utils.local_namespace - @security.google_user_xsrf_protection - @security.weak_security_checks - @session.session_required - @db.transactional() - def post(self): - entry_key = self.request.get('key') - - entries = (models.StateEntry.all() - .ancestor(self.client.parent_key()) - .filter('entry_key =', entry_key) - .fetch(1)) - if entries: - return { - 'value': entries[0].entry_value - } - - return {} - - class CreateChannel(webapp2.RequestHandler): @utils.chaos_monkey @utils.returns_json @@ -119,6 +99,5 @@ class CreateChannel(webapp2.RequestHandler): app = webapp2.WSGIApplication([ (config.URL_PREFIX + '/api/createChannel', CreateChannel), (config.URL_PREFIX + '/api/getUser', GetUser), - (config.URL_PREFIX + '/api/getValue', GetValue), (config.URL_PREFIX + '/api/setValue', SetValue), ]) diff --git a/lib/models.py b/lib/models.py index be047b9..b20b513 100644 --- a/lib/models.py +++ b/lib/models.py @@ -19,6 +19,8 @@ import logging from google.appengine.api import channel from google.appengine.ext import db +import utils + # Profile # ↳ Client @@ -94,7 +96,7 @@ class Client(db.Model): return cls.FromProfile(profile) def SendMessage(self, msg): - channel.send_message(str(self.key()), json.dumps(msg)) + channel.send_message(str(self.key()), json.dumps(msg, default=utils.EncodeJSON)) class StateEntry(db.Model): @@ -103,12 +105,15 @@ class StateEntry(db.Model): last_set = db.DateTimeProperty(required=True, auto_now=True) entry_key = db.StringProperty(required=True) entry_value = db.StringProperty() + public = db.BooleanProperty(required=True, default=False) def ToMessage(self): return { 'message_type': 'state', - 'key': self.entry_key, - 'value': self.entry_value, + 'key': self.entry_key, + 'value': self.entry_value, + 'last_set': self.last_set, + 'public': self.public, } diff --git a/lib/utils.py b/lib/utils.py index 54363ad..43e6502 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import datetime import functools import json import random +import time from google.appengine.api import namespace_manager @@ -27,7 +29,7 @@ def returns_json(handler): @functools.wraps(handler) def SerializeResult(self): - json.dump(handler(self), self.response.out) + json.dump(handler(self), self.response.out, default=EncodeJSON) return SerializeResult @@ -54,3 +56,9 @@ def local_namespace(handler): return handler(self) return SetNamespace + + +def EncodeJSON(o): + if isinstance(o, datetime.datetime): + return time.mktime(o.timetuple()) + return json.JSONEncoder.default(o) diff --git a/static/cosmopolite.js b/static/cosmopolite.js index 5d224df..8a09bcf 100644 --- a/static/cosmopolite.js +++ b/static/cosmopolite.js @@ -144,10 +144,11 @@ cosmopolite.Client.prototype.getUser_ = function() { }); }; -cosmopolite.Client.prototype.setValue = function(key, value) { +cosmopolite.Client.prototype.setValue = function(key, value, is_public) { this.sendRPC_('setValue', { 'key': key, 'value': value, + 'public': is_public, }) // Provide immediate feedback without waiting for a round trip. // We'll also get a response from the server, so this should be eventually @@ -200,14 +201,20 @@ cosmopolite.Client.prototype.onServerMessage_ = function(msg) { switch (msg.message_type) { case 'state': var key = msg['key']; - var value = msg['value']; - if (this.stateCache_[key] == value) { + if (this.stateCache_[key] && + this.stateCache_[key]['value'] == msg['value'] && + this.stateCache_[key]['last_set'] == msg['last_set'] && + this.stateCache_[key]['public'] == msg['public']) { // Duplicate message. break; } - this.stateCache_[key] = value; + this.stateCache_[key] = { + 'value': msg['value'], + 'last_set': msg['last_set'], + 'public': msg['public'], + } if ('onStateChange' in this.callbacks_) { - this.callbacks_['onStateChange'](key, value); + this.callbacks_['onStateChange'](key, this.stateCache_[key]); } break; default: diff --git a/static/debug.html b/static/debug.html index 08bb547..1a7234f 100644 --- a/static/debug.html +++ b/static/debug.html @@ -11,23 +11,35 @@ a {
Google user:
- Key: - - - -
- +
+ Key: + + + +
+
+ Last set: + +
+
+ Public +
+
+ +