@andrew_l/binlog 0.3.21 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +99 -101
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +211 -311
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -9
- package/dist/index.cjs +0 -326
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -123
- package/dist/index.d.ts +0 -123
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrew_l/binlog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A high-performance binary logging system for Node.js applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,27 +15,28 @@
|
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
17
17
|
"import": "./dist/index.mjs",
|
|
18
|
-
"require": "./dist/index.
|
|
18
|
+
"require": "./dist/index.mjs",
|
|
19
|
+
"types": "./dist/index.d.mts"
|
|
19
20
|
}
|
|
20
21
|
},
|
|
21
|
-
"main": "./dist/index.
|
|
22
|
-
"types": "./dist/index.d.
|
|
22
|
+
"main": "./dist/index.mjs",
|
|
23
|
+
"types": "./dist/index.d.mts",
|
|
23
24
|
"files": [
|
|
24
25
|
"dist"
|
|
25
26
|
],
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/node": "22.10.5",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
29
|
+
"obuild": "^0.4.37",
|
|
30
|
+
"typescript": "6.0.3",
|
|
30
31
|
"vitest": "^3.2.4"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@andrew_l/
|
|
34
|
-
"@andrew_l/
|
|
34
|
+
"@andrew_l/tl-pack": "0.4.0",
|
|
35
|
+
"@andrew_l/toolkit": "0.4.0"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"check-types": "tsc --noEmit",
|
|
38
|
-
"build": "
|
|
39
|
+
"build": "obuild",
|
|
39
40
|
"test": "vitest run --typecheck",
|
|
40
41
|
"test:watch": "vitest watch --typecheck"
|
|
41
42
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const toolkit = require('@andrew_l/toolkit');
|
|
4
|
-
const tlPack = require('@andrew_l/tl-pack');
|
|
5
|
-
const fs = require('node:fs');
|
|
6
|
-
const path = require('node:path');
|
|
7
|
-
|
|
8
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
9
|
-
|
|
10
|
-
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
11
|
-
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
12
|
-
|
|
13
|
-
class Binlog {
|
|
14
|
-
_options;
|
|
15
|
-
_filePattern;
|
|
16
|
-
_directory;
|
|
17
|
-
_currentFile;
|
|
18
|
-
_currentFileDescriptor;
|
|
19
|
-
_currentFileSize;
|
|
20
|
-
_currentFileIndex;
|
|
21
|
-
_isOpen;
|
|
22
|
-
_log;
|
|
23
|
-
BINLOG_MAGIC = 1145197643;
|
|
24
|
-
BINLOG_VERSION = 1;
|
|
25
|
-
BINLOG_HEADER_SIZE = 16;
|
|
26
|
-
BINLOG_ENTRY_HEADER_SIZE = 20;
|
|
27
|
-
BINLOG_FLAG = Object.freeze({
|
|
28
|
-
NONE: 0,
|
|
29
|
-
TL: 1 << 0
|
|
30
|
-
});
|
|
31
|
-
constructor(options) {
|
|
32
|
-
this._log = toolkit.logger("Binlog");
|
|
33
|
-
this._options = {
|
|
34
|
-
...options,
|
|
35
|
-
structures: options.structures ? [...options.structures] : []
|
|
36
|
-
};
|
|
37
|
-
this._filePattern = path__default.basename(options.path);
|
|
38
|
-
this._directory = path__default.dirname(options.path);
|
|
39
|
-
this._currentFile = null;
|
|
40
|
-
this._currentFileDescriptor = null;
|
|
41
|
-
this._currentFileSize = 0;
|
|
42
|
-
this._currentFileIndex = 0;
|
|
43
|
-
this._isOpen = false;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Initialize the binlog system, ensuring directory exists and pick most recent binlog file
|
|
47
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
48
|
-
*/
|
|
49
|
-
init() {
|
|
50
|
-
return Promise.resolve().then(() => fs__default.promises.mkdir(this._directory, { recursive: true })).then(() => this.#findLatestBinlogFile());
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Find the latest binlog file to continue writing
|
|
54
|
-
*/
|
|
55
|
-
#findLatestBinlogFile() {
|
|
56
|
-
return Promise.resolve().then(() => fs__default.promises.readdir(this._directory)).then((files) => {
|
|
57
|
-
const fileRegEx = filePatternToRegex(this._filePattern);
|
|
58
|
-
this._currentFileIndex = 0;
|
|
59
|
-
for (const fileName of files) {
|
|
60
|
-
const match = fileName.match(fileRegEx);
|
|
61
|
-
if (match) {
|
|
62
|
-
this._currentFileIndex = Math.max(
|
|
63
|
-
this._currentFileIndex,
|
|
64
|
-
parseInt(match[1], 10)
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Open the binlog for writing
|
|
72
|
-
*/
|
|
73
|
-
open() {
|
|
74
|
-
const filePath = path__default.join(this._directory, this.currentFileName);
|
|
75
|
-
return Promise.resolve().then(() => fs__default.promises.open(filePath, "a+")).then((fileDescription) => {
|
|
76
|
-
this._currentFileDescriptor = fileDescription;
|
|
77
|
-
this._currentFile = filePath;
|
|
78
|
-
return this._currentFileDescriptor.stat();
|
|
79
|
-
}).then((fileStat) => {
|
|
80
|
-
this._currentFileSize = fileStat.size;
|
|
81
|
-
this._isOpen = true;
|
|
82
|
-
if (this._currentFileSize === 0) {
|
|
83
|
-
return this.#writeBinlogHeader();
|
|
84
|
-
} else {
|
|
85
|
-
return this.#checkBinlogHeaders(this._currentFileDescriptor).then(
|
|
86
|
-
toolkit.noop
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Close the current binlog file
|
|
93
|
-
*/
|
|
94
|
-
close() {
|
|
95
|
-
return Promise.resolve().then(() => {
|
|
96
|
-
if (!this._isOpen || !this._currentFileDescriptor) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
return this._currentFileDescriptor.close();
|
|
100
|
-
}).then(() => {
|
|
101
|
-
this._currentFileDescriptor = null;
|
|
102
|
-
this._currentFile = null;
|
|
103
|
-
this._isOpen = false;
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Write a binlog entry
|
|
108
|
-
* @param opcode - Operation code
|
|
109
|
-
* @param data - Data to write
|
|
110
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
111
|
-
*/
|
|
112
|
-
write(opcode, data) {
|
|
113
|
-
let promise = Promise.resolve();
|
|
114
|
-
if (!this._isOpen) {
|
|
115
|
-
promise = promise.then(() => this.open());
|
|
116
|
-
}
|
|
117
|
-
return promise.then(() => {
|
|
118
|
-
if (this._options.rotation && this._currentFileSize >= this._options.maxFileSize) {
|
|
119
|
-
return this.rotate();
|
|
120
|
-
}
|
|
121
|
-
}).then(() => {
|
|
122
|
-
toolkit.assert.ok(this._currentFileDescriptor, "File descriptor is null");
|
|
123
|
-
let flags = this.BINLOG_FLAG.NONE;
|
|
124
|
-
if (!Buffer.isBuffer(data)) {
|
|
125
|
-
if (data instanceof tlPack.Structure) {
|
|
126
|
-
data = tlPack.tlEncode(data);
|
|
127
|
-
flags |= this.BINLOG_FLAG.TL;
|
|
128
|
-
} else {
|
|
129
|
-
data = tlPack.tlEncode(data);
|
|
130
|
-
flags |= this.BINLOG_FLAG.TL;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const dataLength = data.length;
|
|
134
|
-
const totalLength = this.BINLOG_ENTRY_HEADER_SIZE + dataLength;
|
|
135
|
-
const headerBuffer = Buffer.allocUnsafe(this.BINLOG_ENTRY_HEADER_SIZE);
|
|
136
|
-
headerBuffer.writeUInt32LE(opcode, 0);
|
|
137
|
-
headerBuffer.writeUInt32LE(flags, 4);
|
|
138
|
-
headerBuffer.writeUInt32LE(toolkit.timestamp(), 8);
|
|
139
|
-
headerBuffer.writeUInt32LE(dataLength, 12);
|
|
140
|
-
headerBuffer.writeUInt32LE(
|
|
141
|
-
toolkit.crc32(
|
|
142
|
-
Buffer.concat([headerBuffer.subarray(0, 16), data])
|
|
143
|
-
) >>> 0,
|
|
144
|
-
16
|
|
145
|
-
);
|
|
146
|
-
return Promise.resolve().then(() => this._currentFileDescriptor.write(headerBuffer)).then(() => this._currentFileDescriptor.write(data)).then(() => {
|
|
147
|
-
if (this._options.syncWrites) {
|
|
148
|
-
return this._currentFileDescriptor.sync();
|
|
149
|
-
}
|
|
150
|
-
}).then(() => {
|
|
151
|
-
this._currentFileSize += totalLength;
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Rotate the binlog file
|
|
157
|
-
*/
|
|
158
|
-
rotate() {
|
|
159
|
-
return Promise.resolve().then(() => this.close()).then(() => {
|
|
160
|
-
this._currentFileIndex++;
|
|
161
|
-
return this.open();
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Write the binlog header
|
|
166
|
-
*/
|
|
167
|
-
#writeBinlogHeader() {
|
|
168
|
-
toolkit.assert.ok(this._currentFileDescriptor, "File descriptor is null");
|
|
169
|
-
const headerBuffer = Buffer.allocUnsafe(this.BINLOG_HEADER_SIZE);
|
|
170
|
-
headerBuffer.writeUInt32LE(this.BINLOG_MAGIC, 0);
|
|
171
|
-
headerBuffer.writeUInt32LE(this.BINLOG_VERSION, 4);
|
|
172
|
-
headerBuffer.writeUInt32LE(toolkit.timestamp(), 8);
|
|
173
|
-
headerBuffer.writeUInt32LE(0, 12);
|
|
174
|
-
return Promise.resolve().then(() => this._currentFileDescriptor.write(headerBuffer)).then(() => {
|
|
175
|
-
this._currentFileSize += headerBuffer.length;
|
|
176
|
-
if (this._options.syncWrites) {
|
|
177
|
-
return this._currentFileDescriptor.sync();
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Read and parse all entries from a binlog file
|
|
183
|
-
* @param filename - Binlog file to read
|
|
184
|
-
* @param unsafe - Ignore broken binlog records otherwise throws error
|
|
185
|
-
* @returns Array of parsed entries
|
|
186
|
-
*/
|
|
187
|
-
readEntries(filename, unsafe) {
|
|
188
|
-
var filepath = path__default.join(this._directory, filename);
|
|
189
|
-
var fileHandle;
|
|
190
|
-
var entries = [];
|
|
191
|
-
return fs__default.promises.open(filepath, "r").then((_fileHandle) => {
|
|
192
|
-
fileHandle = _fileHandle;
|
|
193
|
-
return this.#checkBinlogHeaders(fileHandle);
|
|
194
|
-
}).then((isValidHeader) => {
|
|
195
|
-
if (!isValidHeader) {
|
|
196
|
-
if (unsafe) {
|
|
197
|
-
this._log.warn("Invalid binlog file format: " + filename);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
return Promise.reject(
|
|
201
|
-
new Error("Invalid binlog file format:\n" + filepath)
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
return fileHandle.stat();
|
|
205
|
-
}).then((stats) => {
|
|
206
|
-
if (!stats) return;
|
|
207
|
-
var contentSize = stats.size - this.BINLOG_HEADER_SIZE;
|
|
208
|
-
var position = this.BINLOG_HEADER_SIZE;
|
|
209
|
-
var headerBuffer = Buffer.allocUnsafe(this.BINLOG_ENTRY_HEADER_SIZE);
|
|
210
|
-
return new Promise((resolve, reject) => {
|
|
211
|
-
var processNextBatch = () => {
|
|
212
|
-
if (position >= contentSize) {
|
|
213
|
-
return resolve();
|
|
214
|
-
}
|
|
215
|
-
fileHandle.read(headerBuffer, 0, this.BINLOG_ENTRY_HEADER_SIZE, position).then(() => {
|
|
216
|
-
var header = this.#readEntryHeader(headerBuffer, position);
|
|
217
|
-
var dataBuffer = Buffer.allocUnsafe(header.dataLength);
|
|
218
|
-
position += this.BINLOG_ENTRY_HEADER_SIZE;
|
|
219
|
-
return fileHandle.read(dataBuffer, 0, header.dataLength, position).then(() => {
|
|
220
|
-
var entry = this.#readEntry(
|
|
221
|
-
headerBuffer,
|
|
222
|
-
header,
|
|
223
|
-
dataBuffer.subarray(0, header.dataLength)
|
|
224
|
-
);
|
|
225
|
-
if (!entry) {
|
|
226
|
-
if (!unsafe) {
|
|
227
|
-
return Promise.reject(
|
|
228
|
-
new Error(
|
|
229
|
-
`CRC mismatch at position ${position - this.BINLOG_ENTRY_HEADER_SIZE}`
|
|
230
|
-
)
|
|
231
|
-
);
|
|
232
|
-
} else {
|
|
233
|
-
this._log.warn(
|
|
234
|
-
`CRC mismatch at position ${position - this.BINLOG_ENTRY_HEADER_SIZE}`
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
entries.push(entry);
|
|
239
|
-
}
|
|
240
|
-
position += header.dataLength;
|
|
241
|
-
}).then(() => processNextBatch()).catch(reject);
|
|
242
|
-
});
|
|
243
|
-
};
|
|
244
|
-
processNextBatch();
|
|
245
|
-
});
|
|
246
|
-
}).then(() => fileHandle?.close()).then(() => entries).catch((error) => {
|
|
247
|
-
return fileHandle.close().then(() => Promise.reject(error));
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
#readEntryHeader(buffer, position) {
|
|
251
|
-
return {
|
|
252
|
-
opcode: buffer.readUInt32LE(0),
|
|
253
|
-
flags: buffer.readUInt32LE(4),
|
|
254
|
-
timestamp: buffer.readUInt32LE(8),
|
|
255
|
-
dataLength: buffer.readUInt32LE(12),
|
|
256
|
-
crc: buffer.readUInt32LE(16),
|
|
257
|
-
position
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
#readEntry(headerBuffer, header, dataBuffer) {
|
|
261
|
-
var crc = toolkit.crc32([headerBuffer.subarray(0, 16), dataBuffer]) >>> 0;
|
|
262
|
-
if (crc !== header.crc) {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
var data;
|
|
266
|
-
if (toolkit.checkBitmask(header.flags, this.BINLOG_FLAG.TL)) {
|
|
267
|
-
data = tlPack.tlDecode(dataBuffer, {
|
|
268
|
-
structures: this._options.structures
|
|
269
|
-
});
|
|
270
|
-
} else {
|
|
271
|
-
data = Buffer.from(dataBuffer);
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
opcode: header.opcode,
|
|
275
|
-
timestamp: header.timestamp,
|
|
276
|
-
data,
|
|
277
|
-
position: header.position
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
#checkBinlogHeaders(fileHandle) {
|
|
281
|
-
var headerBuffer = Buffer.allocUnsafe(this.BINLOG_HEADER_SIZE);
|
|
282
|
-
return Promise.resolve().then(() => fileHandle.read(headerBuffer, 0, this.BINLOG_HEADER_SIZE, 0)).then(() => {
|
|
283
|
-
var magic = headerBuffer.readUInt32LE(0);
|
|
284
|
-
var version = headerBuffer.readUInt32LE(4);
|
|
285
|
-
return magic === this.BINLOG_MAGIC && version === this.BINLOG_VERSION;
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Get the current binlog file index
|
|
290
|
-
*/
|
|
291
|
-
get currentFileIndex() {
|
|
292
|
-
return this._currentFileIndex;
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Get current binlog file name
|
|
296
|
-
*/
|
|
297
|
-
get currentFileName() {
|
|
298
|
-
return this._filePattern.replaceAll(
|
|
299
|
-
"{index}",
|
|
300
|
-
String(this._currentFileIndex)
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Get current binlog directory
|
|
305
|
-
*/
|
|
306
|
-
get directory() {
|
|
307
|
-
return this._directory;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
function filePatternToRegex(value) {
|
|
311
|
-
return new RegExp(value.replaceAll("{index}", "(\\d+)"));
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const DEF_OPTIONS = {
|
|
315
|
-
path: "./binlogs/log-{index}.bin",
|
|
316
|
-
maxFileSize: 104857600,
|
|
317
|
-
rotation: true,
|
|
318
|
-
syncWrites: true
|
|
319
|
-
};
|
|
320
|
-
function createBinlog(options) {
|
|
321
|
-
return new Binlog(toolkit.deepDefaults(options, DEF_OPTIONS));
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
exports.Binlog = Binlog;
|
|
325
|
-
exports.createBinlog = createBinlog;
|
|
326
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/Binlog.ts","../src/index.ts"],"sourcesContent":["import { Structure, tlDecode, tlEncode } from '@andrew_l/tl-pack';\nimport {\n type Logger,\n assert,\n checkBitmask,\n crc32,\n logger,\n noop,\n timestamp,\n} from '@andrew_l/toolkit';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\n/**\n * Options for configuring the KdbBinlog\n */\nexport interface BinlogOptions {\n /**\n * File location to store binlog files\n * @default './binlogs/log-{index}.bin'\n */\n path: string;\n\n /**\n * Maximum size of each binlog file before rotation (in bytes)\n * @default 104857600\n */\n maxFileSize: number;\n\n /**\n * Whether to enable log rotation\n * @default true\n */\n rotation: boolean;\n\n /**\n * Whether to sync writes to disk immediately\n * @default true\n */\n syncWrites: boolean;\n\n structures?: Structure.Constructor[];\n}\n\n/**\n * Represents a single binlog entry\n */\nexport interface BinlogEntry<TData = Buffer> {\n /**\n * Operation code defining the type of operation\n */\n opcode: number;\n\n /**\n * Unix timestamp when the entry was created\n */\n timestamp: number;\n\n /**\n * Binary data of the entry\n */\n data: TData | Buffer;\n\n /**\n * Position in the file where this entry starts\n */\n position: number;\n}\n\ninterface EntryHeader {\n opcode: number;\n flags: number;\n timestamp: number;\n dataLength: number;\n crc: number;\n position: number;\n}\n\n/**\n * TypeScript implementation of binlog system\n * Adapted from https://github.com/vk-com/kphp-kdb/blob/master/binlog/kdb-binlog-common.c\n * @group Main\n */\nexport class Binlog {\n private _options: Required<BinlogOptions>;\n private _filePattern: string;\n private _directory: string;\n private _currentFile: string | null;\n private _currentFileDescriptor: fs.promises.FileHandle | null;\n private _currentFileSize: number;\n private _currentFileIndex: number;\n private _isOpen: boolean;\n private _log: Logger;\n\n private readonly BINLOG_MAGIC: number = 0x4442544b;\n private readonly BINLOG_VERSION: number = 1;\n private readonly BINLOG_HEADER_SIZE: number = 16;\n private readonly BINLOG_ENTRY_HEADER_SIZE: number = 20;\n private readonly BINLOG_FLAG = Object.freeze({\n NONE: 0,\n TL: 1 << 0,\n } as const);\n\n constructor(options: BinlogOptions) {\n this._log = logger('Binlog');\n this._options = {\n ...options,\n structures: options.structures ? [...options.structures] : [],\n };\n this._filePattern = path.basename(options.path);\n this._directory = path.dirname(options.path);\n this._currentFile = null;\n this._currentFileDescriptor = null;\n this._currentFileSize = 0;\n this._currentFileIndex = 0;\n this._isOpen = false;\n }\n\n /**\n * Initialize the binlog system, ensuring directory exists and pick most recent binlog file\n * @returns Promise resolving to true if successful, false otherwise\n */\n public init(): Promise<void> {\n return Promise.resolve()\n .then(() => fs.promises.mkdir(this._directory, { recursive: true }))\n .then(() => this.#findLatestBinlogFile());\n }\n\n /**\n * Find the latest binlog file to continue writing\n */\n #findLatestBinlogFile(): Promise<void> {\n return Promise.resolve()\n .then(() => fs.promises.readdir(this._directory))\n .then(files => {\n const fileRegEx = filePatternToRegex(this._filePattern);\n\n this._currentFileIndex = 0;\n\n for (const fileName of files) {\n const match = fileName.match(fileRegEx);\n\n if (match) {\n this._currentFileIndex = Math.max(\n this._currentFileIndex,\n parseInt(match[1], 10),\n );\n }\n }\n });\n }\n\n /**\n * Open the binlog for writing\n */\n public open(): Promise<void> {\n const filePath = path.join(this._directory, this.currentFileName);\n\n return Promise.resolve()\n .then(() => fs.promises.open(filePath, 'a+'))\n .then(fileDescription => {\n this._currentFileDescriptor = fileDescription;\n this._currentFile = filePath;\n\n return this._currentFileDescriptor.stat();\n })\n .then(fileStat => {\n this._currentFileSize = fileStat.size;\n this._isOpen = true;\n\n // Write the binlog header\n if (this._currentFileSize === 0) {\n return this.#writeBinlogHeader();\n } else {\n return this.#checkBinlogHeaders(this._currentFileDescriptor!).then(\n noop,\n );\n }\n });\n }\n\n /**\n * Close the current binlog file\n */\n public close(): Promise<void> {\n return Promise.resolve()\n .then(() => {\n if (!this._isOpen || !this._currentFileDescriptor) {\n return;\n }\n\n return this._currentFileDescriptor.close();\n })\n .then(() => {\n this._currentFileDescriptor = null;\n this._currentFile = null;\n this._isOpen = false;\n });\n }\n\n /**\n * Write a binlog entry\n * @param opcode - Operation code\n * @param data - Data to write\n * @returns Promise resolving to true if successful, false otherwise\n */\n public write(opcode: number, data: unknown): Promise<void> {\n let promise = Promise.resolve();\n\n if (!this._isOpen) {\n promise = promise.then(() => this.open());\n }\n\n // Check if we need to rotate the file\n return promise\n .then(() => {\n if (\n this._options.rotation &&\n this._currentFileSize >= this._options.maxFileSize\n ) {\n return this.rotate();\n }\n })\n .then(() => {\n assert.ok(this._currentFileDescriptor, 'File descriptor is null');\n\n let flags = this.BINLOG_FLAG.NONE;\n\n if (!Buffer.isBuffer(data)) {\n if (data instanceof Structure) {\n data = tlEncode(data);\n flags |= this.BINLOG_FLAG.TL;\n } else {\n data = tlEncode(data) as Buffer;\n flags |= this.BINLOG_FLAG.TL;\n }\n }\n\n // Create entry header\n const dataLength = (data as Buffer).length;\n const totalLength = this.BINLOG_ENTRY_HEADER_SIZE + dataLength;\n\n const headerBuffer = Buffer.allocUnsafe(this.BINLOG_ENTRY_HEADER_SIZE);\n headerBuffer.writeUInt32LE(opcode, 0);\n headerBuffer.writeUInt32LE(flags, 4);\n headerBuffer.writeUInt32LE(timestamp(), 8);\n headerBuffer.writeUInt32LE(dataLength, 12);\n\n headerBuffer.writeUInt32LE(\n crc32(\n Buffer.concat([headerBuffer.subarray(0, 16), data as Buffer]),\n ) >>> 0,\n 16,\n );\n\n // Write the entry\n return Promise.resolve()\n .then(() => this._currentFileDescriptor!.write(headerBuffer))\n .then(() => this._currentFileDescriptor!.write(data as Buffer))\n .then(() => {\n if (this._options.syncWrites) {\n return this._currentFileDescriptor!.sync();\n }\n })\n .then(() => {\n this._currentFileSize += totalLength;\n });\n });\n }\n\n /**\n * Rotate the binlog file\n */\n public rotate(): Promise<void> {\n return Promise.resolve()\n .then(() => this.close())\n .then(() => {\n this._currentFileIndex++;\n return this.open();\n });\n }\n\n /**\n * Write the binlog header\n */\n #writeBinlogHeader(): Promise<void> {\n assert.ok(this._currentFileDescriptor, 'File descriptor is null');\n\n const headerBuffer = Buffer.allocUnsafe(this.BINLOG_HEADER_SIZE);\n\n headerBuffer.writeUInt32LE(this.BINLOG_MAGIC, 0);\n headerBuffer.writeUInt32LE(this.BINLOG_VERSION, 4);\n headerBuffer.writeUInt32LE(timestamp(), 8);\n headerBuffer.writeUInt32LE(0, 12); // Reserved field\n\n return Promise.resolve()\n .then(() => this._currentFileDescriptor!.write(headerBuffer))\n .then(() => {\n this._currentFileSize += headerBuffer.length;\n\n if (this._options.syncWrites) {\n return this._currentFileDescriptor!.sync();\n }\n });\n }\n\n /**\n * Read and parse all entries from a binlog file\n * @param filename - Binlog file to read\n * @param unsafe - Ignore broken binlog records otherwise throws error\n * @returns Array of parsed entries\n */\n public readEntries<TData = Buffer>(\n filename: string,\n unsafe?: boolean,\n ): Promise<BinlogEntry<TData>[]> {\n var filepath = path.join(this._directory, filename);\n var fileHandle: fs.promises.FileHandle;\n var entries: BinlogEntry<TData>[] = [];\n\n return fs.promises\n .open(filepath, 'r')\n .then(_fileHandle => {\n fileHandle = _fileHandle;\n return this.#checkBinlogHeaders(fileHandle);\n })\n .then(isValidHeader => {\n if (!isValidHeader) {\n if (unsafe) {\n this._log.warn('Invalid binlog file format: ' + filename);\n return;\n }\n return Promise.reject(\n new Error('Invalid binlog file format:\\n' + filepath),\n );\n }\n\n return fileHandle.stat();\n })\n .then(stats => {\n if (!stats) return;\n\n var contentSize = stats.size - this.BINLOG_HEADER_SIZE;\n var position = this.BINLOG_HEADER_SIZE;\n var headerBuffer = Buffer.allocUnsafe(this.BINLOG_ENTRY_HEADER_SIZE);\n\n return new Promise<void>((resolve, reject) => {\n var processNextBatch = () => {\n if (position >= contentSize) {\n return resolve();\n }\n\n fileHandle\n .read(headerBuffer, 0, this.BINLOG_ENTRY_HEADER_SIZE, position)\n .then(() => {\n var header = this.#readEntryHeader(headerBuffer, position);\n var dataBuffer = Buffer.allocUnsafe(header.dataLength);\n\n position += this.BINLOG_ENTRY_HEADER_SIZE;\n\n return fileHandle\n .read(dataBuffer, 0, header.dataLength, position)\n .then(() => {\n var entry = this.#readEntry(\n headerBuffer,\n header,\n dataBuffer.subarray(0, header.dataLength),\n );\n\n if (!entry) {\n if (!unsafe) {\n return Promise.reject(\n new Error(\n `CRC mismatch at position ${position - this.BINLOG_ENTRY_HEADER_SIZE}`,\n ),\n );\n } else {\n this._log.warn(\n `CRC mismatch at position ${position - this.BINLOG_ENTRY_HEADER_SIZE}`,\n );\n }\n } else {\n entries.push(entry);\n }\n\n position += header.dataLength;\n })\n .then(() => processNextBatch())\n .catch(reject);\n });\n };\n\n processNextBatch();\n });\n })\n .then(() => fileHandle?.close())\n .then(() => entries)\n .catch(error => {\n return fileHandle.close().then(() => Promise.reject(error));\n });\n }\n\n #readEntryHeader(buffer: Buffer, position: number): EntryHeader {\n return {\n opcode: buffer.readUInt32LE(0),\n flags: buffer.readUInt32LE(4),\n timestamp: buffer.readUInt32LE(8),\n dataLength: buffer.readUInt32LE(12),\n crc: buffer.readUInt32LE(16),\n position,\n };\n }\n\n #readEntry(\n headerBuffer: Buffer,\n header: EntryHeader,\n dataBuffer: Buffer,\n ): BinlogEntry<any> | null {\n // Verify CRC\n var crc = crc32([headerBuffer.subarray(0, 16), dataBuffer]) >>> 0;\n\n if (crc !== header.crc) {\n return null;\n }\n\n var data: any;\n\n if (checkBitmask(header.flags, this.BINLOG_FLAG.TL)) {\n data = tlDecode(dataBuffer, {\n structures: this._options.structures,\n });\n } else {\n // Make copy\n data = Buffer.from(dataBuffer);\n }\n\n return {\n opcode: header.opcode,\n timestamp: header.timestamp,\n data: data,\n position: header.position,\n };\n }\n\n #checkBinlogHeaders(fileHandle: fs.promises.FileHandle): Promise<boolean> {\n var headerBuffer = Buffer.allocUnsafe(this.BINLOG_HEADER_SIZE);\n\n return Promise.resolve()\n .then(() => fileHandle.read(headerBuffer, 0, this.BINLOG_HEADER_SIZE, 0))\n .then(() => {\n var magic = headerBuffer.readUInt32LE(0);\n var version = headerBuffer.readUInt32LE(4);\n\n return magic === this.BINLOG_MAGIC && version === this.BINLOG_VERSION;\n });\n }\n\n /**\n * Get the current binlog file index\n */\n get currentFileIndex(): number {\n return this._currentFileIndex;\n }\n\n /**\n * Get current binlog file name\n */\n get currentFileName(): string {\n return this._filePattern.replaceAll(\n '{index}',\n String(this._currentFileIndex),\n );\n }\n\n /**\n * Get current binlog directory\n */\n get directory(): string {\n return this._directory;\n }\n}\n\nfunction filePatternToRegex(value: string): RegExp {\n return new RegExp(value.replaceAll('{index}', '(\\\\d+)'));\n}\n","import { deepDefaults } from '@andrew_l/toolkit';\nimport { Binlog, type BinlogOptions } from './Binlog.js';\n\nexport * from './Binlog.js';\n\nconst DEF_OPTIONS: BinlogOptions = {\n path: './binlogs/log-{index}.bin',\n maxFileSize: 104857600,\n rotation: true,\n syncWrites: true,\n};\n\n/**\n * Create binlog instance\n * @group Main\n */\nexport function createBinlog(options: Partial<BinlogOptions>): Binlog {\n return new Binlog(deepDefaults(options, DEF_OPTIONS));\n}\n"],"names":["logger","path","fs","noop","assert","Structure","tlEncode","timestamp","crc32","checkBitmask","tlDecode","deepDefaults"],"mappings":"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"}
|
package/dist/index.d.cts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Structure } from '@andrew_l/tl-pack';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Options for configuring the KdbBinlog
|
|
5
|
-
*/
|
|
6
|
-
interface BinlogOptions {
|
|
7
|
-
/**
|
|
8
|
-
* File location to store binlog files
|
|
9
|
-
* @default './binlogs/log-{index}.bin'
|
|
10
|
-
*/
|
|
11
|
-
path: string;
|
|
12
|
-
/**
|
|
13
|
-
* Maximum size of each binlog file before rotation (in bytes)
|
|
14
|
-
* @default 104857600
|
|
15
|
-
*/
|
|
16
|
-
maxFileSize: number;
|
|
17
|
-
/**
|
|
18
|
-
* Whether to enable log rotation
|
|
19
|
-
* @default true
|
|
20
|
-
*/
|
|
21
|
-
rotation: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Whether to sync writes to disk immediately
|
|
24
|
-
* @default true
|
|
25
|
-
*/
|
|
26
|
-
syncWrites: boolean;
|
|
27
|
-
structures?: Structure.Constructor[];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Represents a single binlog entry
|
|
31
|
-
*/
|
|
32
|
-
interface BinlogEntry<TData = Buffer> {
|
|
33
|
-
/**
|
|
34
|
-
* Operation code defining the type of operation
|
|
35
|
-
*/
|
|
36
|
-
opcode: number;
|
|
37
|
-
/**
|
|
38
|
-
* Unix timestamp when the entry was created
|
|
39
|
-
*/
|
|
40
|
-
timestamp: number;
|
|
41
|
-
/**
|
|
42
|
-
* Binary data of the entry
|
|
43
|
-
*/
|
|
44
|
-
data: TData | Buffer;
|
|
45
|
-
/**
|
|
46
|
-
* Position in the file where this entry starts
|
|
47
|
-
*/
|
|
48
|
-
position: number;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* TypeScript implementation of binlog system
|
|
52
|
-
* Adapted from https://github.com/vk-com/kphp-kdb/blob/master/binlog/kdb-binlog-common.c
|
|
53
|
-
* @group Main
|
|
54
|
-
*/
|
|
55
|
-
declare class Binlog {
|
|
56
|
-
#private;
|
|
57
|
-
private _options;
|
|
58
|
-
private _filePattern;
|
|
59
|
-
private _directory;
|
|
60
|
-
private _currentFile;
|
|
61
|
-
private _currentFileDescriptor;
|
|
62
|
-
private _currentFileSize;
|
|
63
|
-
private _currentFileIndex;
|
|
64
|
-
private _isOpen;
|
|
65
|
-
private _log;
|
|
66
|
-
private readonly BINLOG_MAGIC;
|
|
67
|
-
private readonly BINLOG_VERSION;
|
|
68
|
-
private readonly BINLOG_HEADER_SIZE;
|
|
69
|
-
private readonly BINLOG_ENTRY_HEADER_SIZE;
|
|
70
|
-
private readonly BINLOG_FLAG;
|
|
71
|
-
constructor(options: BinlogOptions);
|
|
72
|
-
/**
|
|
73
|
-
* Initialize the binlog system, ensuring directory exists and pick most recent binlog file
|
|
74
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
75
|
-
*/
|
|
76
|
-
init(): Promise<void>;
|
|
77
|
-
/**
|
|
78
|
-
* Open the binlog for writing
|
|
79
|
-
*/
|
|
80
|
-
open(): Promise<void>;
|
|
81
|
-
/**
|
|
82
|
-
* Close the current binlog file
|
|
83
|
-
*/
|
|
84
|
-
close(): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Write a binlog entry
|
|
87
|
-
* @param opcode - Operation code
|
|
88
|
-
* @param data - Data to write
|
|
89
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
90
|
-
*/
|
|
91
|
-
write(opcode: number, data: unknown): Promise<void>;
|
|
92
|
-
/**
|
|
93
|
-
* Rotate the binlog file
|
|
94
|
-
*/
|
|
95
|
-
rotate(): Promise<void>;
|
|
96
|
-
/**
|
|
97
|
-
* Read and parse all entries from a binlog file
|
|
98
|
-
* @param filename - Binlog file to read
|
|
99
|
-
* @param unsafe - Ignore broken binlog records otherwise throws error
|
|
100
|
-
* @returns Array of parsed entries
|
|
101
|
-
*/
|
|
102
|
-
readEntries<TData = Buffer>(filename: string, unsafe?: boolean): Promise<BinlogEntry<TData>[]>;
|
|
103
|
-
/**
|
|
104
|
-
* Get the current binlog file index
|
|
105
|
-
*/
|
|
106
|
-
get currentFileIndex(): number;
|
|
107
|
-
/**
|
|
108
|
-
* Get current binlog file name
|
|
109
|
-
*/
|
|
110
|
-
get currentFileName(): string;
|
|
111
|
-
/**
|
|
112
|
-
* Get current binlog directory
|
|
113
|
-
*/
|
|
114
|
-
get directory(): string;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create binlog instance
|
|
119
|
-
* @group Main
|
|
120
|
-
*/
|
|
121
|
-
declare function createBinlog(options: Partial<BinlogOptions>): Binlog;
|
|
122
|
-
|
|
123
|
-
export { Binlog, type BinlogEntry, type BinlogOptions, createBinlog };
|
package/dist/index.d.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Structure } from '@andrew_l/tl-pack';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Options for configuring the KdbBinlog
|
|
5
|
-
*/
|
|
6
|
-
interface BinlogOptions {
|
|
7
|
-
/**
|
|
8
|
-
* File location to store binlog files
|
|
9
|
-
* @default './binlogs/log-{index}.bin'
|
|
10
|
-
*/
|
|
11
|
-
path: string;
|
|
12
|
-
/**
|
|
13
|
-
* Maximum size of each binlog file before rotation (in bytes)
|
|
14
|
-
* @default 104857600
|
|
15
|
-
*/
|
|
16
|
-
maxFileSize: number;
|
|
17
|
-
/**
|
|
18
|
-
* Whether to enable log rotation
|
|
19
|
-
* @default true
|
|
20
|
-
*/
|
|
21
|
-
rotation: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Whether to sync writes to disk immediately
|
|
24
|
-
* @default true
|
|
25
|
-
*/
|
|
26
|
-
syncWrites: boolean;
|
|
27
|
-
structures?: Structure.Constructor[];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Represents a single binlog entry
|
|
31
|
-
*/
|
|
32
|
-
interface BinlogEntry<TData = Buffer> {
|
|
33
|
-
/**
|
|
34
|
-
* Operation code defining the type of operation
|
|
35
|
-
*/
|
|
36
|
-
opcode: number;
|
|
37
|
-
/**
|
|
38
|
-
* Unix timestamp when the entry was created
|
|
39
|
-
*/
|
|
40
|
-
timestamp: number;
|
|
41
|
-
/**
|
|
42
|
-
* Binary data of the entry
|
|
43
|
-
*/
|
|
44
|
-
data: TData | Buffer;
|
|
45
|
-
/**
|
|
46
|
-
* Position in the file where this entry starts
|
|
47
|
-
*/
|
|
48
|
-
position: number;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* TypeScript implementation of binlog system
|
|
52
|
-
* Adapted from https://github.com/vk-com/kphp-kdb/blob/master/binlog/kdb-binlog-common.c
|
|
53
|
-
* @group Main
|
|
54
|
-
*/
|
|
55
|
-
declare class Binlog {
|
|
56
|
-
#private;
|
|
57
|
-
private _options;
|
|
58
|
-
private _filePattern;
|
|
59
|
-
private _directory;
|
|
60
|
-
private _currentFile;
|
|
61
|
-
private _currentFileDescriptor;
|
|
62
|
-
private _currentFileSize;
|
|
63
|
-
private _currentFileIndex;
|
|
64
|
-
private _isOpen;
|
|
65
|
-
private _log;
|
|
66
|
-
private readonly BINLOG_MAGIC;
|
|
67
|
-
private readonly BINLOG_VERSION;
|
|
68
|
-
private readonly BINLOG_HEADER_SIZE;
|
|
69
|
-
private readonly BINLOG_ENTRY_HEADER_SIZE;
|
|
70
|
-
private readonly BINLOG_FLAG;
|
|
71
|
-
constructor(options: BinlogOptions);
|
|
72
|
-
/**
|
|
73
|
-
* Initialize the binlog system, ensuring directory exists and pick most recent binlog file
|
|
74
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
75
|
-
*/
|
|
76
|
-
init(): Promise<void>;
|
|
77
|
-
/**
|
|
78
|
-
* Open the binlog for writing
|
|
79
|
-
*/
|
|
80
|
-
open(): Promise<void>;
|
|
81
|
-
/**
|
|
82
|
-
* Close the current binlog file
|
|
83
|
-
*/
|
|
84
|
-
close(): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Write a binlog entry
|
|
87
|
-
* @param opcode - Operation code
|
|
88
|
-
* @param data - Data to write
|
|
89
|
-
* @returns Promise resolving to true if successful, false otherwise
|
|
90
|
-
*/
|
|
91
|
-
write(opcode: number, data: unknown): Promise<void>;
|
|
92
|
-
/**
|
|
93
|
-
* Rotate the binlog file
|
|
94
|
-
*/
|
|
95
|
-
rotate(): Promise<void>;
|
|
96
|
-
/**
|
|
97
|
-
* Read and parse all entries from a binlog file
|
|
98
|
-
* @param filename - Binlog file to read
|
|
99
|
-
* @param unsafe - Ignore broken binlog records otherwise throws error
|
|
100
|
-
* @returns Array of parsed entries
|
|
101
|
-
*/
|
|
102
|
-
readEntries<TData = Buffer>(filename: string, unsafe?: boolean): Promise<BinlogEntry<TData>[]>;
|
|
103
|
-
/**
|
|
104
|
-
* Get the current binlog file index
|
|
105
|
-
*/
|
|
106
|
-
get currentFileIndex(): number;
|
|
107
|
-
/**
|
|
108
|
-
* Get current binlog file name
|
|
109
|
-
*/
|
|
110
|
-
get currentFileName(): string;
|
|
111
|
-
/**
|
|
112
|
-
* Get current binlog directory
|
|
113
|
-
*/
|
|
114
|
-
get directory(): string;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create binlog instance
|
|
119
|
-
* @group Main
|
|
120
|
-
*/
|
|
121
|
-
declare function createBinlog(options: Partial<BinlogOptions>): Binlog;
|
|
122
|
-
|
|
123
|
-
export { Binlog, type BinlogEntry, type BinlogOptions, createBinlog };
|