Dfinity Dapp开发——Canister实现Publisher/Subscriber(发布/订阅者)消息模式

本文档介绍了如何使用DFX和Motoko编程语言创建一个发布者/订阅者模式的应用。发布者Canister发布消息,而订阅者Canister接收并处理这些消息。通过示例代码展示了如何初始化订阅者、发布消息以及获取消息值的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

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获取消息值:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知来者逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值