scrapbox-userscript-websocket
/icons/hr.icon
ScrapboxのUserScriptでWebSocketを使用するための低レイヤーlibrary 提供する機能
socketIO()
CDN経由でSocket.IOのlibraryを読み込み、Socketを生成して返す
wrap()
Socketの型付きPromise wrapper
Scrapboxが使っている通信objectの型定義
helper函数は実装しない
実装したいこと
event listenerの型定義を簡単にする
現状
Parameter<>が入れ子になるなど、型定義が読みにくくなっている
どうするか
入力の型と出力の型とのペアを代わりに使う
これちょっと難しそうだったtakker.icon
response()のほうはそんなに難しそうではないけど
request()のほうがややこしい
入力の型が複数あったりする
現状問題は起きていないので放置する
型定義の修正で、いちいち2つのrepoを操作しないといけないのが面倒
replacelinksなど、いくつか共通する型定義がある
2022-02-11
16:46:15 ImageCommitはimage: nullも受け取るようだ
修正しよう
code:mod.ts
code:mod.js
var m="4.2.0",f=https://cdnjs.cloudflare.com/ajax/libs/socket.io/${m}/socket.io.min.js,u;async function v(){let o=(await l())("https://scrapbox.io",{reconnectionDelay:5e3,transports:["websocket"]});return await new Promise((n,s)=>{let r=i=>s(i);o.once("connect",()=>{o.off("disconnect",r),n()}),o.once("disconnect",r)}),o}async function l(){if(!document.querySelector(script[src="${f}"])){let e=document.createElement("script");e.src=f,await new Promise((o,n)=>{e.onload=()=>o(),e.onerror=s=>{u=s,n(s)},document.head.append(e)})}return new Promise((e,o)=>{let n=setInterval(()=>{window.io&&(clearInterval(n),e(window.io))},500)})}function w(e,o=9e4){function n(r,i){let c;return new Promise((d,t)=>{let p=a=>{clearTimeout(c),t(new Error(a))};e.emit(r,i,a=>{clearTimeout(c),e.off("disconnect",p),a.error&&t(new Error(JSON.stringify(a.error))),"data"in a?d(a?.data):d(void 0)}),c=setTimeout(()=>{e.off("disconnect",p),t(new Error(Timeout: exceeded ${o}ms))},o),e.once("disconnect",p)})}async function*s(...r){let i,c=()=>new Promise(t=>i=t),d=t=>{i?.(t)};for(let t of r)e.on(t,d);try{for(;;)yield await c()}finally{for(let t of r)e.off(t,d)}}return{request:n,response:s}}export{v as socketIO,w as wrap}; test
code:streamを購読する.js
import { socketIO, wrap } from "./mod.js";
const io = await socketIO();
const { request, response } = wrap(io);
try {
await request("socket.io-request", {
method: "room:join",
data: {
projectUpdatesStream: true,
projectId: "5f2f02f3c4a48d00237e1534", // takker
pageId: null,
},
});
for await (const data of response("projectUpdatesStream:commit")) {
console.debug(data);
}
} catch (e) {
console.error(e);
}