change files structure
This commit is contained in:
parent
3210e72b22
commit
1ed6449ac6
30 changed files with 7 additions and 7 deletions
82
server/src/core/services/executor_program_service.ts
Normal file
82
server/src/core/services/executor_program_service.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import cluster, { Worker } from "node:cluster";
|
||||
import { TypedEvent } from "../helper/typed_event.js";
|
||||
import { Result } from "../helper/result.js";
|
||||
import { WorkerDataExec, WorkerType } from "../helper/worker_computed.js";
|
||||
import { delay } from "../helper/delay.js";
|
||||
import { ExecutorResult } from "../model/executor_result.js";
|
||||
import { EXEC_TYPE, ExecError, SpawnError } from "../model/exec_error_model.js";
|
||||
|
||||
abstract class IExecutorProgramService {
|
||||
abstract execPath: string;
|
||||
}
|
||||
|
||||
export class ExecutorProgramService
|
||||
extends TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
|
||||
implements IExecutorProgramService
|
||||
{
|
||||
static event = "ExecutorProgramService";
|
||||
execPath: string;
|
||||
worker: Worker | any;
|
||||
maxTime: null | number = null;
|
||||
|
||||
constructor(execPath: string, maxTime: number | null = null) {
|
||||
super();
|
||||
this.execPath = execPath;
|
||||
this.maxTime = maxTime;
|
||||
}
|
||||
private async workerExecuted(command: string, workerType: WorkerType,args:Array<string> | undefined = undefined) {
|
||||
cluster.setupPrimary({
|
||||
exec: "./src/core/helper/worker_computed.js",
|
||||
});
|
||||
|
||||
const worker = cluster.fork();
|
||||
|
||||
await delay(300);
|
||||
|
||||
this.worker = worker;
|
||||
|
||||
const workerDataExec: WorkerDataExec = {
|
||||
command: command,
|
||||
execPath: this.execPath,
|
||||
type: workerType,
|
||||
cliArgs:args
|
||||
};
|
||||
worker.send(workerDataExec);
|
||||
worker.on("message", (e) => {
|
||||
const spawnError = SpawnError.isError(e);
|
||||
if (spawnError instanceof SpawnError) {
|
||||
this.emit(Result.error(spawnError));
|
||||
}
|
||||
const executorResult = ExecutorResult.isExecutorResult(e);
|
||||
if (executorResult instanceof ExecutorResult) {
|
||||
this.emit(Result.ok(executorResult));
|
||||
}
|
||||
|
||||
const execError = ExecError.isExecError(e);
|
||||
if (execError instanceof ExecError) {
|
||||
this.emit(Result.error(execError));
|
||||
}
|
||||
});
|
||||
if (this.maxTime != null) {
|
||||
setTimeout(() => {
|
||||
this.worker.kill();
|
||||
this.emit(
|
||||
Result.error(
|
||||
WorkerType.EXEC
|
||||
? new ExecError(command, "timeout err")
|
||||
: new SpawnError(command, "timeout err")
|
||||
)
|
||||
);
|
||||
}, this.maxTime!);
|
||||
}
|
||||
}
|
||||
public async call(type: EXEC_TYPE, command: string, args:Array<string> | undefined = undefined): Promise<void> {
|
||||
if (type == EXEC_TYPE.EXEC) {
|
||||
this.workerExecuted(command, WorkerType.EXEC);
|
||||
|
||||
return;
|
||||
}
|
||||
this.workerExecuted(command, WorkerType.SPAWN,args);
|
||||
return;
|
||||
}
|
||||
}
|
122
server/src/core/services/files_change_notifier_service.ts
Normal file
122
server/src/core/services/files_change_notifier_service.ts
Normal file
|
@ -0,0 +1,122 @@
|
|||
import * as fs from "fs";
|
||||
import { resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { createHash } from "node:crypto";
|
||||
import "reflect-metadata";
|
||||
import { BinaryLike } from "crypto";
|
||||
import { EventsFileChanger, MetaDataFileManagerModel } from "../model/meta_data_file_manager_model.js";
|
||||
import { Result } from "../helper/result.js";
|
||||
import { TypedEvent } from "../helper/typed_event.js";
|
||||
|
||||
const readFileAsync = promisify(fs.readFile);
|
||||
const readdir = promisify(fs.readdir);
|
||||
const stat = promisify(fs.stat);
|
||||
|
||||
function md5(content: Buffer | BinaryLike) {
|
||||
return createHash("md5").update(content).digest("hex");
|
||||
}
|
||||
|
||||
interface IHashesCache {
|
||||
[key: string]: MetaDataFileManagerModel;
|
||||
}
|
||||
export abstract class IFilesChangeNotifierService {
|
||||
abstract directory: string;
|
||||
}
|
||||
export class FilesChangeNotifierService
|
||||
extends TypedEvent<Result<Error, IHashesCache>>
|
||||
implements IFilesChangeNotifierService
|
||||
{
|
||||
watcher!: fs.FSWatcher;
|
||||
directory: string;
|
||||
constructor(directory: string) {
|
||||
super();
|
||||
this.directory = directory;
|
||||
this.init();
|
||||
}
|
||||
hashes: IHashesCache = {};
|
||||
async init() {
|
||||
const files = await this.getFiles(this.directory);
|
||||
for (const file of files) {
|
||||
await this.setHash(file);
|
||||
}
|
||||
}
|
||||
async setHash(file: string) {
|
||||
const data = await readFileAsync(file);
|
||||
const md5Current = md5(data);
|
||||
|
||||
this.hashes[file] = new MetaDataFileManagerModel(
|
||||
file,
|
||||
md5Current,
|
||||
EventsFileChanger.static
|
||||
);
|
||||
this.emit(Result.ok(this.hashes));
|
||||
}
|
||||
async getFiles(dir: string): Promise<string | any[]> {
|
||||
const subdirs = await readdir(dir);
|
||||
const files = await Promise.all(
|
||||
subdirs.map(async (subdir) => {
|
||||
const res = resolve(dir, subdir);
|
||||
return (await stat(res)).isDirectory() ? this.getFiles(res) : res;
|
||||
})
|
||||
);
|
||||
return files.reduce((a: string | any[], f: any) => a.concat(f), []);
|
||||
}
|
||||
|
||||
public call = (): Result<Error, boolean> => {
|
||||
try {
|
||||
let md5Previous: string | null = null;
|
||||
let fsWait: NodeJS.Timeout | boolean = false;
|
||||
const watcher = fs.watch(
|
||||
this.directory,
|
||||
{ recursive: true },
|
||||
async (_e, filename) => {
|
||||
const filePath = this.directory + filename;
|
||||
if (filename) {
|
||||
if (fsWait) return;
|
||||
fsWait = setTimeout(() => {
|
||||
fsWait = false;
|
||||
}, 100);
|
||||
try {
|
||||
const file = await readFileAsync(filePath);
|
||||
const md5Current = md5(file);
|
||||
|
||||
if (md5Current === md5Previous) {
|
||||
return;
|
||||
}
|
||||
const status = this.hashes[filePath] === undefined
|
||||
? EventsFileChanger.create
|
||||
: EventsFileChanger.update;
|
||||
|
||||
const model = new MetaDataFileManagerModel(
|
||||
filePath,
|
||||
md5Current,
|
||||
status
|
||||
);
|
||||
this.hashes[filePath] = model;
|
||||
md5Previous = md5Current;
|
||||
this.emit(Result.ok(this.hashes));
|
||||
} catch (error) {
|
||||
this.emit(Result.ok(this.hashes));
|
||||
this.hashes[filePath] = new MetaDataFileManagerModel(
|
||||
filePath,
|
||||
null,
|
||||
EventsFileChanger.delete
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
this.watcher = watcher;
|
||||
return Result.ok(true);
|
||||
} catch (error) {
|
||||
return Result.error(error as Error);
|
||||
}
|
||||
};
|
||||
cancel() {
|
||||
if (this.watcher != undefined) {
|
||||
this.watcher.close();
|
||||
this.listenersOncer = []
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue