diff --git a/package.json b/package.json index c4a2f7e..4c1f5f3 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ ], "license": "ISC", "dependencies": { - "@abearxiong/router": "0.0.1-alpha.32", + "@abearxiong/router": "0.0.1-alpha.33", "@abearxiong/use-config": "^0.0.2", "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0938ee7..74439c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@abearxiong/router': - specifier: 0.0.1-alpha.32 - version: 0.0.1-alpha.32 + specifier: 0.0.1-alpha.33 + version: 0.0.1-alpha.33 '@abearxiong/use-config': specifier: ^0.0.2 version: 0.0.2 @@ -147,8 +147,8 @@ importers: packages: - '@abearxiong/router@0.0.1-alpha.32': - resolution: {integrity: sha512-ZbGSV7RjKQGQ650Oe6HJBT12SmY7UjaWgSwRVxCF0GdQXxeAlVm0w95tupZvvUXU6+wunozB/IH+YdYqK+64jQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.32/bb54dcffda24b6c7af8caf6016c61391c2aaff1b} + '@abearxiong/router@0.0.1-alpha.33': + resolution: {integrity: sha512-e2ownDhKsRfyjeuxtuThkRWys7cMLN3aLNdMOZKY3XVy2CYy1dZNzI1Mg3z2OY/hdmBtwovASUwJd1peRDPiiQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.33/a36a6d5b5a4d0b28094854a048c438f274a82e47} '@abearxiong/use-config@0.0.2': resolution: {integrity: sha512-IBOmeP46ykbDlkplFS65UsAHjyPDKnvS2oqbkpLWhbSwDbF5zhBnD4ibsFZKPCyc3lMlPeRqYva4x6puX3E/qQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/use-config/0.0.2/59fbeec8c8e086ec48e55024fe39020b079e6fa5} @@ -3095,7 +3095,7 @@ packages: snapshots: - '@abearxiong/router@0.0.1-alpha.32': + '@abearxiong/router@0.0.1-alpha.33': dependencies: ws: 8.18.0 transitivePeerDependencies: diff --git a/src/app.ts b/src/app.ts index 12adb77..215cdb2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,21 +1,82 @@ import { App } from '@abearxiong/router'; import { useConfig } from '@abearxiong/use-config'; import { dynamicImport } from './lib/dynamic-import.ts'; -import { redisPublisher } from './modules/redis.ts'; +import { redisPublisher, redisSubscriber } from './modules/redis.ts'; useConfig(); -export const emit = (channel: string, message: string) => { - redisPublisher.publish(channel, message); +export const emit = (channel: string, message?: any) => { + redisPublisher.publish(channel, JSON.stringify(message)); }; -export const app = new App<{ import: any, emit: typeof emit }>({ +export const app = new App<{ import: any; emit: typeof emit }>({ serverOptions: { cors: { origin: '*', }, }, + io: true, routerContext: { import: dynamicImport, emit, }, }); + +const clients = []; +// 订阅频道 pageEdit, container 单个页面预览 container 整个页面预览 +type ClientData = { + cid?: string; // container id + pid?: string[]; // page id + cids?: string[]; // container id + type: 'page' | 'container' | 'flow'; +}; +type MessageData = { + source: 'container'; + data: any; + operation?: 'edit'; +}; +redisSubscriber.subscribe('pageEdit', () => { + console.log('Subscribed to Redis data-updates channel'); +}); +redisSubscriber.on('message', (channel, message) => { + if (channel !== 'pageEdit') return; + const m = JSON.parse(message) as MessageData; + clients.forEach((client) => { + const data = client.data as any; + const { cid, cids = [] } = data || {}; + const wrapper = (data: any) => { + const res = { + type: 'pageEdit', + source: 'container', + data, + }; + return JSON.stringify(res); + }; + const { source, data: mData } = m; // 拆包 + if (source === 'container') { + if (cid === mData?.id) { + client.ws.send(wrapper(mData)); + } else if (cids.includes(mData?.id)) { + client.ws.send(wrapper(mData)); + } + } + // 其他操作 暂时 不处理 + // TODO + }); +}); +app.io.addListener('subscribe', async ({ data, end, ws }) => { + const { type } = data || {}; + if (type === 'pageEdit') { + clients.push({ ws, data: data.data }); // 拆包,里面包含的type信息,去掉 + end({ code: 200, data: 'subscribe success' }); + } else if (type === 'unsubscribe') { + const index = clients.findIndex((client) => client.ws === ws); + clients.splice(index, 1); + end({ code: 200, data: 'unsubscribe success' }); + } else { + end({ code: 404, data: 'subscribe fail' }); + } + ws.on('close', () => { + const index = clients.findIndex((client) => client.ws === ws); + clients.splice(index, 1); + }); +}); diff --git a/src/routes/container/list.ts b/src/routes/container/list.ts index c72380c..44a05c1 100644 --- a/src/routes/container/list.ts +++ b/src/routes/container/list.ts @@ -61,7 +61,12 @@ add.run = async (ctx) => { containerModel = await ContainerModel.findByPk(container.id); if (containerModel) { containerModel.update(container); - containerModel.save(); + await containerModel.save(); + ctx.emit?.('pageEdit', { + source: 'container', + data: containerModel.toJSON(), + operation: 'edit', + }); } } else { try { @@ -94,13 +99,12 @@ deleteRoute.run = async (ctx) => { }; deleteRoute.addTo(app); -const publish = app.route({ - path: 'container', - key: 'publish', -}); -publish.nextRoute = { path: 'resource', key: 'publishContainer' }; - -publish +app + .route({ + path: 'container', + key: 'publish', + nextRoute: { path: 'resource', key: 'publishContainer' }, + }) .define(async (ctx) => { const { data } = ctx.query; const { id, publish, type = 'patch', beta = false } = data;