前言
1.Publisher/Subscriber是因特网计算机上一个特别有价值的模式,该模式的作用是发布者和订阅者可以相互发送消息。
2.Publisher(发布者)定义一个协议,以便能够随时向一个或多个它的订阅者传输一系列消息值。但它有一个缺点是,它发出的一个或者多个消息值,不管是正常完成还是消息传递失败,一旦发布者发出完成事件,它就算任务完成了,不能再给出任何异常的消息事件。
3.Subscriber(订阅者)是一种协议,它定义了能够从发布者接收消息值的类型的接口,如果声明了Publisher,但是没有任何订阅者订阅它消息的话,Publisher也是无法发出任何消息值。
实现代码
1.创建一个项目
dfx new PubSub
之后用vscode打开
2.创建一个Publisher canister,在Publisher公开了一个订阅方法,其他canister可以调用这个方法来注册一个回调函数,每当Publisher发布一个消息值时,这个回调就被执行。
Publisher canister 代码:
import Array "mo:base/Array";
actor Pub
{
type Counter =
{
topic:Text;
value:Nat;
info_text : Text;
};
type Sub =
{
topic : Text;
callback : shared Counter ->();
};
var subs : [Sub] = [];
public func subscribe (sub : Sub)
{
subs := Array.append<Sub>(subs,[sub]); //数组附加
};
public func publish(counter : Counter)
{
for(sub in subs.vals())
{
//判断订阅的主题
if(sub.topic == counter.topic)
{
sub.callback(counter);
};
};
};
}
3.创建消息订阅的Subscriber canister,当Publisher canister发布一个消息值时,执行Subscriber canister的updateInfo就判断是否与订阅的消息匹配,如果匹配则返回获取消息值,为了更好的演示这个功能,这里创建了两个Subscriber canister 。
sub_one.mo
import Pub "canister:pub";
actor SubOne
{
type Counter =
{
topic : Text;
value : Nat;
info_text : Text;
};
type Information =
{
count : Nat;
info_text : Text;
};
var count : Nat = 0;
var text : Text = "";
public func init(topic0 : Text)
{
Pub.subscribe({
topic = topic0; callback = updateInfo;});
};
public func updateInfo(counter : Counter)
{
count += counter.value;
info_text := counter.text;
};
public query func getCount() : async Information
{
let info : Information = {
count = count;
info_text = text;
};
return info;
};
};
sub_two.mo
import Pub "canister:pub";
actor SubTwo
{
type Counter =
{
topic : Text;
value : Nat;
};
var count : Nat = 0;
public func init(topic0 : Text)
{
Pub.subscribe({
topic = topic0; callback = updateCount;});
};
public func updateCount(counter : Counter)
{
count += counter.value;
};
public query func getCount() : async Nat
{
return count;
};
};
4.在dfx.json文件里面添加canister
{
"canisters": {
"pub": {
"main": "src/pubsub/pub/pub.mo"
},
"sub_one": {
"main": "src/pubsub/sub_one/sub_one.mo"
},
"sub_two": {
"main": "src/pubsub/sub_two/sub_two.mo"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"dfx": "0.9.2",
"networks": {
"local": {
"bind": "127.0.0.1:8000",
"type": "ephemeral"
}
},
"version": 1
}
5.部署项目
运行环境
dfx start
部署项目
dfx deploy
6.订阅/发布信息
sub_one 订阅的是A这个主题
dfx canister call sub_one init '("A")'
sub_two 订阅的是B这个主题
dfx canister call sub_two init '("B")'
pub发布第1个A消息值
dfx canister call pub publish '(record { "topic" = "A"; "value" = 2;"info_text" = "This is theme A" })'
sub_one获取消息值
dfx canister call sub_one getCount
会得到以下结果
sub_tow获取消息值
dfx canister call sub_two getCount
pub发布第2个B消息值
dfx canister call pub publish '(record { "topic" = "B"; "value" = 2;"info_text" = "This is theme B" })'
sub_one获取的消息值还是原来的消息值:
sub_two获取消息值: