UNPKG

@mieweb/wikigdrive

Version:

Google Drive to MarkDown synchronization

123 lines (93 loc) 3.27 kB
import path from 'node:path'; import fs, {ReadStream} from 'node:fs'; import os from 'node:os'; import {StreamOptions} from 'node:stream'; import Transport, {TransportStreamOptions} from 'winston-transport'; import {JobLogFileProcessor} from './JobLogFileProcessor.ts'; interface JobLogStreamOptions extends TransportStreamOptions { file_options?: StreamOptions<ReadStream>; zippedArchive?: boolean; extension?: string; dirname: string; filename: string; eol?: string; } function isValidFileName(filename) { // eslint-disable-next-line no-control-regex return !/["<>|:*?\\/\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]/g.test(filename); } function isValidDirName(dirname) { // eslint-disable-next-line no-control-regex return !/["<>|\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]/g.test(dirname); } const loggerDefaults: { file_options: any, eol: string } = { file_options: { flags: 'a' }, eol: os.EOL, }; export class JobLogFile extends Transport { name = 'jobLogFile'; private options: JobLogStreamOptions; private dirname: string; private filename: string; constructor(options: JobLogStreamOptions) { super(options); this.options = { ...loggerDefaults, ...options }; this.filename = options.filename; this.dirname = options.dirname; if (!isValidFileName(this.filename) || !isValidDirName(this.dirname)) { throw new Error('Your path or filename contain an invalid character.'); } } log(info, callback) { if (info?.jobId) { const logStream = this.getLogStream(info.driveId, info.jobId); logStream.write(JSON.stringify(info) + this.options.eol); logStream.close(); this.emit('logged', info); } if (callback) { callback(null, true); } } async close() { this.emit('finish'); } getLogStream(driveId: string, jobId: string) { driveId = driveId || ''; const dirname = this.dirname .replace('%driveId%', driveId) .replace('%jobId%', jobId) .replace('//', '/'); fs.mkdirSync(dirname, { recursive: true }); const filename = path.join(dirname, this.filename) .replace(/%JOB_ID%/g, jobId); return fs.createWriteStream(filename, this.options.file_options); } async query(options, callback) { if (!this.filename) { throw new Error('query() may not be used when initializing with a stream'); } options = options || {}; if (!options.jobId || !options.driveId) { callback(null, []); return []; } options.order = options.order || 'desc'; const dirname = this.dirname .replace('%driveId%', options.driveId) .replace('%jobId%', options.jobId) .replace('//', '/'); fs.mkdirSync(dirname, { recursive: true }); const filename = path.join(dirname, this.filename) .replace(/%JOB_ID%/g, options.jobId); try { const processor = new JobLogFileProcessor(filename, options); const results = await processor.query(); callback(null, results); return results; } catch (err) { callback(err); throw err; } } }