@deepkit/framework
Version:
165 lines • 7.52 kB
JavaScript
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