Parts of a game talk to each other through a message board: a part subscribes a handler function to a topic, and whenever someone publishes a message on that topic, the handler is called with the message's payload.
Write make_bus() that returns a pair of functions (subscribe, publish) sharing one board:
subscribe(topic, handler)registershandlerfortopicand returns a functionunsubscribe(). Calling it removes that one registration; calling it again does nothing. Subscribing the same handler twice makes two registrations. The topic"*"receives every message.publish(topic, payload)calls every handler registered fortopicor for"*", in the order in which they were subscribed, and returns a list with one entry per call: the handler's return value, or, if the handler raised an exception, the string"error: "followed by the exception's class name. A failing handler does not stop the others.- The handlers that receive a message are decided when
publishstarts: a handler that subscribes or unsubscribes during a publish changes only later publishes. A handler may itself publish; that inner publish works the same way.
The tests use the helper run_bus(make_bus, script), which plays a list of steps (("sub", id, topic, spec), ("unsub", id), ("pub", topic, payload)) and returns the results of the "pub" steps. The handler specs are described in the helper's docstring; help(run_bus) prints it with Run.
Examples
Input: run_bus(make_bus, [("sub", 1, "score", "double"), ("sub", 2, "*", ("tag", "log")),
("pub", "score", 5), ("pub", "chat", "hi"), ("unsub", 1), ("pub", "score", 7)])
Output: [[10, "log:5"], ["log:hi"], ["log:7"]]
Input: run_bus(make_bus, [("sub", 1, "t", "fail"), ("sub", 2, "t", "echo"), ("pub", "t", 3)])
Output: [["error: RuntimeError", 3]]
Input: run_bus(make_bus, [("sub", 1, "t", ("unsub", 2)), ("sub", 2, "t", "echo"),
("pub", "t", "a"), ("pub", "t", "b")])
Output: [["unsubscribed", "a"], ["unsubscribed"]]
Explanation: handler 2 was already chosen for "a"; it is gone for "b".
Constraints
- Up to 2000 registrations and 2000 publishes.
- Handlers are any functions of one argument; they may raise any exception derived from
Exception.
Goals
- Return several functions that share one piece of hidden state
- Return a function that undoes one specific registration
- Keep one failing callback from breaking the others, and decide what a callback may change while it runs