diff --git a/fe-app-podkop/src/podkop/services/core.service.ts b/fe-app-podkop/src/podkop/services/core.service.ts index 4b7d827..ac9df68 100644 --- a/fe-app-podkop/src/podkop/services/core.service.ts +++ b/fe-app-podkop/src/podkop/services/core.service.ts @@ -1,5 +1,5 @@ import { TabServiceInstance } from './tab.service'; -import { store } from '../../store'; +import { store } from './store.service'; export function coreService() { TabServiceInstance.onChange((activeId, tabs) => { diff --git a/fe-app-podkop/src/podkop/services/index.ts b/fe-app-podkop/src/podkop/services/index.ts index 4b776d2..d6477f7 100644 --- a/fe-app-podkop/src/podkop/services/index.ts +++ b/fe-app-podkop/src/podkop/services/index.ts @@ -1,2 +1,4 @@ export * from './tab.service'; export * from './core.service'; +export * from './socket.service'; +export * from './store.service'; diff --git a/fe-app-podkop/src/socket.ts b/fe-app-podkop/src/podkop/services/socket.service.ts similarity index 100% rename from fe-app-podkop/src/socket.ts rename to fe-app-podkop/src/podkop/services/socket.service.ts diff --git a/fe-app-podkop/src/store.ts b/fe-app-podkop/src/podkop/services/store.service.ts similarity index 95% rename from fe-app-podkop/src/store.ts rename to fe-app-podkop/src/podkop/services/store.service.ts index 3bd35a9..5093ba7 100644 --- a/fe-app-podkop/src/store.ts +++ b/fe-app-podkop/src/podkop/services/store.service.ts @@ -1,5 +1,5 @@ -import { Podkop } from './podkop/types'; -import { initialDiagnosticStore } from './podkop/tabs/diagnostic/diagnostic.store'; +import { Podkop } from '../types'; +import { initialDiagnosticStore } from '../tabs/diagnostic/diagnostic.store'; function jsonStableStringify(obj: T): string { return JSON.stringify(obj, (_, value) => { @@ -29,7 +29,7 @@ function jsonEqual(a: A, b: B): boolean { type Listener = (next: T, prev: T, diff: Partial) => void; // eslint-disable-next-line -class Store> { +class StoreService> { private value: T; private readonly initial: T; private listeners = new Set>(); @@ -207,4 +207,4 @@ const initialStore: StoreType = { ...initialDiagnosticStore, }; -export const store = new Store(initialStore); +export const store = new StoreService(initialStore); diff --git a/fe-app-podkop/src/podkop/tabs/dashboard/initDashboardController.ts b/fe-app-podkop/src/podkop/tabs/dashboard/initDashboardController.ts index d9be183..6915ba4 100644 --- a/fe-app-podkop/src/podkop/tabs/dashboard/initDashboardController.ts +++ b/fe-app-podkop/src/podkop/tabs/dashboard/initDashboardController.ts @@ -4,8 +4,6 @@ import { onMount, preserveScrollForPage, } from '../../../helpers'; -import { store, StoreType } from '../../../store'; -import { socket } from '../../../socket'; import { prettyBytes } from '../../../helpers/prettyBytes'; import { renderSections } from './renderSections'; import { renderWidget } from './renderWidget'; @@ -14,6 +12,7 @@ import { CustomPodkopMethods, PodkopShellMethods, } from '../../methods'; +import { socket, store, StoreType } from '../../services'; // Fetchers diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts index 18a0dac..f33d11c 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runDnsCheck.ts @@ -1,8 +1,8 @@ import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck'; import { insertIf } from '../../../../helpers'; -import { IDiagnosticsChecksItem } from '../../../../store'; import { DIAGNOSTICS_CHECKS_MAP } from './contstants'; import { PodkopShellMethods } from '../../../methods'; +import { IDiagnosticsChecksItem } from '../../../services'; export async function runDnsCheck() { const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.DNS; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts index d2b87e3..5983a84 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts @@ -1,8 +1,8 @@ import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck'; import { insertIf } from '../../../../helpers'; -import { IDiagnosticsChecksItem } from '../../../../store'; import { DIAGNOSTICS_CHECKS_MAP } from './contstants'; import { PodkopShellMethods, RemoteFakeIPMethods } from '../../../methods'; +import { IDiagnosticsChecksItem } from '../../../services'; export async function runFakeIPCheck() { const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.FAKEIP; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts index cc0a4c9..0fc8d87 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/checks/runNftCheck.ts @@ -1,7 +1,6 @@ import { updateDiagnosticsCheck } from '../updateDiagnosticsCheck'; import { DIAGNOSTICS_CHECKS_MAP } from './contstants'; -import { RemoteFakeIPMethods } from '../../../methods/fakeip'; -import { PodkopShellMethods } from '../../../methods'; +import { RemoteFakeIPMethods, PodkopShellMethods } from '../../../methods'; export async function runNftCheck() { const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.NFT; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/diagnostic.store.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/diagnostic.store.ts index a39c141..b34bbc0 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/diagnostic.store.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/diagnostic.store.ts @@ -2,7 +2,7 @@ import { DIAGNOSTICS_CHECKS, DIAGNOSTICS_CHECKS_MAP, } from './checks/contstants'; -import { StoreType } from '../../../store'; +import { StoreType } from '../../services'; export const initialDiagnosticStore: Pick< StoreType, diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/initDiagnosticController.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/initDiagnosticController.ts index a8f43df..94ea952 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/initDiagnosticController.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/initDiagnosticController.ts @@ -1,5 +1,4 @@ import { onMount, preserveScrollForPage } from '../../../helpers'; -import { store, StoreType } from '../../../store'; import { renderCheckSection } from './renderCheckSection'; import { runDnsCheck } from './checks/runDnsCheck'; import { runSingBoxCheck } from './checks/runSingBoxCheck'; @@ -9,6 +8,7 @@ import { renderDiagnosticRunAction } from './renderDiagnosticRunAction'; import { renderAvailableActions } from './renderAvailableActions'; import { renderSystemInfo } from './renderSystemInfo'; import { loadingDiagnosticsChecksStore } from './diagnostic.store'; +import { store, StoreType } from '../../services'; function renderDiagnosticsChecks() { console.log('renderDiagnosticsChecks'); diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts index e7d8098..5f83387 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/renderCheckSection.ts @@ -8,7 +8,7 @@ import { renderTriangleAlertIcon24, renderXIcon24, } from '../../../icons'; -import { IDiagnosticsChecksStoreItem } from '../../../store'; +import { IDiagnosticsChecksStoreItem } from '../../services'; type IRenderCheckSectionProps = IDiagnosticsChecksStoreItem; diff --git a/fe-app-podkop/src/podkop/tabs/diagnostic/updateDiagnosticsCheck.ts b/fe-app-podkop/src/podkop/tabs/diagnostic/updateDiagnosticsCheck.ts index a36697f..62e75f2 100644 --- a/fe-app-podkop/src/podkop/tabs/diagnostic/updateDiagnosticsCheck.ts +++ b/fe-app-podkop/src/podkop/tabs/diagnostic/updateDiagnosticsCheck.ts @@ -1,4 +1,4 @@ -import { IDiagnosticsChecksStoreItem, store } from '../../../store'; +import { IDiagnosticsChecksStoreItem, store } from '../../services'; export function updateDiagnosticsCheck( check: IDiagnosticsChecksStoreItem, diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index ac258f0..61b965f 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -1477,7 +1477,7 @@ var loadingDiagnosticsChecksStore = { ] }; -// src/store.ts +// src/podkop/services/store.service.ts function jsonStableStringify(obj) { return JSON.stringify(obj, (_2, value) => { if (value && typeof value === "object" && !Array.isArray(value)) { @@ -1499,7 +1499,7 @@ function jsonEqual(a, b) { return false; } } -var Store = class { +var StoreService = class { constructor(initial) { this.listeners = /* @__PURE__ */ new Set(); this.lastHash = ""; @@ -1600,7 +1600,7 @@ var initialStore = { }, ...initialDiagnosticStore }; -var store = new Store(initialStore); +var store = new StoreService(initialStore); // src/podkop/services/core.service.ts function coreService() { @@ -1614,6 +1614,108 @@ function coreService() { }); } +// src/podkop/services/socket.service.ts +var SocketManager = class _SocketManager { + constructor() { + this.sockets = /* @__PURE__ */ new Map(); + this.listeners = /* @__PURE__ */ new Map(); + this.connected = /* @__PURE__ */ new Map(); + this.errorListeners = /* @__PURE__ */ new Map(); + } + static getInstance() { + if (!_SocketManager.instance) { + _SocketManager.instance = new _SocketManager(); + } + return _SocketManager.instance; + } + connect(url) { + if (this.sockets.has(url)) return; + const ws = new WebSocket(url); + this.sockets.set(url, ws); + this.connected.set(url, false); + this.listeners.set(url, /* @__PURE__ */ new Set()); + this.errorListeners.set(url, /* @__PURE__ */ new Set()); + ws.addEventListener("open", () => { + this.connected.set(url, true); + console.info(`Connected: ${url}`); + }); + ws.addEventListener("message", (event) => { + const handlers = this.listeners.get(url); + if (handlers) { + for (const handler of handlers) { + try { + handler(event.data); + } catch (err) { + console.error(`Handler error for ${url}:`, err); + } + } + } + }); + ws.addEventListener("close", () => { + this.connected.set(url, false); + console.warn(`Disconnected: ${url}`); + this.triggerError(url, "Connection closed"); + }); + ws.addEventListener("error", (err) => { + console.error(`Socket error for ${url}:`, err); + this.triggerError(url, err); + }); + } + subscribe(url, listener, onError) { + if (!this.sockets.has(url)) { + this.connect(url); + } + this.listeners.get(url)?.add(listener); + if (onError) { + this.errorListeners.get(url)?.add(onError); + } + } + unsubscribe(url, listener, onError) { + this.listeners.get(url)?.delete(listener); + if (onError) { + this.errorListeners.get(url)?.delete(onError); + } + } + // eslint-disable-next-line + send(url, data) { + const ws = this.sockets.get(url); + if (ws && this.connected.get(url)) { + ws.send(typeof data === "string" ? data : JSON.stringify(data)); + } else { + console.warn(`Cannot send: not connected to ${url}`); + this.triggerError(url, "Not connected"); + } + } + disconnect(url) { + const ws = this.sockets.get(url); + if (ws) { + ws.close(); + this.sockets.delete(url); + this.listeners.delete(url); + this.errorListeners.delete(url); + this.connected.delete(url); + } + } + disconnectAll() { + for (const url of this.sockets.keys()) { + this.disconnect(url); + } + } + triggerError(url, err) { + const handlers = this.errorListeners.get(url); + if (handlers) { + for (const cb of handlers) { + try { + cb(err); + } catch (e) { + console.error(`Error handler threw for ${url}:`, e); + } + } + } + } +}; +var socket = SocketManager.getInstance(); + // src/podkop/tabs/dashboard/renderSections.ts function renderFailedState() { return E( @@ -1839,108 +1941,6 @@ function renderDashboard() { ); } -// src/socket.ts -var SocketManager = class _SocketManager { - constructor() { - this.sockets = /* @__PURE__ */ new Map(); - this.listeners = /* @__PURE__ */ new Map(); - this.connected = /* @__PURE__ */ new Map(); - this.errorListeners = /* @__PURE__ */ new Map(); - } - static getInstance() { - if (!_SocketManager.instance) { - _SocketManager.instance = new _SocketManager(); - } - return _SocketManager.instance; - } - connect(url) { - if (this.sockets.has(url)) return; - const ws = new WebSocket(url); - this.sockets.set(url, ws); - this.connected.set(url, false); - this.listeners.set(url, /* @__PURE__ */ new Set()); - this.errorListeners.set(url, /* @__PURE__ */ new Set()); - ws.addEventListener("open", () => { - this.connected.set(url, true); - console.info(`Connected: ${url}`); - }); - ws.addEventListener("message", (event) => { - const handlers = this.listeners.get(url); - if (handlers) { - for (const handler of handlers) { - try { - handler(event.data); - } catch (err) { - console.error(`Handler error for ${url}:`, err); - } - } - } - }); - ws.addEventListener("close", () => { - this.connected.set(url, false); - console.warn(`Disconnected: ${url}`); - this.triggerError(url, "Connection closed"); - }); - ws.addEventListener("error", (err) => { - console.error(`Socket error for ${url}:`, err); - this.triggerError(url, err); - }); - } - subscribe(url, listener, onError) { - if (!this.sockets.has(url)) { - this.connect(url); - } - this.listeners.get(url)?.add(listener); - if (onError) { - this.errorListeners.get(url)?.add(onError); - } - } - unsubscribe(url, listener, onError) { - this.listeners.get(url)?.delete(listener); - if (onError) { - this.errorListeners.get(url)?.delete(onError); - } - } - // eslint-disable-next-line - send(url, data) { - const ws = this.sockets.get(url); - if (ws && this.connected.get(url)) { - ws.send(typeof data === "string" ? data : JSON.stringify(data)); - } else { - console.warn(`Cannot send: not connected to ${url}`); - this.triggerError(url, "Not connected"); - } - } - disconnect(url) { - const ws = this.sockets.get(url); - if (ws) { - ws.close(); - this.sockets.delete(url); - this.listeners.delete(url); - this.errorListeners.delete(url); - this.connected.delete(url); - } - } - disconnectAll() { - for (const url of this.sockets.keys()) { - this.disconnect(url); - } - } - triggerError(url, err) { - const handlers = this.errorListeners.get(url); - if (handlers) { - for (const cb of handlers) { - try { - cb(err); - } catch (e) { - console.error(`Error handler threw for ${url}:`, e); - } - } - } - } -}; -var socket = SocketManager.getInstance(); - // src/helpers/prettyBytes.ts function prettyBytes(n) { const UNITS = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; @@ -3232,7 +3232,9 @@ return baseclass.extend({ preserveScrollForPage, renderDashboard, renderDiagnostic, + socket, splitProxyString, + store, svgEl, validateDNS, validateDomain,