sipyco.sync_struct.Subscriber has access to the full backing_struct of the remote sipyco.sync_struct.Notifier (i.e. to the full dictionary being synchronized) in sipyco/sync_struct.py #L155 and #L157.

Why does Subscriber not expose target? For example, via def get_struct(self): return self.__target? Are local scripts supposed to create their notifiers and register callback functions with the subscriber, via its argument notify_cb?

For anybody curious, I have played around with sipyco.sync_struct in the code below.

publisher.py

Run in terminal: python publisher.py

import asyncio
import atexit
from signal import SIGINT

from sipyco.asyncio_tools import atexit_register_coroutine
from sipyco.sync_struct import Notifier, Publisher

async def endless_modifications(notifier):
    print("Starting loop of endless modifications.")
    i = 0
    try:
        while True:
            await asyncio.sleep(1)
            notifier[f"var{i}"] = i
            print(f"set \"var{i}\" = {i}")
            i += 1
    except asyncio.CancelledError:
        print("\nStopping loop of endless modifications.")

def main():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    atexit.register(loop.close)
    
    classmates = Notifier(dict())
    
    publisher = Publisher({
        "classmates": classmates,
    })
    loop.run_until_complete(publisher.start("localhost", 5000))
    atexit_register_coroutine(publisher.stop, loop=loop)

    task = loop.create_task(endless_modifications(classmates))
    loop.add_signal_handler(SIGINT, task.cancel)
    loop.run_until_complete(task)

if __name__ == "__main__":
    main()

subscriber.py

Run in a different terminal: python subscriber.py

import asyncio
import atexit
from signal import SIGINT
import time

from sipyco.asyncio_tools import atexit_register_coroutine
from sipyco.sync_struct import Subscriber

stop_event = asyncio.Event()

async def run_forever():
    try:
        await stop_event.wait()
    except asyncio.CancelledError:
        pass
    print("\nStopping `sipyco.sync_struct.Subscriber`.")

def verbose_before_connect():
    print(f"{time.time():.2f}: before_receive_cb() called")

def verbose_builder(obj):
    print(f"{time.time():.2f}: target_builder(obj) called with obj =", obj)
    return obj

def verbose_notify(mod):
    print(f"{time.time():.2f}: notify_cb(mod) called with mod =", mod)

def verbose_disconnect():
    print(f"{time.time():.2f}: disconnect_cb() called")
    stop_event.set()

def main():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    atexit.register(loop.close)
    
    classmates_remote = Subscriber(
        notifier_name = "classmates",
        target_builder = verbose_builder,
        notify_cb = verbose_notify,
        disconnect_cb = verbose_disconnect,
    )
    loop.run_until_complete(classmates_remote.connect("localhost", 5000, before_receive_cb=verbose_before_connect))
    atexit_register_coroutine(classmates_remote.close, loop=loop)

    task = loop.create_task(run_forever())
    loop.add_signal_handler(SIGINT, task.cancel)
    loop.run_until_complete(task)

if __name__ == "__main__":
    main()

    Hi!

    Why does Subscriber not expose target? For example, via def get_struct(self): return self.__target

    Is it not sufficient to maintain the "target" struct yourself on the Subscriber side, calling process_mod(target, mod) on it with the modifications coming from notify_cb? Not all target structs necessarily want/need every modification coming from the Publisher. For example, here we filter for the modifications we want, and ignore any modifications that are not relevant to that target struct.

    dtsevas

    Are local scripts supposed to create their notifiers and register callback functions with the subscriber, via its argument notify_cb?

    Yes. This is the intended usage. The Subscriber's role is to receive and process updates, not to serve as a data store. Using callbacks, applications can process updates according to their specific needs without coupling their data access patterns to the synchronization mechanism, as @srenblad mentioned.