{"id":18962268,"url":"https://github.com/lipp/zbus","last_synced_at":"2025-04-19T11:53:03.428Z","repository":{"id":2600018,"uuid":"3582643","full_name":"lipp/zbus","owner":"lipp","description":"A simple TCP/IP based message bus in Lua.","archived":false,"fork":false,"pushed_at":"2012-09-07T13:14:34.000Z","size":350,"stargazers_count":12,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T07:33:37.080Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lipp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-02-29T14:59:46.000Z","updated_at":"2020-09-09T05:23:32.000Z","dependencies_parsed_at":"2022-08-29T16:31:14.319Z","dependency_job_id":null,"html_url":"https://github.com/lipp/zbus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lipp%2Fzbus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lipp%2Fzbus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lipp%2Fzbus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lipp%2Fzbus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lipp","download_url":"https://codeload.github.com/lipp/zbus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249195438,"owners_count":21228200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T14:15:47.568Z","updated_at":"2025-04-16T04:33:12.147Z","avatar_url":"https://github.com/lipp.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About\n\nzbus is a message bus in Lua. \n\nIt allows processes to provide or call methods between each other and to publish and subscribe notifications. The functionality provided should cover many use cases where [dbus](http://www.freedesktop.org/wiki/Software/dbus) may be suitable.\n\nIn opposite to dbus, zbus neither describes a message format nor requires XML for service registration etc. It is possible to register methods which handle multiple method-urls to keep the broker slim. Anyhow, zbus comes with an optional JSON serializer, which allows convenient and typed interfaces. Introspection is not part of zbus.\n\nIf you are interested in a higher level bus, have a look at [jet](https://github.com/lipp/jet), which is build on top of zbus.\n\n## Purpose\n\nzbus is designed with these goals:\n\n-    inter-process method calls\n-    inter-process notifications (publish/subscribe)\n-    efficiency (context switches, parsing)\n\nTo achieve this, you have to become a zbus.member. zbus members can:\n\n-  register callbacks to handle inter-process method calls.\n-  register callbacks to handle notifications (publish/**subscribe**)\n-  send notificiations (**publish**/subscribe)\n-  call methods in another process\n-  a extendable event loop\n\n## Requirements\n\nzbusd heavily relies on luasocket and [lua-ev](https://github.com/brimworks/lua-ev). The optional JSON message wrapper (zbus/json.lua) requires [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php). They are all available via luarocks and will be installed automatically with the zbus rock.\n\n## Other Languages like C,Python,...\n\nEven if the broker (zbusd.lua) and the modules provided are written in Lua, zbus members could be written in **any language** with support for TCP/IP.\n\n## Protocol\n\nzbus defines a simple protocol based on **multi-part messages**.This allows zbusd.lua to effectively recognize (or simply forward):\n\n-    method-urls\n-    method-arguments\n-    return-values\n-    exceptions\n-    notification-data\n\n**The zbus protocol itself is aware of any dataformat** but provides a\n  default implementation for JSON which allows a very convient\n  (stand-alone) zbus.\n\n## Build\n\nzbus is Lua-only, so no build/compile process is involved.\n\n## Install\n\nLatest version from github:\n\n       $ sudo luarocks install https://github.com/lipp/zbus/raw/master/rockspecs/zbus-scm-1.rockspec\n\n\nor from cloned repo directory:\n\n   $ sudo luarocks make rockspecs/zbus-scm-1.rockspec\n\nThere is no official release yet.\n\n# Example\n\n## zbusd.lua\n\n**All examples require zbusd to run**:\n\n      $ zbusd.lua\n\n\nIt is a daemon process and will never return. If the zbusd.lua daemon is not started, all zbus.members will block until zbusd.lua is started.\n\n## Echo method (without argument serialization)\n\n### The server providing the 'echo' method\n\n```lua\n-- load zbus module\nlocal zbus = require'zbus'\n\n-- create a default zbus member\nlocal member = zbus.member.new()\n\n-- register a function, which will be called, when a zbus-message's url matches expression\nmember:replier_add(\n\t  -- the expression to match ^matches string begin, $ matches string end\t\n          '^echo$', \n\t  -- the callback gets passed in the matched url, in this case always 'echo', \n\t  -- and the unserialized argument string\t\n\t  function(url,argument_str) \n\t       print(url,argument_str)\n\t       return argument_str\n         end)\n\n-- start the event loop, which will forward all 'echo' calls to member.\nmember:loop()\n\n```\n\n### The client calling the 'echo' method\n\n```lua\n-- load zbus module\nlocal zbus = require'zbus'\n\n-- create a default zbus member\nlocal member = zbus.member.new()\n\n-- call the service function and pass some argument string\nlocal result_str = member:call(\n\t'echo', -- the method url/name\n\t'Hello there' -- the argument string\n)\n-- verify that the echo service works\nassert(result_str=='Hello there')\n```\n\n### Run the example\ncheck is zbusd.lua is running! The echo_server.lua will never return (it is a service!) and must be terminated with aisgnal of choice, e.g. kill.\n\n      $ lua examples/echo_server.lua \u0026\n      $ lua examples/echo_client\n\n\n## Echo method service and client (with JSON serialization)\n\nIf a serialization config is provided, we can work with multiple typed arguments and return values.\nWhat the zbus_json_config does, is wrapping/unwrapping the arguments and results to a JSON array.\n\n### The server providing the 'echo' method\n\n```lua\n-- load zbus module\nlocal zbus = require'zbus'\n\n-- load the JSON message format serilization\nlocal zbus_json_config = require'zbus.json'\n\n-- create a zbus member with the specified serializers\nlocal member = zbus.member.new(zbus_json_config)\n\n-- register a function, which will be called, when a zbus-message's url matches expression\nmember:replier_add(\n\t -- the expression to match\t\n          '^echo$', \n\t  -- the callback gets passed in the matched url, in this case always 'echo', \n\t  -- and the unserialized argument data\t\n          function(url,...) \n\t\tprint(url,...)\n\t\treturn ...\n          end)\n\n-- start the event loop, which will forward all 'echo' calls to member.\nmember:loop()\n\n```\n\n### The client calling the 'echo' method\n\n```lua\n-- load zbus module\nlocal zbus = require'zbus'\n\n-- load the JSON message format serilization\nlocal zbus_json_config = require'zbus.json'\n\n-- create a zbus member with the specified serializers\nlocal member = zbus.member.new(zbus_json_config)\n\n-- call the service function and pass some arguments\nlocal res = {member:call(\n\t'echo', -- the method url/name\n\t'Hello',123,'is my number',{stuff=8181} -- the arguments\n)}\n-- verify that the echo service works\nassert(res[1]=='Hello')\nassert(res[2]==123)\nassert(res[3]=='is my number')\nassert(res[4].stuff==8181)\n```\n\n### Run the example\ncheck is zbusd.lua is running! The echo_server.lua will never return (it is a service!) and must be terminated with aisgnal of choice, e.g. kill.\n\n      $ lua examples/echo_server_json.lua \u0026\n      $ lua examples/echo_client_json.lua\n\n\n\n# How it works\n\n## Broker (zbusd.lua)\n\nEffectively *zbusd.lua* just starts the *zbus broker*. The terms *zbusd* and *broker* are used interchangeably in this context. \n\nThe broker has two jobs: \n\n- **route zbus-messages** for method calls and notifications\n- **provide means for route registration** to allow members to interact with the zbus\n- **url pool** for automatic socket assignment\n\n### Routing\nThe zbus-messages are routed based on their url part (the first part of the multi-part message). The process for notifications and method-calls differs slightly.\n\n#### Notification routing\nThe broker traverses all registered notification expressions and forwards the complete message to **all** matching routes.\n\n#### Method request routing\nThe broker traverses all registered method-call expressions and **assures that just one expression matches**. Otherwise the method-call url is ambigouos and an error message is returned In case of a unique match, the complete message is forwarded via the matched route. The response will be routed to the message queue which made the request.\n\n### Registration\nzbus members must register routes to subscribe to notifications or to\nprovide services (methods). A route consists of an expression (a [Lua\npattern](http://www.lua.org/pil/20.2.html)) and a an IP address + port. The broker provides a so called **registration socket (default port: 33329)**, which accepts registration requests. These are the registration calls:\n\n- **replier_open** registers a new (method) replier socket. The broker\n binds an acceptor/listener to the url returned.\n + return: a url to connect to\n- **replier_close** unregisters a previously opened (method) replier\n socket and closes it.\n + params: url\n- **replier_add** adds an expression to the specified replier\n socket. Tells the broker to forward incoming _method-call-request_ to\n the specified url as _method-call-request-forward_ if they match the\n expression. The replier must return a _method-call-response_.\n + params: url,expression\n- **replier_remove** removes an expression to the specified replier\n socket. Stops the broker from forwarding incoming _method-call-request_\n to the specified url.\n + params: url,expression\n- **listen_open** registers a new listen socket acceptor/listener. The\n broker binds a socket to the url returned. \n + return: a url to connect to\n- **listen_close** unregisters a previously opened (subscribe) listen socket\n + params: url\n- **listen_add** adds an expression to the specified listen socket. Incoming _notifications_ are\n forwarded as _notification-forward_ to this socket if they match the expression.\n + params: url,expression\n- **listen_remove** removes an expression to the specified listen socket\n + params: url,expression\n\n\n## Messages\n\nThere are seven kinds of zbus messages:\n\n- **registration-request**, sent from zbus members to the broker to manage repliers and listeners\n- **registration-response**, sent from the broker to zbus members as response to a registration-request\n- **method-call-request**, sent from a member to the broker\n- **method-call socket** (default \"tcp://*:33325\") to call a method on an unknown bus member\n- **method-call-request-forward**, sent from the broker to the registered replier socket\n- **method-call-response**, sent from replier to the broker and from the broker to the requestor (the caller)\n- **notification**, sent from a member to the broker notification socket (default \"tcp://*:33328\")\n- **notification-forward**, sent from the broker to all listen sockets (subscribers)\n\nThe format of the message data (argument/result/error/data) **can be of any kind** (e.g.,ascii, JSON, binary, etc)! \n(When using zbus/json.lua as zbus.member configuration, all stuff is converted to and from JSON.)\n\n### registration-request\nA registration-request is a multi-part message with the following layout:\n\n\u003ctable border=\"1\"\u003e   \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e            \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eMethod\u003c/td\u003e\u003ctd\u003ereplier_add\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003earg 1\u003c/td\u003e\u003ctd\u003e8765\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e3\u003c/td\u003e\u003ctd\u003earg 2\u003c/td\u003e\u003ctd\u003e^echo$\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e...\u003c/td\u003e\u003ctd\u003e ... \u003c/td\u003e\u003ctd\u003e ... \u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003en + 1\u003c/td\u003e\u003ctd\u003e arg n \u003c/td\u003e\u003ctd\u003e ... \u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\nThe method part (first part) is required, all arguments to registration calls are further parts in the multi-part message.\n\n### registration-response\nA registration-response is a multi-part message. \n\n**In case of error, it has two parts**:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003ePlaceholder\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eError\u003c/td\u003e\u003ctd\u003esome error message\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\n\n**In case of success, it has one part**:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eResult\u003c/td\u003e\u003ctd\u003e8765\u003c/td\u003e\n        \u003c/tr\u003e\n\u003c/table\u003e\n\n\n### method-call-request\nThe method-call-request is sent by a zbus member to issue a method call. The broker will forward the method-call-request as method-call-request-forward message. The method-call-request message must always be a **two-part message**. The first argument is the method-url to call, the second is the argument:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eMethod URL\u003c/td\u003e\u003ctd\u003eecho\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eArgument\u003c/td\u003e\u003ctd\u003e[1,111,\"hallo\"]\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\n\n### method-call-request-forward\nThe method-call-request-forward message is forwarded by the broker to\nthe member who registered to handle it (based on the url). The message\nmust always be a **two-part message**. The first argument is the method-url to call, the second is the argument:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eMatched Expression\u003c/td\u003e\u003ctd\u003e^echo$\u003c/td\u003e\n        \u003c/tr\u003e                    \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eMethod URL\u003c/td\u003e\u003ctd\u003eecho\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eArgument\u003c/td\u003e\u003ctd\u003e[1,111,\"hallo\"]\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\nThe format of the **argument and result data can be of any kind** (e.g.,ascii, JSON, binary, etc)! \nIt COULD be JSON (e.g. when using zbus/json.lua as zbus.member configuration, the member:call arguments and result are serialized to JSON.)\n\n### method-call-response\nThe method-call-response message may:\nIn case of **SUCCESS**, **one** part:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eResult\u003c/td\u003e\u003ctd\u003e[1,111,\"hallo\"]\u003c/td\u003e\n        \u003c/tr\u003e\n\u003c/table\u003e\n\nIn case of a **EXCEPTION** (handler error), it has **two** parts:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003ePlaceholder\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eError\u003c/td\u003e\u003ctd\u003e{message:\"something went wrong\",code=123}\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\n\nIn case of an **zbus/broker error**, it has **three** parts:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003ePlaceholder\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eError\u003c/td\u003e\u003ctd\u003eERR_AMBIGUOUS\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eError description\u003c/td\u003e\u003ctd\u003emethod ambiguous: echo\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\n\n### notification\nnotifications can be send by a zbus member to the broker. The broker\nwill forward them as notification-forward message to all\nsubscribers. Multiple notifications can be sent as one 'physical'\nmessage by appending more Topic/Data tuples as message parts. There\nmust be at least one Topic/Data tuple. The notification message looks like:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e                     \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eTopic URL 1\u003c/td\u003e\u003ctd\u003eadc.status\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eData 1\u003c/td\u003e\u003ctd\u003eoverflow\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\t\t\n                \u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eTopic URL 2\u003c/td\u003e\u003ctd\u003eadc.mode\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e4\u003c/td\u003e\u003ctd\u003eData 2 \u003c/td\u003e\u003ctd\u003eslow\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e...\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\t\t\n                \u003ctd\u003en*2\u003c/td\u003e\u003ctd\u003eTopic URL n\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003en*2+1\u003c/td\u003e\u003ctd\u003eData n \u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\t\n        \u003c/tr\u003e\n\u003c/table\u003e\n\n### notification-forward\nlisteners will receive notification-forward messages on the registered\nsocket. There is one Expression/Topic/Data tuple for each\nforwarded notification. There must be at least one\nExpression/Topic/Data tuple inside the multipart message, but there\nmay be more. The notification message looks like:\n\u003ctable border=\"1\"\u003e      \n       \u003ctr\u003e\n\t\u003ctd\u003eMessage Part\u003c/td\u003e\u003ctd\u003eMeaning\u003c/td\u003e\u003ctd\u003eExample\u003c/td\u003e\n       \u003c/tr\u003e \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eMatched expression 1\u003c/td\u003e\u003ctd\u003e^adc.*\u003c/td\u003e\n        \u003c/tr\u003e                    \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eTopic URL 1\u003c/td\u003e\u003ctd\u003eadc.status\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eData 1\u003c/td\u003e\u003ctd\u003eoverflow\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\t\t\n                \u003ctd\u003e4\u003c/td\u003e\u003ctd\u003eMatched expression 2\u003c/td\u003e\u003ctd\u003e^adc.*\u003c/td\u003e\n        \u003c/tr\u003e                    \n        \u003ctr\u003e\t\t\n                \u003ctd\u003e5\u003c/td\u003e\u003ctd\u003eTopic URL 2\u003c/td\u003e\u003ctd\u003eadc.mode\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003e6\u003c/td\u003e\u003ctd\u003eData 2\u003c/td\u003e\u003ctd\u003eslow\u003c/td\u003e\t\n        \u003c/tr\u003e\n        \u003ctr\u003e\t\t\n                \u003ctd\u003e...\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\n        \u003c/tr\u003e                    \n        \u003ctr\u003e\t\t\n                \u003ctd\u003en*3\u003c/td\u003e\u003ctd\u003eMatched expression n\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\n        \u003c/tr\u003e                    \n        \u003ctr\u003e\t\t\n                \u003ctd\u003en*3+1\u003c/td\u003e\u003ctd\u003eTopic URL n\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n                \u003ctd\u003en*3+2\u003c/td\u003e\u003ctd\u003eData n\u003c/td\u003e\u003ctd\u003e...\u003c/td\u003e\t\n        \u003c/tr\u003e\n\n\u003c/table\u003e\n\n\n\n## Members\neveryone who wants to use the zbus is called a **zbus member**. zbus members may:\n\n- call methods\n- subscribe/unsubscribe to notifications (so called listener)\n- register/provide methods (so called replier)\n- publish notifications\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flipp%2Fzbus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flipp%2Fzbus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flipp%2Fzbus/lists"}