UNPKG

@deepkit/framework

Version:

165 lines 7.52 kB
const __ΩPick = ['T', 'K', 'Pick', 'l+e#!e"!fRb!b"Pde""N#!w#y']; /*@ts-ignore*/ import { __ΩFrameStart } from '@deepkit/stopwatch'; /*@ts-ignore*/ import { __ΩFrameEnd } from '@deepkit/stopwatch'; function __assignType(fn, args) { fn.__type = args; return fn; } import { decodeCompoundKey, encodeCompoundKey, FrameType, incrementCompoundKey, StopwatchStore } from '@deepkit/stopwatch'; import { existsSync, mkdirSync, readFileSync, unlinkSync } from 'fs'; import { appendFile } from 'fs/promises'; import { join } from 'path'; import { decodeFrames, encodeAnalytic, encodeFrameData, encodeFrames } from '@deepkit/framework-debug-api'; import { formatError, Mutex } from '@deepkit/core'; import { FrameworkConfig } from '../../module.config.js'; import { Zone } from '../../zone.js'; import cluster from 'cluster'; import { performance } from 'perf_hooks'; import { DebugBrokerBus } from '../broker.js'; import { BrokerBusChannel } from '@deepkit/broker'; import { Logger } from '@deepkit/logger'; export class FileStopwatchStore extends StopwatchStore { constructor(config, broker, logger) { super(); this.config = config; this.broker = broker; this.logger = logger; this.syncMutex = new Mutex; this.lastId = -1; this.lastContext = -1; this.framesPath = join(this.config.varPath, this.config.debugStorePath, 'frames.bin'); this.framesDataPath = join(this.config.varPath, this.config.debugStorePath, 'frames-data.bin'); this.analyticsPath = join(this.config.varPath, this.config.debugStorePath, 'analytics.bin'); this.ended = false; this.folderCreated = false; this.frameChannel = (broker.channel.Ω = [['W']], broker.channel('_debug/frames')); this.frameDataChannel = (broker.channel.Ω = [['W']], broker.channel('_debug/frames-data')); } removeAll() { // truncate all files for (const file of [this.framesPath, this.framesDataPath, this.analyticsPath]) { try { unlinkSync(file); } catch { } } this.lastId = -1; this.lastContext = -1; } async close() { //last sync, then stop everything try { // close() is called onAppExecuted so it must not throw await this.syncNow(); } catch (error) { this.logger.error('Could not sync debug store', formatError(error)); } this.ended = true; } run(data, cb) { return Zone.run(data, cb); } getZone() { return Zone.current(); } add(frame) { const [id, worker] = decodeCompoundKey(frame.cid); frame.cid = encodeCompoundKey(id, cluster.isWorker ? cluster.worker.id : 0); frame.timestamp = Math.floor(performance.timeOrigin * 1000 + performance.now() * 1000); super.add(frame); } async loadLastNumberRange() { if (this.lastId >= 0) return; if (existsSync(this.framesPath)) { const data = readFileSync(this.framesPath); if (data.byteLength === 0) { this.lastId = 0; this.lastContext = 0; return; } let last; decodeFrames(data, __assignType((frame) => { if (frame.type === FrameType.start) { last = frame; } }, ['frame', '', 'P"2!"/"'])); if (last) { this.lastId = decodeCompoundKey(last.cid)[0]; this.lastContext = last.context; } } else { this.lastId = 0; } } sync() { if (this.lastSync) return; this.lastSync = setTimeout(() => this.syncNow(), 250); } ensureVarDebugFolder() { if (this.folderCreated) return; mkdirSync(join(this.config.varPath, this.config.debugStorePath), { recursive: true }); this.folderCreated = true; } async syncNow() { if (this.ended) return; await this.syncMutex.lock(); try { await this.loadLastNumberRange(); const frames = this.frameQueue.slice(); const frameData = this.dataQueue.slice(); const analytics = this.analytics.slice(); this.frameQueue = []; this.dataQueue = []; this.analytics = []; for (const frame of frames) { frame.cid = incrementCompoundKey(frame.cid, this.lastId); if (frame.type === FrameType.start) frame.context += this.lastContext; } for (const frame of frameData) { frame.cid = incrementCompoundKey(frame.cid, this.lastId); } const frameBytes = encodeFrames(frames); const dataBytes = encodeFrameData(frameData); const analyticsBytes = encodeAnalytic(analytics); try { this.ensureVarDebugFolder(); if (frameBytes.byteLength) await appendFile(this.framesPath, frameBytes); if (dataBytes.byteLength) await appendFile(this.framesDataPath, dataBytes); if (analyticsBytes.byteLength) await appendFile(this.analyticsPath, analyticsBytes); } catch (error) { this.logger.error('Could not write to debug store', String(error)); } if (!this.ended) { //when we ended, broker connection already closed. So we just write to disk. if (frameBytes.byteLength && this.frameChannel) await this.frameChannel.publish(frameBytes); if (dataBytes.byteLength && this.frameDataChannel) await this.frameDataChannel.publish(dataBytes); } this.lastSync = undefined; const more = this.dataQueue.length || this.frameQueue.length || this.analytics.length; if (more) { this.sync(); } } finally { this.syncMutex.unlock(); } } } FileStopwatchStore.__type = [() => StopwatchStore, 'lastSync', 'syncMutex', function () { return new Mutex; }, 'lastId', function () { return -1; }, 'lastContext', function () { return -1; }, () => BrokerBusChannel, 'frameChannel', () => BrokerBusChannel, 'frameDataChannel', 'framesPath', function () { return join(this.config.varPath, this.config.debugStorePath, 'frames.bin'); }, 'framesDataPath', function () { return join(this.config.varPath, this.config.debugStorePath, 'frames-data.bin'); }, 'analyticsPath', function () { return join(this.config.varPath, this.config.debugStorePath, 'analytics.bin'); }, 'ended', function () { return false; }, 'folderCreated', function () { return false; }, () => __ΩPick, () => FrameworkConfig, "varPath", "debugStorePath", 'config', () => DebugBrokerBus, 'broker', () => Logger, 'logger', 'constructor', 'removeAll', 'close', 'data', '', 'cb', 'run', 'getZone', () => __ΩFrameStart, () => __ΩFrameEnd, 'frame', 'add', 'loadLastNumberRange', 'sync', 'ensureVarDebugFolder', 'syncNow', 'FileStopwatchStore', 'P7!"3"8<!3#<>$\'3%<>&\'3\'<>(PPW7)-J3*PPW7+-J3,&3-<>.&3/<>0&31<>2)33<>4)35<>6PP78P.9.:Jo7#2;<P7<2=<P7>2?<"0@P"0AP"0BPP&"LM2CP"`/D2E"`0FPPP&"LM-J0GPPnHnIJ2J$0KP"0L<P"0M<P"0N<P"0O<5wP']; //# sourceMappingURL=store.js.map