dbus: add file format version negotiation for the JSON data

Export the supported versions in a Manager property and require the client to
request a specific version in GetJSONData. Without that, the server could
never update the format and clients would have to support every single
historical version to make sure they can run against any version server.

Fixes #98
This commit is contained in:
Peter Hutterer 2018-02-19 10:51:39 +10:00
parent d4ea6e3938
commit caf1264952
3 changed files with 35 additions and 5 deletions

View File

@ -94,6 +94,12 @@ org.freedesktop.tuhi1.Manager
Read-only Read-only
Property: JSONDataVersions (au)
Specifies the JSON file format versions the server supports. The
client must request one of these versions in Device.GetJSONData().
Read-only, constant
Method: StartSearch() -> () Method: StartSearch() -> ()
Start searching for available devices ready for registering Start searching for available devices ready for registering
for an unspecified timeout. When the timeout expires or an error for an unspecified timeout. When the timeout expires or an error
@ -295,14 +301,17 @@ org.freedesktop.tuhi1.Device
arriving, the device may still send events. It's the responsibility of arriving, the device may still send events. It's the responsibility of
the client to handle events until the LiveStopped signal arrives. the client to handle events until the LiveStopped signal arrives.
Method: GetJSONData(timestamp: t) -> (s) Method: GetJSONData(file-version: u, timestamp: t) -> (s)
Returns a JSON file with the drawings specified by the timestamp Returns a JSON file with the drawings specified by the timestamp
argument. The requested timestamp must be one of the entries in the argument. The requested timestamp must be one of the entries in the
DrawingsAvailable property value. See section JSON FILE DrawingsAvailable property value. The file-version argument specifies
the file format version the client requests. See section JSON FILE
FORMAT for the format of the returned data. FORMAT for the format of the returned data.
Returns a string representing the JSON data from the last drawings or Returns a string representing the JSON data from the last drawings or
the empty string if the timestamp is not available. the empty string if the timestamp is not available or the file format
version is outside the server-supported range advertised in
Manager.JSONDataVersions.
Signal: ButtonPressRequired() Signal: ButtonPressRequired()
Sent when the user is expected to press the physical button on the Sent when the user is expected to press the physical button on the
@ -368,6 +377,12 @@ org.freedesktop.tuhi1.Device
JSON File Format JSON File Format
---------------- ----------------
The current file format version is 1. A server may only support a subset of
historical file formats, this subset is advertized as list of versions in
the **org.freedesktop.tuhi1.Manager.JSONDataVersions** property. Likewise, a
client may only support a subset of the possible formats. A client should
always pick the highest format supported by both the client and the server.
Below is the example file format (with comments, not present in the real Below is the example file format (with comments, not present in the real
files). The JSON objects are "drawing" (the root object), "strokes", files). The JSON objects are "drawing" (the root object), "strokes",
"points". Pseudo-code is used to illustrate the objects in the file. "points". Pseudo-code is used to illustrate the objects in the file.

View File

@ -271,7 +271,8 @@ class TuhiKeteDevice(_DBusObject):
self.live = False self.live = False
def json(self, timestamp): def json(self, timestamp):
return self.proxy.GetJSONData('(t)', timestamp) SUPPORTED_FILE_FORMAT = 1
return self.proxy.GetJSONData('(ut)', SUPPORTED_FILE_FORMAT, timestamp)
def _on_signal_received(self, proxy, sender, signal, parameters): def _on_signal_received(self, proxy, sender, signal, parameters):
if signal == 'ButtonPressRequired': if signal == 'ButtonPressRequired':

View File

@ -15,6 +15,7 @@ import logging
import errno import errno
from gi.repository import GObject, Gio, GLib from gi.repository import GObject, Gio, GLib
from .drawing import Drawing
logger = logging.getLogger('tuhi.dbus') logger = logging.getLogger('tuhi.dbus')
@ -29,6 +30,10 @@ INTROSPECTION_XML = '''
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/> <annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='true'/>
</property> </property>
<property type='au' name='JSONDataVersions' access='read'>
<annotation name='org.freedesktop.DBus.Property.EmitsChangedSignal' value='const'/>
</property>
<method name='StartSearch'> <method name='StartSearch'>
<annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/> <annotation name='org.freedesktop.DBus.Method.NoReply' value='true'/>
</method> </method>
@ -87,6 +92,7 @@ INTROSPECTION_XML = '''
</method> </method>
<method name='GetJSONData'> <method name='GetJSONData'>
<arg name='file_version' type='u' direction='in'/>
<arg name='timestamp' type='t' direction='in'/> <arg name='timestamp' type='t' direction='in'/>
<arg name='json' type='s' direction='out'/> <arg name='json' type='s' direction='out'/>
</method> </method>
@ -427,7 +433,12 @@ class TuhiDBusDevice(_TuhiDBus):
self.live = False self.live = False
def _json_data(self, args): def _json_data(self, args):
index = args[0] file_format = args[0]
if file_format != Drawing.JSON_FILE_FORMAT_VERSION:
logger.info(f'Unsupported file format requested: {file_format}')
return ''
index = args[1]
try: try:
drawing = self.drawings[index] drawing = self.drawings[index]
except KeyError: except KeyError:
@ -533,6 +544,9 @@ class TuhiDBusServer(_TuhiDBus):
return GLib.Variant.new_objv([d.objpath for d in self._devices if d.registered]) return GLib.Variant.new_objv([d.objpath for d in self._devices if d.registered])
elif propname == 'Searching': elif propname == 'Searching':
return GLib.Variant.new_boolean(self.is_searching) return GLib.Variant.new_boolean(self.is_searching)
elif propname == 'JSONDataVersions':
return GLib.Variant.new_array(GLib.VariantType('u'),
[GLib.Variant.new_uint32(Drawing.JSON_FILE_FORMAT_VERSION)])
return None return None