Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/core/models/DetachedJsPathCallsTable.ts
1028 views
1
import { Database as SqliteDatabase } from 'better-sqlite3';
2
import SqliteTable from '@secret-agent/commons/SqliteTable';
3
import IScriptInstanceMeta from '@secret-agent/interfaces/IScriptInstanceMeta';
4
import { IJsPathHistory } from '../lib/JsPath';
5
6
export default class DetachedJsPathCallsTable extends SqliteTable<IDetachedJsPathCallsRecord> {
7
private cacheByCallsiteKey: {
8
[entrypoint_callsitepath_key: string]: IDetachedJsPathCallsRecord;
9
} = {};
10
11
constructor(readonly db: SqliteDatabase) {
12
super(db, 'DetachedJsPathCalls', [
13
['scriptEntrypoint', 'TEXT'],
14
['callsitePath', 'TEXT'],
15
['execJsPathHistory', 'TEXT'],
16
['timestamp', 'INTEGER'],
17
['key', 'TEXT'],
18
]);
19
}
20
21
public insert(
22
scriptMeta: IScriptInstanceMeta,
23
callsitePath: string,
24
execJsPathHistory: IJsPathHistory[],
25
timestamp: Date,
26
key = 'default',
27
): void {
28
if (!scriptMeta) return;
29
const { entrypoint: scriptEntrypoint } = scriptMeta;
30
const record = {
31
scriptEntrypoint,
32
callsitePath,
33
timestamp: timestamp.getTime(),
34
execJsPathHistory: JSON.stringify(execJsPathHistory),
35
key,
36
};
37
const existing = this.getCachedRecord(scriptMeta, callsitePath, key);
38
// already stored
39
if (existing?.execJsPathHistory === record.execJsPathHistory) return;
40
41
this.insertNow([
42
record.scriptEntrypoint,
43
record.callsitePath,
44
record.execJsPathHistory,
45
record.timestamp,
46
record.key,
47
]);
48
this.cacheRecord(record);
49
}
50
51
public find(
52
scriptMeta: IScriptInstanceMeta,
53
callsite: string,
54
key = 'default',
55
): IDetachedJsPathCallsRecord {
56
if (!scriptMeta) return null;
57
58
const cached = this.getCachedRecord(scriptMeta, callsite, key);
59
if (cached) return cached;
60
61
try {
62
const result = this.db
63
.prepare(
64
`select * from ${this.tableName} where scriptEntrypoint=? and callsitePath=? and key=? order by timestamp desc limit 1`,
65
)
66
.get(scriptMeta.entrypoint, callsite, key);
67
68
if (result) this.cacheRecord(result);
69
70
return result;
71
} catch (err) {
72
if (String(err).includes('no such table')) return;
73
throw err;
74
}
75
}
76
77
private getCachedRecord(
78
scriptMeta: IScriptInstanceMeta,
79
callsite: string,
80
key: string,
81
): IDetachedJsPathCallsRecord {
82
const entrypoint = scriptMeta?.entrypoint ?? '';
83
const cacheKey = DetachedJsPathCallsTable.getCacheKey(entrypoint, callsite, key);
84
return this.cacheByCallsiteKey[cacheKey];
85
}
86
87
private cacheRecord(record: IDetachedJsPathCallsRecord): void {
88
const cacheKey = DetachedJsPathCallsTable.getCacheKey(
89
record.scriptEntrypoint,
90
record.callsitePath,
91
record.key,
92
);
93
this.cacheByCallsiteKey[cacheKey] = record;
94
}
95
96
private static getCacheKey(scriptEntrypoint: string, callsitePath: string, key: string): string {
97
return `${scriptEntrypoint}_${callsitePath}_${key}`;
98
}
99
}
100
101
export interface IDetachedJsPathCallsRecord {
102
scriptEntrypoint: string;
103
callsitePath: string;
104
execJsPathHistory: string;
105
timestamp: number;
106
key: string;
107
}
108
109