监听思源 main websocket

监听思源main websocket

// see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/app/src/layout/Model.ts
// see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/kernel/util/websocket.go
(() => {
    // 创建socket客户端
    createSocketClient(siyuan.ws.ws.url);

    // 当收到消息时被调用
    function onReceivedMessage(event) {
        const message = parseJson(event.data);
        if(message.cmd === 'transactions') {
            // 这里获取更新后的数据
            console.log(message);
        }
    }

    // 创建socket客户端
    function createSocketClient(url) {
        // 连接 WebSocket 服务器
        const socket = new WebSocket(url);
  
        socket.onopen = function(event) {
            console.log('WebSocket opened');
        };
  
        socket.onmessage = onReceivedMessage;
  
        socket.onclose = function(event) {
            console.log('WebSocket closed!');
        };
  
        socket.onerror = function(error) {
            console.error('WebSocket Error:', error);
        };

        return socket;
    }

    // 客户端向服务器发送消息
    function sendMessage(socket, message) {
        if (socket.readyState === WebSocket.OPEN) {
            socket.send(message);
        } else {
            console.error('WebSocket connection is not open');
        }
    }

    // 解析json
    function parseJson(jsonString) {
        let json = {};
        try {
            json = JSON.parse(jsonString || '{}');
        } catch(e) {
            json = {};
            console.error('parseJson error', e);
        }
        return json;
    }
})()

see https://github.com/siyuan-note/siyuan/issues/13313?utm_source=ld246.com#issuecomment-2513905906

测试结果

image

测试代码

// see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/app/src/layout/Model.ts
// see https://github.com/siyuan-note/siyuan/blob/1710194122495d282a51650441d9fc80804561bb/kernel/util/websocket.go
(() => {
    // 创建socket客户端
    createSocketClient(siyuan.ws.ws.url);

    let time = 0, blockId = '';
    // 记录刚刚输入完数据
    document.body.addEventListener('keyup', async (event) => {
        time = new Date().getTime();

        // 更新前
        blockId = event.target.lastElementChild?.dataset?.nodeId;
        const result = await fetchSyncPost('/api/block/getBlockDOM', {id: blockId});
        console.log('before transactions', result.data?.dom);
    })

    // 当收到消息时被调用
    async function onReceivedMessage(event) {
        const message = parseJson(event.data);
        if(message.cmd === 'transactions') {
            // 这里获取更新后的数据
            console.log(new Date().getTime() - time, message);

            // 更新后
            const result = await fetchSyncPost('/api/block/getBlockDOM', {id: blockId});
            console.log('after transactions', result.data?.dom);
        }
    }

    // 创建socket客户端
    function createSocketClient(url) {
        // 连接 WebSocket 服务器
        const socket = new WebSocket(url);
  
        socket.onopen = function(event) {
            console.log('WebSocket opened');
        };
  
        socket.onmessage = onReceivedMessage;
  
        socket.onclose = function(event) {
            console.log('WebSocket closed!');
        };
  
        socket.onerror = function(error) {
            console.error('WebSocket Error:', error);
        };

        return socket;
    }

    // 客户端向服务器发送消息
    function sendMessage(socket, message) {
        if (socket.readyState === WebSocket.OPEN) {
            socket.send(message);
        } else {
            console.error('WebSocket connection is not open');
        }
    }

    // 解析json
    function parseJson(jsonString) {
        let json = {};
        try {
            json = JSON.parse(jsonString || '{}');
        } catch(e) {
            json = {};
            console.error('parseJson error', e);
        }
        return json;
    }

    // 发送api请求
    async function fetchSyncPost(url, data, returnType = 'json') {
        const init = {
            method: "POST",
        };
        if (data) {
            if (data instanceof FormData) {
                init.body = data;
            } else {
                init.body = JSON.stringify(data);
            }
        }
        try {
            const res = await fetch(url, init);
            const res2 = returnType === 'json' ? await res.json() : await res.text();
            return res2;
        } catch(e) {
            console.log(e);
            return returnType === 'json' ? {code:e.code||1, msg: e.message||"", data: null} : "";
        }
    }
})()

直接监听方法

不用再次启动客户端监听了,只需要监听思源已有的客户端的消息事件即可

siyuan.ws.ws.addEventListener('message', (e) => {
    const msg = JSON.parse(e.data);
    if(msg.cmd === "transactions") {
        // 这里获取更新后的数据
        console.log(msg);
    }
});

终极方案。

封装成了仅调用一次的便捷方案。

如果持续监听用原生更方便。

// 当块被保存时执行回调(仅执行一次)
function whenBlockSaved(filter) {
    return new Promise((resolve, reject) => {
        const ws = siyuan.ws.ws;
        const clearEvent = () => ws.removeEventListener('message', handler);
        const handler = (event) => {
            try {
                const msg = JSON.parse(event.data);
                if(msg.cmd === "transactions") {
                    if(typeof filter === 'function') {
                        if(filter(msg)) resolve(msg);
                    } else {
                        resolve(msg);
                    }
                    clearEvent();
                }
            } catch(e) {
                reject(e);
                clearEvent();
            }
        }
        clearEvent();
        ws.addEventListener('message', handler);
    });
}

// 调用示例

// 链式调用
// whenBlockSaved().then((msg) => {
//     console.log(msg);
// });

// 异步调用
// const msg = await whenBlockSaved();
// console.log(msg);

// 过滤条件
// whenBlockSaved(msg => {
//     return msg.data.find(item => item.doOperations.find(item2 => item2.action === 'update' && item2.id === '20241204115642-hmpp8kh'));
// }).then((msg) => {
//     console.log(msg);
// });

// const filter = msg => msg.data.find(item => item.doOperations.find(item2 => item2.action === 'update' && item2.id === '20241204115642-hmpp8kh'));
// const msg = await whenBlockSaved(filter);
// console.log(msg);

监听同步完成

setTimeout(() => {
    // 监听同步完成
    siyuan.ws.ws.addEventListener('message', (event) => {
        const msg = JSON.parse(event.data);
        if(msg.cmd === 'syncing' && msg.msg !== siyuan.languages._kernel[81]) {
            console.log('数据同步完成');
        }
    });
}, 5000);

监听同步开始

setTimeout(() => {
    // 监听同步开始
    siyuan.ws.ws.addEventListener('message', (event) => {
        const msg = JSON.parse(event.data);
        if(msg.cmd === 'syncing' && msg.msg === siyuan.languages._kernel[81]) {
            console.log('数据同步开始');
        }
    });
}, 5000);

image.png

留下你的脚步
推荐阅读