|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
import * as plugins from './typedserver_web.plugins.js';
|
|
|
|
|
import * as interfaces from '../dist_ts_interfaces/index.js';
|
|
|
|
|
import { logger } from './typedserver_web.logger.js';
|
|
|
|
|
logger.log('info', `TypedServer-Devtools initialized!`);
|
|
|
|
|
// TypedServer-Devtools loaded
|
|
|
|
|
|
|
|
|
|
import { TypedserverStatusPill } from './typedserver_web.statuspill.js';
|
|
|
|
|
|
|
|
|
|
@@ -51,6 +51,9 @@ export class ReloadChecker {
|
|
|
|
|
window.location.reload();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private swRetryCount = 0;
|
|
|
|
|
private static readonly MAX_SW_RETRIES = 5;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Subscribe to service worker status updates
|
|
|
|
|
*/
|
|
|
|
|
@@ -67,13 +70,12 @@ export class ReloadChecker {
|
|
|
|
|
timestamp: status.timestamp,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
logger.log('info', 'Subscribed to service worker status updates');
|
|
|
|
|
logger.log('ok', 'Subscribed to service worker status updates');
|
|
|
|
|
|
|
|
|
|
// Get initial SW status
|
|
|
|
|
this.fetchServiceWorkerStatus();
|
|
|
|
|
} else {
|
|
|
|
|
logger.log('note', 'Service worker client not available yet, will retry...');
|
|
|
|
|
// Retry after a delay
|
|
|
|
|
} else if (this.swRetryCount < ReloadChecker.MAX_SW_RETRIES) {
|
|
|
|
|
this.swRetryCount++;
|
|
|
|
|
setTimeout(() => this.subscribeToServiceWorker(), 2000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -109,7 +111,6 @@ export class ReloadChecker {
|
|
|
|
|
* starts the reload checker
|
|
|
|
|
*/
|
|
|
|
|
public async performHttpRequest() {
|
|
|
|
|
logger.log('info', 'performing http check...');
|
|
|
|
|
(await this.store.get(this.storeKey))
|
|
|
|
|
? null
|
|
|
|
|
: await this.store.set(this.storeKey, globalThis.typedserver.lastReload);
|
|
|
|
|
@@ -201,22 +202,29 @@ export class ReloadChecker {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async connectTypedsocket() {
|
|
|
|
|
if (!this.typedsocket) {
|
|
|
|
|
this.typedrouter.addTypedHandler<interfaces.IReq_PushLatestServerChangeTime>(
|
|
|
|
|
new plugins.typedrequest.TypedHandler('pushLatestServerChangeTime', async (dataArg) => {
|
|
|
|
|
this.checkReload(dataArg.time);
|
|
|
|
|
return {};
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
this.typedsocket = await plugins.typedsocket.TypedSocket.createClient(
|
|
|
|
|
this.typedrouter,
|
|
|
|
|
plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl()
|
|
|
|
|
);
|
|
|
|
|
private typedsocketConnected = false;
|
|
|
|
|
|
|
|
|
|
public connectTypedsocket() {
|
|
|
|
|
if (this.typedsocket) return;
|
|
|
|
|
|
|
|
|
|
this.typedrouter.addTypedHandler<interfaces.IReq_PushLatestServerChangeTime>(
|
|
|
|
|
new plugins.typedrequest.TypedHandler('pushLatestServerChangeTime', async (dataArg) => {
|
|
|
|
|
this.checkReload(dataArg.time);
|
|
|
|
|
return {};
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Connect in the background — never block the HTTP polling loop
|
|
|
|
|
plugins.typedsocket.TypedSocket.createClient(
|
|
|
|
|
this.typedrouter,
|
|
|
|
|
plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl()
|
|
|
|
|
).then(async (socket) => {
|
|
|
|
|
this.typedsocket = socket;
|
|
|
|
|
this.typedsocketConnected = true;
|
|
|
|
|
await this.typedsocket.setTag('typedserver_frontend', {});
|
|
|
|
|
this.typedsocket.statusSubject.subscribe(async (statusArg) => {
|
|
|
|
|
console.log(`typedsocket status: ${statusArg}`);
|
|
|
|
|
if (statusArg === 'disconnected' || statusArg === 'reconnecting') {
|
|
|
|
|
this.typedsocketConnected = false;
|
|
|
|
|
this.backendConnectionLost = true;
|
|
|
|
|
this.statusPill.updateStatus({
|
|
|
|
|
source: 'backend',
|
|
|
|
|
@@ -225,35 +233,39 @@ export class ReloadChecker {
|
|
|
|
|
persist: true,
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
});
|
|
|
|
|
} else if (statusArg === 'connected' && this.backendConnectionLost) {
|
|
|
|
|
this.backendConnectionLost = false;
|
|
|
|
|
this.statusPill.updateStatus({
|
|
|
|
|
source: 'backend',
|
|
|
|
|
type: 'connected',
|
|
|
|
|
message: 'TypedSocket connected',
|
|
|
|
|
persist: false,
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
});
|
|
|
|
|
// lets check if a reload is necessary
|
|
|
|
|
const getLatestServerChangeTime =
|
|
|
|
|
this.typedsocket.createTypedRequest<interfaces.IReq_GetLatestServerChangeTime>(
|
|
|
|
|
'getLatestServerChangeTime'
|
|
|
|
|
);
|
|
|
|
|
const response = await getLatestServerChangeTime.fire({});
|
|
|
|
|
this.checkReload(response.time);
|
|
|
|
|
} else if (statusArg === 'connected') {
|
|
|
|
|
this.typedsocketConnected = true;
|
|
|
|
|
if (this.backendConnectionLost) {
|
|
|
|
|
this.backendConnectionLost = false;
|
|
|
|
|
this.statusPill.updateStatus({
|
|
|
|
|
source: 'backend',
|
|
|
|
|
type: 'connected',
|
|
|
|
|
message: 'TypedSocket connected',
|
|
|
|
|
persist: false,
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
});
|
|
|
|
|
// lets check if a reload is necessary
|
|
|
|
|
const getLatestServerChangeTime =
|
|
|
|
|
this.typedsocket.createTypedRequest<interfaces.IReq_GetLatestServerChangeTime>(
|
|
|
|
|
'getLatestServerChangeTime'
|
|
|
|
|
);
|
|
|
|
|
const response = await getLatestServerChangeTime.fire({});
|
|
|
|
|
this.checkReload(response.time);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
logger.log('success', `ReloadChecker connected through typedsocket!`);
|
|
|
|
|
logger.log('ok', `ReloadChecker connected via TypedSocket`);
|
|
|
|
|
|
|
|
|
|
// Enable traffic logging for sw-dash
|
|
|
|
|
this.enableTrafficLogging();
|
|
|
|
|
}
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
logger.log('warn', `TypedSocket connection failed: ${err}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public started = false;
|
|
|
|
|
public async start() {
|
|
|
|
|
this.started = true;
|
|
|
|
|
logger.log('info', `starting ReloadChecker...`);
|
|
|
|
|
|
|
|
|
|
// Subscribe to service worker status updates
|
|
|
|
|
this.subscribeToServiceWorker();
|
|
|
|
|
@@ -261,11 +273,12 @@ export class ReloadChecker {
|
|
|
|
|
while (this.started) {
|
|
|
|
|
const response = await this.performHttpRequest();
|
|
|
|
|
if (response?.status === 200) {
|
|
|
|
|
logger.log('info', `ReloadChecker reached backend!`);
|
|
|
|
|
await this.checkReload(parseInt(await response.text()));
|
|
|
|
|
await this.connectTypedsocket();
|
|
|
|
|
this.connectTypedsocket();
|
|
|
|
|
}
|
|
|
|
|
await plugins.smartdelay.delayFor(120000);
|
|
|
|
|
// Poll more frequently when WebSocket isn't connected (fallback detection)
|
|
|
|
|
const pollInterval = this.typedsocketConnected ? 120000 : 5000;
|
|
|
|
|
await plugins.smartdelay.delayFor(pollInterval);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -282,20 +295,24 @@ export class ReloadChecker {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private trafficLoggingRetryCount = 0;
|
|
|
|
|
private static readonly MAX_TRAFFIC_LOGGING_RETRIES = 5;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enable TypedRequest traffic logging to the service worker
|
|
|
|
|
* Sets up global hooks on TypedRouter to capture all request/response traffic
|
|
|
|
|
*/
|
|
|
|
|
public enableTrafficLogging(): void {
|
|
|
|
|
if (this.trafficLoggingEnabled) {
|
|
|
|
|
logger.log('note', 'Traffic logging already enabled');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if service worker client is available
|
|
|
|
|
if (!globalThis.globalSw?.actionManager) {
|
|
|
|
|
logger.log('note', 'Service worker client not available, will retry traffic logging setup...');
|
|
|
|
|
setTimeout(() => this.enableTrafficLogging(), 2000);
|
|
|
|
|
if (this.trafficLoggingRetryCount < ReloadChecker.MAX_TRAFFIC_LOGGING_RETRIES) {
|
|
|
|
|
this.trafficLoggingRetryCount++;
|
|
|
|
|
setTimeout(() => this.enableTrafficLogging(), 2000);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -320,7 +337,7 @@ export class ReloadChecker {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.trafficLoggingEnabled = true;
|
|
|
|
|
logger.log('success', 'TypedRequest traffic logging enabled');
|
|
|
|
|
logger.log('ok', 'Traffic logging enabled');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|