Property Changes
Using a Signal for Property Updates
Because Wyrd resources can (in principle) be updated outside of your current process, it may make sense for your code to be notified of such events. This is mapped to standard signals.
You can set up any GObject as the receiver of such a signal. The following
code sets a receiver object up to receive a signal for updates for a named
wyrd property.
receiver = GObject.Object() # Use a more sensible receiver
signal = handle.setup_property_signal(receiver, ".foo.bar")
Because of the way GObject mappings to other languages work, it’s difficult to already connect the signal here. Instead, the function returns a signal name that you can connect a callback to:
def func(handle, propert_path, value):
# do something with the new value
pass
handle.connect(signal, func)
If the property now gets updates — also from within the same process — the callback above will be invoked via the signalling mechanism.
handle.set_property(".baz", 42) # does not trigger the callback
handle.set_property(".foo.bar", "hello") # triggers the callback
Wyrd Property to GObject Property Mapping
Of course when you think about signals and properties, you’re likely going to
think of GObject properties and their very own notify:: signal. Would it not
be nice if you could somehow make updates to such GObject properties be
persisted in Wyrd properties, and vice versa have updates to Wyrd properties
propagate to GObject properties?
Why yes, it would. One could argue that that is the main purpose of this SDK, to offer easy persistence of application state.
For this, we’ll define a GObject with a property first:
class ObjectWithProperty(GObject.Object):
@GObject.Property(type=int)
def prop_gint(self):
"""Read-write integer property."""
if not hasattr(self, 'value'):
return None
return self.value
@prop_gint.setter
def prop_gint(self, value):
self.value = value
Of course, this is a rather boring example, but nothing prevents you from using more interesting code you may already have.
Next, we’ll use the WyrdHandle to connect a Wyrd property to a GObject
property like so:
obj = ObjectWithProperty()
res = handle.property_connect(obj, "prop-gint", ".foo.bar")
obj.set_property("prop-gint", 321)
val = handle.get_property(".foo.bar")
assert 321 == val
ret = handle.set_property(".foo.bar", 123)
assert 123 == obj.get_property("prop-gint")
And there you have it. Easy state persistence for your code.
Further Reading
It’s worth pointing out that Wyrd documents are actually vessel resources. Vessel is a container file format for arbitrary data, not just Wyrd properties. But it has features that make it particularly suitable for networked data, where nodes may synchronize updates to a resource periodically.
Wyrd on the other hand makes use of those features, and adds conflict-free replicated data type functionality. Each wyrd property is, in fact, such a CRDT. That means that using this method for storing application state prepares your application for networked, multi-user operations.
Future updates to this SDK will allow you to configure such networking code as well. In the meantime, this library “just” offers easy state persistence with a pathway to full offline-first, eventually synchronized operations.