diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 60be90db..fa208344 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,12 +17,12 @@ jobs: strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install -g codecov diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5d365709..062fbddf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,11 +12,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '18.x' registry-url: 'https://registry.npmjs.org' - name: Build licia run: npm i && npm link && npm run build diff --git a/DOC.md b/DOC.md index 96023acb..039035b0 100644 --- a/DOC.md +++ b/DOC.md @@ -751,6 +751,78 @@ c.remove('content-type'); c.has('content-type'); // -> false ``` +## Channel + +Interconnectable Message channel. + +
+Type Definition + +```typescript +class Channel extends Emitter { + send(msg: any): void; + connect(channel: Channel): void; + disconnect(channel: Channel): void; + isConnected(channel: Channel): boolean; + destroy(): void; +} +``` + +
+ +### send + +Send a message to all connected channels. + +|Name|Desc | +|----|---------------| +|msg |Message to send| + +### connect + +Connect to another channel. + +|Name |Desc | +|-------|------------------| +|channel|Channel to connect| + +### disconnect + +Disconnect from another channel. + +|Name |Desc | +|-------|---------------------| +|channel|Channel to disconnect| + +### isConnected + +Check if a channel is connected to another channel. + +|Name |Desc | +|-------|----------------------| +|channel|Channel to check | +|return |Whether it's connected| + +### destroy + +Destroy the channel, disconnect from all connected channels. + +```javascript +const channelA = new Channel(); +const channelB = new Channel(); +channelA.connect(channelB); +channelB.on('message', msg => { + console.log(msg); // -> 'hello' +}); +channelA.send('hello'); +channelA.on('message', msg => { + console.log(msg); // -> 'world' +}); +channelB.send('world'); +channelA.isConnected(channelB); // -> true +channelB.isConnected(channelA); // -> true +``` + ## Class Create JavaScript class. diff --git a/DOC_CN.md b/DOC_CN.md index 1ae77198..0dc47d64 100644 --- a/DOC_CN.md +++ b/DOC_CN.md @@ -745,6 +745,78 @@ c.remove('content-type'); c.has('content-type'); // -> false ``` +## Channel + +可以相互连接的消息通道。 + +
+类型定义 + +```typescript +class Channel extends Emitter { + send(msg: any): void; + connect(channel: Channel): void; + disconnect(channel: Channel): void; + isConnected(channel: Channel): boolean; + destroy(): void; +} +``` + +
+ +### send + +发送消息给所有连接的通道。 + +|参数名|说明| +|-----|---| +|msg|要发送的消息| + +### connect + +连接到指定通道。 + +|参数名|说明| +|-----|---| +|channel|要连接的通道| + +### disconnect + +断开与指定通道的连接。 + +|参数名|说明| +|-----|---| +|channel|要断开的通道| + +### isConnected + +检查两个通道是否连接。 + +|参数名|说明| +|-----|---| +|channel|目标通道| +|返回值|是否连接| + +### destroy + +销毁通道,断开所有连接的通道。 + +```javascript +const channelA = new Channel(); +const channelB = new Channel(); +channelA.connect(channelB); +channelB.on('message', msg => { + console.log(msg); // -> 'hello' +}); +channelA.send('hello'); +channelA.on('message', msg => { + console.log(msg); // -> 'world' +}); +channelB.send('world'); +channelA.isConnected(channelB); // -> true +channelB.isConnected(channelA); // -> true +``` + ## Class 创建 JavaScript 类。 diff --git a/cspell.json b/cspell.json index 2f7cd763..805f8304 100644 --- a/cspell.json +++ b/cspell.json @@ -57,6 +57,7 @@ "castPath", "centerAlign", "cgroup", + "Channel", "char", "chunk", "clamp", diff --git a/i18n/Channel.md b/i18n/Channel.md new file mode 100644 index 00000000..390fe504 --- /dev/null +++ b/i18n/Channel.md @@ -0,0 +1,40 @@ +## CN + +可以相互连接的消息通道。 + +### send + +发送消息给所有连接的通道。 + +|参数名|说明| +|-----|---| +|msg|要发送的消息| + +### connect + +连接到指定通道。 + +|参数名|说明| +|-----|---| +|channel|要连接的通道| + +### disconnect + +断开与指定通道的连接。 + +|参数名|说明| +|-----|---| +|channel|要断开的通道| + +### isConnected + +检查两个通道是否连接。 + +|参数名|说明| +|-----|---| +|channel|目标通道| +|返回值|是否连接| + +### destroy + +销毁通道,断开所有连接的通道。 diff --git a/index.json b/index.json index 31bb0c15..1a112ecf 100644 --- a/index.json +++ b/index.json @@ -266,6 +266,24 @@ "browser" ] }, + "Channel": { + "dependencies": [ + "Emitter", + "each", + "remove", + "some" + ], + "description": "Interconnectable Message channel.", + "env": [ + "node", + "browser", + "miniprogram" + ], + "test": [ + "node", + "browser" + ] + }, "Class": { "demo": true, "dependencies": [ diff --git a/src/Channel.js b/src/Channel.js new file mode 100644 index 00000000..79ffdaef --- /dev/null +++ b/src/Channel.js @@ -0,0 +1,114 @@ +/* Interconnectable Message channel. + * + * ### send + * + * Send a message to all connected channels. + * + * |Name|Desc | + * |----|---------------| + * |msg |Message to send| + * + * ### connect + * + * Connect to another channel. + * + * |Name |Desc | + * |-------|------------------| + * |channel|Channel to connect| + * + * ### disconnect + * + * Disconnect from another channel. + * + * |Name |Desc | + * |-------|---------------------| + * |channel|Channel to disconnect| + * + * ### isConnected + * + * Check if a channel is connected to another channel. + * + * |Name |Desc | + * |-------|----------------------| + * |channel|Channel to check | + * |return |Whether it's connected| + * + * ### destroy + * + * Destroy the channel, disconnect from all connected channels. + */ + +/* example + * const channelA = new Channel(); + * const channelB = new Channel(); + * channelA.connect(channelB); + * channelB.on('message', msg => { + * console.log(msg); // -> 'hello' + * }); + * channelA.send('hello'); + * channelA.on('message', msg => { + * console.log(msg); // -> 'world' + * }); + * channelB.send('world'); + * channelA.isConnected(channelB); // -> true + * channelB.isConnected(channelA); // -> true + */ + +/* module + * env: all + */ + +/* typescript + * export declare class Channel extends Emitter { + * send(msg: any): void; + * connect(channel: Channel): void; + * disconnect(channel: Channel): void; + * isConnected(channel: Channel): boolean; + * destroy(): void; + * } + */ + +_('Emitter each remove some'); + +exports = Emitter.extend({ + initialize: function Channel() { + this._connections = []; + + this.callSuper(Emitter, 'initialize'); + }, + send(msg) { + each(this._connections, connection => { + connection.emit('message', msg, this); + }); + }, + connect(connection) { + if (this.isConnected(connection)) { + return; + } + + this._connections.push(connection); + + connection.connect(this); + }, + disconnect(connection) { + if (!this.isConnected(connection)) { + return; + } + + remove(this._connections, item => item === connection); + + connection.disconnect(this); + }, + isConnected(connection) { + if (connection === this) { + throw new Error('Connection cannot be connected to itself.'); + } + + return some(this._connections, item => item === connection); + }, + destroy() { + each(this._connections, connection => { + this.disconnect(connection); + }); + } +}); diff --git a/test/Channel.js b/test/Channel.js new file mode 100644 index 00000000..b76f44c3 --- /dev/null +++ b/test/Channel.js @@ -0,0 +1,27 @@ +const a = new Channel(); +const b = new Channel(); + +a.connect(b); +b.on('message', msg => { + expect(msg).to.equal('hello'); +}); +a.send('hello'); +a.on('message', msg => { + expect(msg).to.equal('world'); +}); +b.send('world'); + +expect(a.isConnected(b)).to.be.true; +expect(b.isConnected(a)).to.be.true; + +a.disconnect(b); + +expect(a.isConnected(b)).to.be.false; +expect(b.isConnected(a)).to.be.false; + +b.connect(a); +expect(a.isConnected(b)).to.be.true; +expect(b.isConnected(a)).to.be.true; + +a.destroy(); +expect(b.isConnected(a)).to.be.false;