From 4c957a91d16fd07b49aab4062d4a6a6d32e464aa Mon Sep 17 00:00:00 2001 From: benStre Date: Sat, 8 Jun 2024 14:26:47 +0200 Subject: [PATCH 1/2] Add online status check for client --- .../communication-interfaces/websocket-interface.ts | 10 +++++++++- network/online-status.ts | 10 ++++++++++ runtime/endpoint_config.ts | 1 - 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 network/online-status.ts diff --git a/network/communication-interfaces/websocket-interface.ts b/network/communication-interfaces/websocket-interface.ts index a7bbc1d8..5ead3cb2 100644 --- a/network/communication-interfaces/websocket-interface.ts +++ b/network/communication-interfaces/websocket-interface.ts @@ -1,4 +1,5 @@ import { CommunicationInterface, CommunicationInterfaceSocket } from "../communication-interface.ts"; +import { onlineStatus } from "../online-status.ts"; /** * WebSocket interface socket, used by WebSocket client and server interfaces @@ -50,6 +51,7 @@ export abstract class WebSocketInterface extends CommunicationInterface { + console.warn("error handler", connectionOpen) // don't trigger any further errorHandlers webSocket.removeEventListener('close', errorHandler); webSocket.removeEventListener('error', errorHandler); @@ -62,6 +64,7 @@ export abstract class WebSocketInterface extends CommunicationInterface{ + if (!onlineStatus.val) + errorHandler(); + }); + this.#webSockets.set(webSocket, { errorHandler, openHandler diff --git a/network/online-status.ts b/network/online-status.ts new file mode 100644 index 00000000..000ad48b --- /dev/null +++ b/network/online-status.ts @@ -0,0 +1,10 @@ +import { client_type } from "../utils/constants.ts"; + +export const onlineStatus = $$(navigator?.onLine ?? true); +if (client_type === "deno") { + // TODO +} +else { + globalThis.addEventListener("online", () => onlineStatus.val = true); + globalThis.addEventListener("offline", () => onlineStatus.val = false); +} \ No newline at end of file diff --git a/runtime/endpoint_config.ts b/runtime/endpoint_config.ts index 61fd540f..202e6b70 100644 --- a/runtime/endpoint_config.ts +++ b/runtime/endpoint_config.ts @@ -10,7 +10,6 @@ import { cache_path } from "./cache_path.ts"; import { DatexObject } from "../types/object.ts"; import { Ref } from "./pointers.ts"; import { normalizePath } from "../utils/normalize-path.ts"; -import { ESCAPE_SEQUENCES } from "../datex_all.ts"; type channel_type = 'websocket'|'http' type node_config = { From 2bb03b6117f754f7224679cb61d4b6e5aa58faa3 Mon Sep 17 00:00:00 2001 From: benStre Date: Sat, 8 Jun 2024 17:32:58 +0200 Subject: [PATCH 2/2] fix supranet.connected, global paths --- init.ts | 4 +- network/communication-hub.ts | 12 ++++ .../websocket-interface.ts | 7 +-- network/online-state.ts | 16 +++++ network/online-status.ts | 10 --- network/supranet.ts | 5 ++ runtime/cache_path.ts | 62 ++++++++++--------- runtime/endpoint_config.ts | 4 +- utils/global_values.ts | 15 ++++- 9 files changed, 88 insertions(+), 47 deletions(-) create mode 100644 network/online-state.ts delete mode 100644 network/online-status.ts diff --git a/init.ts b/init.ts index 0b561bce..cf786fe4 100644 --- a/init.ts +++ b/init.ts @@ -3,7 +3,7 @@ import { Pointer } from "./runtime/pointers.ts"; import { LOCAL_ENDPOINT } from "./types/addressing.ts"; import { client_type } from "./utils/constants.ts"; import { Storage, registerStorageAsPointerSource } from "./storage/storage.ts"; -import { cwdURL, logger } from "./utils/global_values.ts"; +import { logger, projectRootURL } from "./utils/global_values.ts"; import { IndexedDBStorageLocation } from "./storage/storage-locations/indexed-db.ts"; import { LocalStorageLocation } from "./storage/storage-locations/local-storage.ts"; import { DenoKVStorageLocation } from "./storage/storage-locations/deno-kv.ts"; @@ -66,7 +66,7 @@ export async function init() { } else if (client_type == "deno") { // TODO: dynamic storage.ts location - use uix path backend/storage.ts as workaround - storageInitModule = new Path('./backend/storage.ts', cwdURL) + storageInitModule = new Path('./backend/storage.ts', projectRootURL) } if (await storageInitModule?.fsExists()) { diff --git a/network/communication-hub.ts b/network/communication-hub.ts index 629c9bb4..e959abae 100644 --- a/network/communication-hub.ts +++ b/network/communication-hub.ts @@ -14,6 +14,7 @@ import { IOHandler } from "../runtime/io_handler.ts"; import { DATEX_ERROR } from "../types/error_codes.ts"; import { LocalLoopbackInterfaceSocket } from "./communication-interfaces/local-loopback-interface.ts"; import { Datex } from "../mod.ts"; +import { Supranet } from "./supranet.ts"; export type DatexInData = { dxb: ArrayBuffer|ReadableStreamDefaultReader, @@ -115,9 +116,20 @@ export class CommunicationHubHandler { const isConnected = this.isConnected(); if (isConnected !== this.connected) { this.#connected = isConnected; + Supranet._setConnected(this.#connected); this.#logger.debug(`Connection status was changed. This endpoint (${Datex.Runtime.endpoint}) is ${isConnected ? "online" : "offline"}!`); + if (this.#connected) + this.onlineEvents.forEach(e => e()); } } + + private onlineEvents = new Set<() => unknown>(); + public addOnlineHandler(method: () => unknown) { + this.onlineEvents.add(method); + } + public removeOnlineHandler(method: () => unknown) { + this.onlineEvents.delete(method); + } private isConnected() { if (this.#defaultInterface?.getSockets().size) { diff --git a/network/communication-interfaces/websocket-interface.ts b/network/communication-interfaces/websocket-interface.ts index 5ead3cb2..f3104df6 100644 --- a/network/communication-interfaces/websocket-interface.ts +++ b/network/communication-interfaces/websocket-interface.ts @@ -1,5 +1,5 @@ import { CommunicationInterface, CommunicationInterfaceSocket } from "../communication-interface.ts"; -import { onlineStatus } from "../online-status.ts"; +import { getOnlineState, onlineStatus } from "../online-state.ts"; /** * WebSocket interface socket, used by WebSocket client and server interfaces @@ -51,7 +51,6 @@ export abstract class WebSocketInterface extends CommunicationInterface { - console.warn("error handler", connectionOpen) // don't trigger any further errorHandlers webSocket.removeEventListener('close', errorHandler); webSocket.removeEventListener('error', errorHandler); @@ -64,7 +63,6 @@ export abstract class WebSocketInterface extends CommunicationInterface{ - if (!onlineStatus.val) + if (!onlineState.val) errorHandler(); }); diff --git a/network/online-state.ts b/network/online-state.ts new file mode 100644 index 00000000..89ad0d08 --- /dev/null +++ b/network/online-state.ts @@ -0,0 +1,16 @@ +import { Pointer } from "../runtime/pointers.ts"; +import { client_type } from "../utils/constants.ts"; +let onlineStatus: Pointer | undefined = undefined; + +export function getOnlineState() { + if (!onlineStatus) + onlineStatus = Pointer.createOrGet(navigator?.onLine ?? true); + if (client_type === "deno") { + // TODO + } + else { + globalThis.addEventListener("online", () => onlineStatus!.val = true); + globalThis.addEventListener("offline", () => onlineStatus!.val = false); + } + return onlineStatus; +} diff --git a/network/online-status.ts b/network/online-status.ts deleted file mode 100644 index 000ad48b..00000000 --- a/network/online-status.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { client_type } from "../utils/constants.ts"; - -export const onlineStatus = $$(navigator?.onLine ?? true); -if (client_type === "deno") { - // TODO -} -else { - globalThis.addEventListener("online", () => onlineStatus.val = true); - globalThis.addEventListener("offline", () => onlineStatus.val = false); -} \ No newline at end of file diff --git a/network/supranet.ts b/network/supranet.ts index cdc7ad46..11d17f4a 100644 --- a/network/supranet.ts +++ b/network/supranet.ts @@ -162,6 +162,11 @@ export class Supranet { return connected; } + // update Supranet.connected state + static _setConnected(connected:boolean) { + this.#connected = connected; + } + static getNode(use_node?:Endpoint) { // channel types? diff --git a/runtime/cache_path.ts b/runtime/cache_path.ts index 60bed3aa..843d83f9 100644 --- a/runtime/cache_path.ts +++ b/runtime/cache_path.ts @@ -1,41 +1,47 @@ import { client_type } from "../utils/constants.ts"; -import { cwdURL } from "../utils/global_values.ts"; +import { projectRootURL } from "../utils/global_values.ts"; import { normalizePath } from "../utils/normalize-path.ts"; +import { commandLineOptions } from "../utils/args.ts"; +let custom_cache_path = commandLineOptions.option("cache-path", {aliases: ["c"], type: "string", description: "Overrides the default path for datex cache files (.datex-cache)"}) -let _cache_path:string|URL = new URL('./.datex-cache/', cwdURL); -let _ptr_cache_path:string|URL = new URL('./pointers/', _cache_path); +export async function _updateCachePaths() { -// command line args (--watch-backend) -if (client_type == "deno") { + let _cache_path:string|URL = new URL('./.datex-cache/', projectRootURL); + let _ptr_cache_path:string|URL = new URL('./pointers/', _cache_path); - const commandLineOptions = (await import("../utils/args.ts" /*lazy*/)).commandLineOptions - - let custom_cache_path = commandLineOptions.option("cache-path", {aliases: ["c"], type: "string", description: "Overrides the default path for datex cache files (.datex-cache)"}) - - if (custom_cache_path) { - if (custom_cache_path?.startsWith("/")) custom_cache_path = `file://${custom_cache_path}`; - if (!custom_cache_path?.endsWith("/")) custom_cache_path += '/'; + // command line args (--watch-backend) + if (client_type == "deno") { + if (custom_cache_path) { - _cache_path = new URL(custom_cache_path, cwdURL); + if (custom_cache_path?.startsWith("/")) custom_cache_path = `file://${custom_cache_path}`; + if (!custom_cache_path?.endsWith("/")) custom_cache_path += '/'; + if (custom_cache_path) { + _cache_path = new URL(custom_cache_path, projectRootURL); + _ptr_cache_path = new URL('./pointers/', _cache_path); + } + } + + // check if write permission for configured datex cache dir + + try { + const testUrl = new URL("write_test", _cache_path.toString()); + Deno.mkdirSync(normalizePath(testUrl), {recursive: true}) + Deno.removeSync(testUrl); + } + catch { + const prev = _cache_path; + _cache_path = new URL(normalizePath(await Deno.makeTempDir()+"/"), "file:///"); _ptr_cache_path = new URL('./pointers/', _cache_path); + console.log("(!) cache directory "+prev+" is readonly, using temporary directory " + _cache_path); } } - // check if write permission for configured datex cache dir - - try { - const testUrl = new URL("write_test", _cache_path.toString()); - Deno.mkdirSync(normalizePath(testUrl), {recursive: true}) - Deno.removeSync(testUrl); - } - catch (e) { - const prev = _cache_path; - _cache_path = new URL(normalizePath(await Deno.makeTempDir()+"/"), "file:///"); - _ptr_cache_path = new URL('./pointers/', _cache_path); - console.log("(!) cache directory "+prev+" is readonly, using temporary directory " + _cache_path); - } + cache_path = _cache_path; + ptr_cache_path = _ptr_cache_path; } -export const cache_path = _cache_path; -export const ptr_cache_path = _ptr_cache_path; +export let cache_path: URL; +export let ptr_cache_path: URL; + +await _updateCachePaths(); \ No newline at end of file diff --git a/runtime/endpoint_config.ts b/runtime/endpoint_config.ts index 202e6b70..24e83a0e 100644 --- a/runtime/endpoint_config.ts +++ b/runtime/endpoint_config.ts @@ -1,6 +1,6 @@ // store and read endpoint config (name, keys, ...) -import { cwdURL, Deno, logger } from "../utils/global_values.ts"; +import { Deno, logger, projectRootURL } from "../utils/global_values.ts"; import { client_type } from "../utils/constants.ts"; import { Endpoint } from "../types/addressing.ts"; import { Crypto } from "./crypto.ts"; @@ -77,7 +77,7 @@ class EndpointConfig implements EndpointConfigData { } // use normal dx file catch { - if (!path) path = new URL('./'+this.DX_FILE_NAME, cwdURL) + if (!path) path = new URL('./'+this.DX_FILE_NAME, projectRootURL) config_file = path; } try { diff --git a/utils/global_values.ts b/utils/global_values.ts index 8c9898a9..078e3560 100644 --- a/utils/global_values.ts +++ b/utils/global_values.ts @@ -34,4 +34,17 @@ export const baseURL = new URL('../../', import.meta.url); export const libURL = new URL('../', import.meta.url); // path from which the script was executed (same aas baseURL in browsers) -export const cwdURL = client_type == "deno" ? new URL('file://'+Deno.cwd()+"/") : baseURL; +export const cwdURL = client_type == "deno" ? new URL('file://'+Deno.cwd()+"/") : baseURL; + +export let projectRootURL = cwdURL; + +/** + * Modify the project root URL (default is the current working directory) + * @param url + */ +export async function _updateProjectRootURL(url:URL) { + const { _updateCachePaths } = await import("../runtime/cache_path.ts"); + + projectRootURL = url; + await _updateCachePaths(); +}