diff options
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/memory.ts | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/api/memory.ts b/src/api/memory.ts new file mode 100644 index 0000000..b6614bb --- /dev/null +++ b/src/api/memory.ts @@ -0,0 +1,119 @@ +import { ClashAPIConfig } from '~/types'; + +import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper'; + +const endpoint = '/memory'; +const textDecoder = new TextDecoder('utf-8'); + +const Size = 150; + +const memory = { + labels: Array(Size).fill(0), + inuse: Array(Size), + oslimit: Array(Size), + + size: Size, + subscribers: [], + appendData(o: { inuse: number; oslimit: number }) { + this.inuse.shift(); + this.oslimit.shift(); + this.labels.shift(); + + const l = Date.now(); + this.inuse.push(o.inuse); + this.oslimit.push(o.oslimit); + this.labels.push(l); + + this.subscribers.forEach((f) => f(o)); + }, + + subscribe(listener: (x: any) => void) { + this.subscribers.push(listener); + return () => { + const idx = this.subscribers.indexOf(listener); + this.subscribers.splice(idx, 1); + }; + }, +}; + +let fetched = false; +let decoded = ''; + +function parseAndAppend(x: string) { + memory.appendData(JSON.parse(x)); +} + +function pump(reader: ReadableStreamDefaultReader) { + return reader.read().then(({ done, value }) => { + const str = textDecoder.decode(value, { stream: !done }); + decoded += str; + + const splits = decoded.split('\n'); + + const lastSplit = splits[splits.length - 1]; + + for (let i = 0; i < splits.length - 1; i++) { + parseAndAppend(splits[i]); + } + + if (done) { + parseAndAppend(lastSplit); + decoded = ''; + + // eslint-disable-next-line no-console + console.log('GET /memory streaming done'); + fetched = false; + return; + } else { + decoded = lastSplit; + } + return pump(reader); + }); +} + +// 1 OPEN +// other value CLOSED +// similar to ws readyState but not the same +// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState +let wsState: number; +function fetchData(apiConfig: ClashAPIConfig) { + if (fetched || wsState === 1) return memory; + wsState = 1; + const url = buildWebSocketURL(apiConfig, endpoint); + const ws = new WebSocket(url); + ws.addEventListener('error', function (_ev) { + wsState = 3; + }); + ws.addEventListener('close', function (_ev) { + wsState = 3; + fetchDataWithFetch(apiConfig); + }); + ws.addEventListener('message', function (event) { + parseAndAppend(event.data); + }); + return memory; +} + +function fetchDataWithFetch(apiConfig: ClashAPIConfig) { + if (fetched) return memory; + fetched = true; + const { url, init } = getURLAndInit(apiConfig); + fetch(url + endpoint, init).then( + (response) => { + if (response.ok) { + const reader = response.body.getReader(); + pump(reader); + } else { + fetched = false; + } + }, + (err) => { + // eslint-disable-next-line no-console + console.log('fetch /memory error', err); + fetched = false; + } + ); + return memory; +} + +export { fetchData }; |
