diff --git a/README.md b/README.md index da391d9..700593f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ - Support different application scenarios, such as asynchronous and synchronous - Provide different syntax writing modes for lambda, callback functions, decorators, etc - A callback function listens on multiple subscriptions +- Provide publisher dispatch callback manage ## Quick Start - [document github-pages](https://undertone0809.github.io/broadcast-service/#/) @@ -44,12 +45,6 @@ There is an easy demo to show how to use broadcast-service. ```python from broadcast_service import broadcast_service - -# callback of common method -def handle_msg(params): - print(f"handle_msg receive params: {params}") - - # callback of decorator @broadcast_service.on_listen('my_topic') def handle_decorator_msg(params): @@ -58,9 +53,6 @@ def handle_decorator_msg(params): if __name__ == '__main__': info = 'This is very important msg' - # subscribe topic - broadcast_service.subscribe('my_topic', handle_msg) - # publish broadcast broadcast_service.publish('my_topic', info) ``` @@ -98,7 +90,30 @@ if __name__ == '__main__': broadcast_service.publish('Test') ``` -You can use decorator to subscirbe your +You can use `config` to make publisher callback If you want. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(*args): + print("handle_publisher_callback") + + +if __name__ == '__main__': + broadcast_service.config( + num_of_executions=5, + callback=handle_publisher_callback, + enable_final_return=True, + interval=0.1 + ).publish("topic") + +``` Moreover, you can see more example in [document](https://undertone0809.github.io/broadcast-service/#/). @@ -107,7 +122,7 @@ Moreover, you can see more example in [document](https://undertone0809.github.io - ~~optimize the syntax expression of broadcast-service~~ - provide more test cases - provide the ability to subscribe the topic and callback once -- Support for fuzzy subscriptions +- support for fuzzy subscriptions - ~~the publisher of the topic can provide a return value~~ - optimize usage in class ('self' params problem) - build observer mode diff --git a/docs/README.md b/docs/README.md index 5d02175..5a45d45 100644 --- a/docs/README.md +++ b/docs/README.md @@ -64,9 +64,13 @@ if __name__ == '__main__': ## TODO - optimize documents and show more examples. - ~~optimize the syntax expression of broadcast-service~~ -- provide more test cases -- privide the ability to subscribe the topic and callback once -- Support for fuzzy subscriptions +- provide more test cases (developing) +- provide the ability to subscribe the topic and callback once +- support for fuzzy subscriptions +- ~~the publisher of the topic can provide a return value~~ +- optimize usage in class ('self' params problem) +- build observer mode +- ~~provide publisher callback when all subscriber have completed callback~~ ## Contribution diff --git a/docs/_coverpage.md b/docs/_coverpage.md index cdad729..7d29773 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ -# broadcast-service 1.2.0 +# broadcast-service 2.0.0 > A lightweight python broadcast library. You can easily construct a Broadcast pattern/Publish subscriber pattern through this library. diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 51acb3b..2caa8b7 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -4,6 +4,7 @@ - Getting started - [Quick Start](quickstart.md) + - [Publisher Dispatch](publisher_dispatch.md) - [Async](async.md) - [Log](log.md) diff --git a/docs/index.html b/docs/index.html index fc4db96..fc7223e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,36 +1,47 @@ - - Document - - - - + + Document + + + + -
- - - - - - - + + + + + + + + + + + + diff --git a/docs/plan.md b/docs/plan.md index a1e6a19..6480524 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -2,10 +2,15 @@ Here are some development plans. -- Optimize Chinese documents and show more examples. -- ~~Optimize the syntax expression of broadcast-service~~ -- Provide more test cases -- Privide the ability to subscribe the topic and callback once `(developing)` -- Support for fuzzy subscriptions +- optimize documents and show more examples. +- ~~optimize the syntax expression of broadcast-service~~ +- provide more test cases (developing) +- provide the ability to subscribe the topic and callback once +- support for fuzzy subscriptions +- ~~the publisher of the topic can provide a return value~~ +- optimize usage in class ('self' params problem) +- build observer mode +- ~~provide publisher callback when all subscriber have completed callback~~ + `(developing)` means I am going to do. As for other plans,if you want to contribute to this project, you can submit pr or issue and tells me which one you want to do. I am glad to see more people involved and optimize it. \ No newline at end of file diff --git a/docs/publisher_dispatch.md b/docs/publisher_dispatch.md new file mode 100644 index 0000000..54ac1f6 --- /dev/null +++ b/docs/publisher_dispatch.md @@ -0,0 +1,234 @@ +# Publisher Dispatch + +## Publisher Callback +As a theme publisher, how do you know if all subscriber's callback functions have ended? The `broadcast-service` provides a relevant callback mechanism, and you can make the callback after all subscriber callback functions have ended. The following example conducts `handle_publisher_callback` callback when `handle_subscriber_callback1` and `handle_subscriber_callback2` callbacks end. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + print("handle_subscriber_callback 1") + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + print("handle_subscriber_callback 2") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +**output:** + +```text +handle_subscriber_callback 1 +handle_subscriber_callback 2 +handle_publisher_callback +``` + +## Publisher Multiple Executions + +`broadcast-service` also supports publishing multiple topics at the same time. The following example shows how to publish multiple topics at the same time. + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + ).publish("topic") + +if __name__ == '__main__': + main() +``` + +**output** + +```text +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +``` + +In addition, if you want to set the time interval to send topics every n seconds, you can also use the `interval` parameter to configure the time interval. + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + interval=2 # 2seconds + ).publish("topic") + +if __name__ == '__main__': + main() + +``` + +Combining the content of the [publisher-callback](#publisher-callback) section, you can make the publisher publish topics multiple times and complete the publisher callback function after all subscriber callback functions are executed. The following example shows how to implement this function. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +For the above example, the output is as follows: + +```text +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +``` + +It can be seen that the topic was published three times, and the publisher callback function was executed three times. If you want the publisher callback function to be executed only once after all topics are published and all subscriber callback functions are executed, you can use the parameter `enable_final_return=False` to achieve this goal. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback, + enable_final_return=True + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +The output is as follows, and in fact, this way of operation may be the result we want most of the time. + +```text +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +handle_publisher_callback +``` + + +## Return value from subscriber callbacks + +The publisher's callback function can also receive messages. The following example shows how to set return values in the subscriber's callback function and finally return them to the publisher's callback function. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + return "handle_subscriber_callback" + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback" + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +Note that if the publisher's callback function needs to receive parameters, you must use `*args` to receive parameters. Therefore, if multiple subscriber callback functions return information, the publisher's callback cannot be set. Therefore, `*args` is used as a parameter pool to receive data returned from the subscriber's callback function. `*args` is a tuple, which can store any type of data, as long as you can successfully obtain the parameter information of `args`. + +The following example shows a complex scenario where multiple subscriber callback functions return information. + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + return "handle_subscriber_callback 1" + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + return [1, 2, 3, 4, 5] + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback3(): + return {"key": "value"} + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback 1" + print(args[1]) # [1,2,3,4,5] + print(args[2]) # {"key", "value"} + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +It should be noted that the order of the three elements `args[0]`, `args[1]`, and `args[2]` in the above example is not uniquely determined, which depends on the execution time of the subscriber's callback function. However, in most cases, we cannot judge which subscriber callback function ends first, so `broadcast-service` development specifications recommend that when using this function, let the return value types of the subscriber callback functions be consistent as much as possible to reduce the cost of additional data judgment. \ No newline at end of file diff --git a/docs/quickstart.md b/docs/quickstart.md index 6313972..dc200c2 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -14,7 +14,7 @@ pip install --upgrade broadcast-service

-**Now you can see a easy pubsub pattern.** +**Now you can see an easy pubsub pattern.** ```python from broadcast_service import broadcast_service @@ -40,17 +40,14 @@ if __name__ == '__main__': ## How to subscribe? Actually, `broadcast-service` support mutiple subscirbe and publish methods, such as `common callback function` and `decorator`. You can see more example as follows. +> Decorator method is recommended. + - **subscribe single topic** ```python from broadcast_service import broadcast_service -# common callback function method -def handle_msg(params): - print(params) - - # decorator method @broadcast_service.on_listen(['my_topic']) def handle_decorator_msg1(params): @@ -63,13 +60,31 @@ def handle_decorator_msg2(params): print(params) +if __name__ == '__main__': + info = 'This is very important msg' + + # publish broadcast + broadcast_service.publish('my_topic', info) +``` + +or + +```python +from broadcast_service import broadcast_service + + +# common callback function method +def handle_msg(params): + print(params) + + if __name__ == '__main__': info = 'This is very important msg' # subscribe topic broadcast_service.subscribe('my_topic', handle_msg) # you can also pass a topics list to subscribe multiple topics - broadcast_service.subscribe(['my_topic'], handle_msg) + # broadcast_service.subscribe(['my_topic'], handle_msg) # publish broadcast broadcast_service.publish('my_topic', info) @@ -85,15 +100,27 @@ if __name__ == '__main__': from broadcast_service import broadcast_service -def handle_msg(params): - print(params) - - @broadcast_service.on_listen(['my_topic1', 'my_topic2']) def handle_decorator_msg(params): print(params) +if __name__ == '__main__': + # publish broadcast + broadcast_service.publish('my_topic1', "msg1") + broadcast_service.publish('my_topic2', "msg2") +``` + +or + +```python +from broadcast_service import broadcast_service + + +def handle_msg(params): + print(params) + + if __name__ == '__main__': # This callback function is triggered when a message is sent from one of two topics subscribed to broadcast_service.subscribe(['my_topic1', 'my_topic2'], handle_msg) diff --git a/docs/zn-cn/publisher_dispatch.md b/docs/zn-cn/publisher_dispatch.md new file mode 100644 index 0000000..1d9fcb7 --- /dev/null +++ b/docs/zn-cn/publisher_dispatch.md @@ -0,0 +1,446 @@ +# Publisher Dispatch + +## Publisher Callback +作为一个主题发布者,如何知道所有订阅者的回调函数是否结束了?`broadcast-service`提供了相关的回调机制,在所有的订阅者回调函数结束之后,你可以进行可以回调, +下面这个示例在`handle_subscriber_callback1`和`handle_subscriber_callback2`回调结束时候会进行`handle_publisher_callback`的回调。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + print("handle_subscriber_callback 1") + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + print("handle_subscriber_callback 2") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +## Publisher Multiple Executions + +`broadcast-service`也支持在同一时间发布多次主题,下面的示例展示了如何在同一时间内进行多次主题的发布。 + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + ).publish("topic") + +if __name__ == '__main__': + main() +``` + +此外,如果你想要设置间隔n秒发送一次主题,你也可以使用interval参数进行时间间隔的配置。 + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + interval=2 # 2seconds + ).publish("topic") + +if __name__ == '__main__': + main() + +``` + +结合[publisher-callback](#publisher-callback)部分的内容,你可以让发布者多次发布主题,并且在订阅者回调函数结束之后完成发布者回调函数的回调, +下面这个示例展示了这种功能实现。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +对于上面的示例,输出结果如下所示。 + +```text +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +``` + +可以看到发布了3次主题,发布者回调函数也执行了三次,如果你想要在所有发布主题、所有订阅者回调函数都执行完之后,最后只执行一次发布者回调函数的话,你 +可以使用`enable_final_return=False`的参数设置来达到这种目的。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback, + enable_final_return=True + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +输出结果如下所示,事实上,这种操作方式或许是大多数时候我们想要的结果。 + +```text +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +handle_publisher_callback +``` + + +## Return value from subscriber callbacks + +发布者的回调当然也可以接收消息,下面一个示例展示了在订阅者的回调函数设置返回值,最终返回给发布者的回调函数。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + return "handle_subscriber_callback" + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback" + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +需要注意的是,如果发布者的回调函数必须使用`*args`去接收参数,因为如果有多个订阅者返回信息,发布者的回调就无法设置,因此`*args`作为参数池来接收 +从订阅者回调函数中返回回来的参数。`*args`是一个元组,里面可以存储任意类型的数据,只要你可以成功获取到`args`的参数信息。 + +下面一个示例展示了有多个订阅者回调函数返回信息的复杂场景。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + return "handle_subscriber_callback 1" + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + return [1,2,3,4,5] + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback3(): + return {"key": "value"} + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback 1" + print(args[1]) # [1,2,3,4,5] + print(args[2]) # {"key", "value"} + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +需要说明的是,在上面的示例中,`args[0]`, `args[1]`, `args[2]`三个元素的顺序并不是唯一确定的,这需要根据订阅者回调函数的执行时间来判断,但是 +在大多数情况下,我们并不能很好的判断哪个订阅者回调函数先结束,因此`broadcast-service`开发规范推荐你在使用这个功能的时候,让订阅者回调函数的返 +回值类型尽可能的一致,减少需要额外判断数据的成本。 + + +# Publisher Dispatch + +## Publisher Callback +作为一个主题发布者,如何知道所有订阅者的回调函数是否结束了?`broadcast-service`提供了相关的回调机制,在所有的订阅者回调函数结束之后,你可以进行可以回调, +下面这个示例在`handle_subscriber_callback1`和`handle_subscriber_callback2`回调结束时候会进行`handle_publisher_callback`的回调。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + print("handle_subscriber_callback 1") + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + print("handle_subscriber_callback 2") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +## Publisher Multiple Executions + +`broadcast-service`也支持在同一时间发布多次主题,下面的示例展示了如何在同一时间内进行多次主题的发布。 + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + ).publish("topic") + +if __name__ == '__main__': + main() +``` + +此外,如果你想要设置间隔n秒发送一次主题,你也可以使用interval参数进行时间间隔的配置。 + +```python +from broadcast_service import broadcast_service + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + +def main(): + broadcast_service.config( + num_of_executions=5, + interval=2 # 2seconds + ).publish("topic") + +if __name__ == '__main__': + main() + +``` + +结合[publisher-callback](#publisher-callback)部分的内容,你可以让发布者多次发布主题,并且在订阅者回调函数结束之后完成发布者回调函数的回调, +下面这个示例展示了这种功能实现。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +对于上面的示例,输出结果如下所示。 + +```text +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +handle_subscriber_callback +handle_publisher_callback +``` + +可以看到发布了3次主题,发布者回调函数也执行了三次,如果你想要在所有发布主题、所有订阅者回调函数都执行完之后,最后只执行一次发布者回调函数的话,你 +可以使用`enable_final_return=False`的参数设置来达到这种目的。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + print("handle_subscriber_callback") + + +def handle_publisher_callback(): + print("handle_publisher_callback") + + +def main(): + broadcast_service.config( + num_of_executions=3, + callback=handle_publisher_callback, + enable_final_return=True + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +输出结果如下所示,事实上,这种操作方式或许是大多数时候我们想要的结果。 + +```text +handle_subscriber_callback +handle_subscriber_callback +handle_subscriber_callback +handle_publisher_callback +``` + + +## Return value from subscriber callbacks + +发布者的回调当然也可以接收消息,下面一个示例展示了在订阅者的回调函数设置返回值,最终返回给发布者的回调函数。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback(): + return "handle_subscriber_callback" + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback" + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() + +``` + +需要注意的是,如果发布者的回调函数必须使用`*args`去接收参数,因为如果有多个订阅者返回信息,发布者的回调就无法设置,因此`*args`作为参数池来接收 +从订阅者回调函数中返回回来的参数。`*args`是一个元组,里面可以存储任意类型的数据,只要你可以成功获取到`args`的参数信息。 + +下面一个示例展示了有多个订阅者回调函数返回信息的复杂场景。 + +```python +from broadcast_service import broadcast_service + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback1(): + return "handle_subscriber_callback 1" + + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback2(): + return [1,2,3,4,5] + +@broadcast_service.on_listen("topic") +def handle_subscriber_callback3(): + return {"key": "value"} + + +def handle_publisher_callback(*args): + print(args[0]) # "handle_subscriber_callback 1" + print(args[1]) # [1,2,3,4,5] + print(args[2]) # {"key", "value"} + + +def main(): + broadcast_service.config( + callback=handle_publisher_callback, + ).publish("topic") + + +if __name__ == '__main__': + main() +``` + +需要说明的是,在上面的示例中,`args[0]`, `args[1]`, `args[2]`三个元素的顺序并不是唯一确定的,这需要根据订阅者回调函数的执行时间来判断,但是 +在大多数情况下,我们并不能很好的判断哪个订阅者回调函数先结束,因此`broadcast-service`开发规范推荐你在使用这个功能的时候,让订阅者回调函数的返 +回值类型尽可能的一致,减少需要额外判断数据的成本。 + +