diff options
| author | Haishan <[email protected]> | 2020-09-05 00:02:53 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2020-09-08 23:15:04 +0800 |
| commit | 702169941e6956aa8f3b727ffe59a7bd6676c346 (patch) | |
| tree | cbac8bb16592229b0499ab43a646df3bc67e0a2c /src/api | |
| parent | 64ea28607a2077ac503cdb507d80632ba56e22f6 (diff) | |
refactor: use api base url instead of hostname and port
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/configs.js | 30 | ||||
| -rw-r--r-- | src/api/configs.ts | 31 | ||||
| -rw-r--r-- | src/api/connections.ts (renamed from src/api/connections.js) | 76 | ||||
| -rw-r--r-- | src/api/logs.ts (renamed from src/api/logs.js) | 58 | ||||
| -rw-r--r-- | src/api/traffic.js | 13 |
5 files changed, 93 insertions, 115 deletions
diff --git a/src/api/configs.js b/src/api/configs.js deleted file mode 100644 index 42f8ff0..0000000 --- a/src/api/configs.js +++ /dev/null @@ -1,30 +0,0 @@ -import { getURLAndInit } from '../misc/request-helper'; - -const endpoint = '/configs'; - -export async function fetchConfigs(apiConfig) { - const { url, init } = getURLAndInit(apiConfig); - return await fetch(url + endpoint, init); -} - -// TODO support PUT /configs -// req body -// { Path: string } - -function configsPatchWorkaround(o) { - // backward compatibility for older clash using `socket-port` - if ('socks-port' in o) { - o['socket-port'] = o['socks-port']; - } - return o; -} - -export async function updateConfigs(apiConfig, o) { - const { url, init } = getURLAndInit(apiConfig); - return await fetch(url + endpoint, { - ...init, - method: 'PATCH', - // mode: 'cors', - body: JSON.stringify(configsPatchWorkaround(o)) - }); -} diff --git a/src/api/configs.ts b/src/api/configs.ts new file mode 100644 index 0000000..4957e85 --- /dev/null +++ b/src/api/configs.ts @@ -0,0 +1,31 @@ +import { getURLAndInit } from 'src/misc/request-helper'; +import { ClashAPIConfig } from 'src/types'; + +const endpoint = '/configs'; + +export async function fetchConfigs(apiConfig: ClashAPIConfig) { + const { url, init } = getURLAndInit(apiConfig); + return await fetch(url + endpoint, init); +} + +// TODO support PUT /configs +// req body +// { Path: string } + +type ClashConfigPartial = { 'socks-port'?: unknown }; +function configsPatchWorkaround(o: ClashConfigPartial) { + // backward compatibility for older clash using `socket-port` + if ('socks-port' in o) { + o['socket-port'] = o['socks-port']; + } + return o; +} + +export async function updateConfigs( + apiConfig: ClashAPIConfig, + o: ClashConfigPartial +) { + const { url, init } = getURLAndInit(apiConfig); + const body = JSON.stringify(configsPatchWorkaround(o)); + return await fetch(url + endpoint, { ...init, body, method: 'PATCH' }); +} diff --git a/src/api/connections.js b/src/api/connections.ts index f540c74..7608a41 100644 --- a/src/api/connections.js +++ b/src/api/connections.ts @@ -1,4 +1,6 @@ -import { getURLAndInit } from '../misc/request-helper'; +import { ClashAPIConfig } from 'src/types'; + +import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper'; const endpoint = '/connections'; @@ -8,31 +10,31 @@ const subscribers = []; // see also https://github.com/Dreamacro/clash/blob/dev/constant/metadata.go#L41 type UUID = string; type ConnectionItem = { - id: UUID, + id: UUID; metadata: { - network: 'tcp' | 'udp', - type: 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown', - sourceIP: string, - destinationIP: string, - sourcePort: string, - destinationPort: string, - host: string, - }, - upload: number, - download: number, + network: 'tcp' | 'udp'; + type: 'HTTP' | 'HTTP Connect' | 'Socks5' | 'Redir' | 'Unknown'; + sourceIP: string; + destinationIP: string; + sourcePort: string; + destinationPort: string; + host: string; + }; + upload: number; + download: number; // e.g. "2019-11-30T22:48:13.416668+08:00", - start: string, - chains: Array<string>, + start: string; + chains: Array<string>; // e.g. 'Match', 'DomainKeyword' - rule: string, + rule: string; }; type ConnectionsData = { - downloadTotal: number, - uploadTotal: number, - connections: Array<ConnectionItem>, + downloadTotal: number; + uploadTotal: number; + connections: Array<ConnectionItem>; }; -function appendData(s) { +function appendData(s: string) { let o: ConnectionsData; try { o = JSON.parse(s); @@ -43,33 +45,25 @@ function appendData(s) { subscribers.forEach((f) => f(o)); } -function getWsUrl(apiConfig) { - const { hostname, port, secret } = apiConfig; - let qs = ''; - if (typeof secret === 'string' && secret !== '') { - qs += '?token=' + encodeURIComponent(secret); - } - return `ws://${hostname}:${port}${endpoint}${qs}`; -} +type UnsubscribeFn = () => void; -let wsState; -function fetchData(apiConfig, listener) { +let wsState: number; +export function fetchData( + apiConfig: ClashAPIConfig, + listener: unknown +): UnsubscribeFn | void { if (fetched || wsState === 1) { if (listener) return subscribe(listener); } wsState = 1; - const url = getWsUrl(apiConfig); + const url = buildWebSocketURL(apiConfig, endpoint); const ws = new WebSocket(url); - ws.addEventListener('error', function (_ev) { - wsState = 3; - }); - ws.addEventListener('message', function (event) { - appendData(event.data); - }); + ws.addEventListener('error', () => (wsState = 3)); + ws.addEventListener('message', (event) => appendData(event.data)); if (listener) return subscribe(listener); } -function subscribe(listener) { +function subscribe(listener: unknown): UnsubscribeFn { subscribers.push(listener); return function unsubscribe() { const idx = subscribers.indexOf(listener); @@ -77,20 +71,18 @@ function subscribe(listener) { }; } -async function closeAllConnections(apiConfig) { +export async function closeAllConnections(apiConfig: ClashAPIConfig) { const { url, init } = getURLAndInit(apiConfig); return await fetch(url + endpoint, { ...init, method: 'DELETE' }); } -export async function fetchConns(apiConfig) { +export async function fetchConns(apiConfig: ClashAPIConfig) { const { url, init } = getURLAndInit(apiConfig); return await fetch(url + endpoint, { ...init }); } -export async function closeConnById(apiConfig, id) { +export async function closeConnById(apiConfig: ClashAPIConfig, id: string) { const { url: baseURL, init } = getURLAndInit(apiConfig); const url = `${baseURL}${endpoint}/${id}`; return await fetch(url, { ...init, method: 'DELETE' }); } - -export { fetchData, closeAllConnections }; diff --git a/src/api/logs.js b/src/api/logs.ts index caabd04..1958638 100644 --- a/src/api/logs.js +++ b/src/api/logs.ts @@ -1,4 +1,16 @@ -import { getURLAndInit } from '../misc/request-helper'; +import { ClashAPIConfig } from 'src/types'; + +import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper'; + +type LogsAPIConfig = ClashAPIConfig & { logLevel: string }; +type LogEntry = { + time?: string; + id?: string; + even?: boolean; + // and some other props +}; +type AppendLogFn = (x: LogEntry) => void; + const endpoint = '/logs'; const textDecoder = new TextDecoder('utf-8'); @@ -10,8 +22,8 @@ let even = false; let fetched = false; let decoded = ''; -function appendData(s, callback) { - let o; +function appendData(s: string, callback: AppendLogFn) { + let o: LogEntry; try { o = JSON.parse(s); } catch (err) { @@ -23,12 +35,12 @@ function appendData(s, callback) { const time = now.toLocaleString('zh-Hans'); // mutate input param in place intentionally o.time = time; - o.id = now - 0 + getRandomStr(); + o.id = +now - 0 + getRandomStr(); o.even = even = !even; callback(o); } -function pump(reader, appendLog) { +function pump(reader: ReadableStreamDefaultReader, appendLog: AppendLogFn) { return reader.read().then(({ done, value }) => { const str = textDecoder.decode(value, { stream: !done }); decoded += str; @@ -56,31 +68,20 @@ function pump(reader, appendLog) { }); } -const apiConfigSnapshot = {}; -let controller; - -function getWsUrl(apiConfig) { - const { hostname, port, secret, logLevel } = apiConfig; - let qs = '?level=' + logLevel; - if (typeof secret === 'string' && secret !== '') { - qs += '&token=' + encodeURIComponent(secret); - } - return `ws://${hostname}:${port}${endpoint}${qs}`; -} +let apiConfigSnapshot: LogsAPIConfig; +let controller: AbortController; // 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; -function fetchLogs(apiConfig, appendLog) { +let wsState: number; +export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) { if (fetched || wsState === 1) return; wsState = 1; - const url = getWsUrl(apiConfig); + const url = buildWebSocketURL(apiConfig, endpoint); const ws = new WebSocket(url); - ws.addEventListener('error', function (_ev) { - wsState = 3; - }); + ws.addEventListener('error', () => (wsState = 3)); ws.addEventListener('close', function (_ev) { wsState = 3; fetchLogsWithFetch(apiConfig, appendLog); @@ -90,11 +91,10 @@ function fetchLogs(apiConfig, appendLog) { }); } -function fetchLogsWithFetch(apiConfig, appendLog) { +function fetchLogsWithFetch(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) { if ( controller && - (apiConfigSnapshot.hostname !== apiConfig.hostname || - apiConfigSnapshot.port !== apiConfig.port || + (apiConfigSnapshot.baseURL !== apiConfig.baseURL || apiConfigSnapshot.secret !== apiConfig.secret || apiConfigSnapshot.logLevel !== apiConfig.logLevel) ) { @@ -104,11 +104,7 @@ function fetchLogsWithFetch(apiConfig, appendLog) { } fetched = true; - - apiConfigSnapshot.hostname = apiConfig.hostname; - apiConfigSnapshot.port = apiConfig.port; - apiConfigSnapshot.secret = apiConfig.secret; - apiConfigSnapshot.logLevel = apiConfig.logLevel; + apiConfigSnapshot = { ...apiConfig }; controller = new AbortController(); const signal = controller.signal; @@ -131,5 +127,3 @@ function fetchLogsWithFetch(apiConfig, appendLog) { } ); } - -export { fetchLogs }; diff --git a/src/api/traffic.js b/src/api/traffic.js index f3f33ca..e50ec5e 100644 --- a/src/api/traffic.js +++ b/src/api/traffic.js @@ -1,4 +1,4 @@ -import { getURLAndInit } from '../misc/request-helper'; +import { buildWebSocketURL, getURLAndInit } from '../misc/request-helper'; const endpoint = '/traffic'; const textDecoder = new TextDecoder('utf-8'); @@ -69,15 +69,6 @@ function pump(reader) { }); } -function getWsUrl(apiConfig) { - const { hostname, port, secret } = apiConfig; - let qs = ''; - if (typeof secret === 'string' && secret !== '') { - qs += '?token=' + encodeURIComponent(secret); - } - return `ws://${hostname}:${port}${endpoint}${qs}`; -} - // 1 OPEN // other value CLOSED // similar to ws readyState but not the same @@ -86,7 +77,7 @@ let wsState; function fetchData(apiConfig) { if (fetched || wsState === 1) return traffic; wsState = 1; - const url = getWsUrl(apiConfig); + const url = buildWebSocketURL(apiConfig, endpoint); const ws = new WebSocket(url); ws.addEventListener('error', function (_ev) { wsState = 3; |
