feat(daemon): Reorganize and refactor core into client/daemon/shared modules; add IPC protocol and tests

This commit is contained in:
2025-08-28 18:17:41 +00:00
parent 1516185c4d
commit ece16b75e2
23 changed files with 83 additions and 32 deletions

View File

@@ -1,5 +1,17 @@
# Changelog # Changelog
## 2025-08-28 - 3.1.0 - feat(daemon)
Reorganize and refactor core into client/daemon/shared modules; add IPC protocol and tests
- Reorganized core code: split daemon and client logic into ts/daemon and ts/client directories
- Moved process management into ProcessManager, ProcessMonitor and ProcessWrapper under ts/daemon
- Added a dedicated IPC client and service manager under ts/client (tspm.ipcclient, tspm.servicemanager)
- Introduced shared protocol and error handling: ts/shared/protocol/ipc.types.ts, protocol.version.ts and ts/shared/common/utils.errorhandler.ts
- Updated CLI to import Logger from shared/common utils and updated related helpers
- Added daemon entrypoint at ts/daemon/index.ts and reorganized daemon startup/shutdown/heartbeat handling
- Added test assets (test/testassets/simple-test.ts, simple-script2.ts) and expanded test files under test/
- Removed legacy top-level class files (classes.*) in favor of the new structured layout
## 2025-08-28 - 3.0.2 - fix(daemon) ## 2025-08-28 - 3.0.2 - fix(daemon)
Ensure TSPM runtime dir exists and improve daemon startup/debug output Ensure TSPM runtime dir exists and improve daemon startup/debug output

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tspm', name: '@git.zone/tspm',
version: '3.0.2', version: '3.1.0',
description: 'a no fuzz process manager' description: 'a no fuzz process manager'
} }

View File

@@ -1,5 +1,5 @@
import * as plugins from '../../../plugins.js'; import * as plugins from '../../../plugins.js';
import { tspmIpcClient } from '../../../classes.ipcclient.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
import type { CliArguments } from '../../types.js'; import type { CliArguments } from '../../types.js';
import { registerIpcCommand } from '../../registration/index.js'; import { registerIpcCommand } from '../../registration/index.js';

View File

@@ -1,5 +1,5 @@
import * as plugins from '../../../plugins.js'; import * as plugins from '../../../plugins.js';
import { tspmIpcClient } from '../../../classes.ipcclient.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
import type { CliArguments } from '../../types.js'; import type { CliArguments } from '../../types.js';
import { registerIpcCommand } from '../../registration/index.js'; import { registerIpcCommand } from '../../registration/index.js';
import { pad } from '../../helpers/formatting.js'; import { pad } from '../../helpers/formatting.js';

View File

@@ -1,5 +1,5 @@
import * as plugins from '../../../plugins.js'; import * as plugins from '../../../plugins.js';
import { tspmIpcClient } from '../../../classes.ipcclient.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
import type { CliArguments } from '../../types.js'; import type { CliArguments } from '../../types.js';
import { registerIpcCommand } from '../../registration/index.js'; import { registerIpcCommand } from '../../registration/index.js';

View File

@@ -1,5 +1,5 @@
import * as plugins from '../../../plugins.js'; import * as plugins from '../../../plugins.js';
import { tspmIpcClient } from '../../../classes.ipcclient.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
import type { IProcessConfig } from '../../../classes.tspm.js'; import type { IProcessConfig } from '../../../classes.tspm.js';
import type { CliArguments } from '../../types.js'; import type { CliArguments } from '../../types.js';
import { parseMemoryString, formatMemory } from '../../helpers/memory.js'; import { parseMemoryString, formatMemory } from '../../helpers/memory.js';

View File

@@ -1,5 +1,5 @@
import * as plugins from '../../../plugins.js'; import * as plugins from '../../../plugins.js';
import { tspmIpcClient } from '../../../classes.ipcclient.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
import type { CliArguments } from '../../types.js'; import type { CliArguments } from '../../types.js';
import { registerIpcCommand } from '../../registration/index.js'; import { registerIpcCommand } from '../../registration/index.js';

View File

@@ -1,6 +1,6 @@
import * as plugins from '../plugins.js'; import * as plugins from '../plugins.js';
import * as paths from '../paths.js'; import * as paths from '../paths.js';
import { Logger, LogLevel } from '../utils.errorhandler.js'; import { Logger, LogLevel } from '../shared/common/utils.errorhandler.js';
// Import command registration functions // Import command registration functions
import { registerDefaultCommand } from './commands/default.js'; import { registerDefaultCommand } from './commands/default.js';

8
ts/client/index.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* Client-side exports for TSPM
* These are the only components that client applications should use
* They only communicate with the daemon via IPC, never directly manage processes
*/
export * from './tspm.ipcclient.js';
export * from './tspm.servicemanager.js';

View File

@@ -1,11 +1,11 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import * as paths from './paths.js'; import * as paths from '../paths.js';
import type { import type {
IpcMethodMap, IpcMethodMap,
RequestForMethod, RequestForMethod,
ResponseForMethod, ResponseForMethod,
} from './ipc.types.js'; } from '../shared/protocol/ipc.types.js';
/** /**
* IPC client for communicating with the TSPM daemon * IPC client for communicating with the TSPM daemon

View File

@@ -1,5 +1,5 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import * as paths from './paths.js'; import * as paths from '../paths.js';
/** /**
* Manages TSPM daemon as a systemd service via smartdaemon * Manages TSPM daemon as a systemd service via smartdaemon

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import { startDaemon } from './classes.daemon.js'; import { startDaemon } from './tspm.daemon.js';
// Start the daemon // Start the daemon
startDaemon().catch((error) => { startDaemon().catch((error) => {

View File

@@ -1,19 +1,19 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import * as paths from './paths.js'; import * as paths from '../paths.js';
import { import {
ProcessMonitor, ProcessMonitor,
type IMonitorConfig, type IMonitorConfig,
} from './classes.processmonitor.js'; } from './processmonitor.js';
import { type IProcessLog } from './classes.processwrapper.js'; import { type IProcessLog } from './processwrapper.js';
import { TspmConfig } from './classes.config.js'; import { TspmConfig } from './tspm.config.js';
import { import {
Logger, Logger,
ProcessError, ProcessError,
ConfigError, ConfigError,
ValidationError, ValidationError,
handleError, handleError,
} from './utils.errorhandler.js'; } from '../shared/common/utils.errorhandler.js';
export interface IProcessConfig extends IMonitorConfig { export interface IProcessConfig extends IMonitorConfig {
id: string; // Unique identifier for the process id: string; // Unique identifier for the process
@@ -32,7 +32,7 @@ export interface IProcessInfo {
restarts: number; restarts: number;
} }
export class Tspm extends EventEmitter { export class ProcessManager extends EventEmitter {
public processes: Map<string, ProcessMonitor> = new Map(); public processes: Map<string, ProcessMonitor> = new Map();
public processConfigs: Map<string, IProcessConfig> = new Map(); public processConfigs: Map<string, IProcessConfig> = new Map();
public processInfo: Map<string, IProcessInfo> = new Map(); public processInfo: Map<string, IProcessInfo> = new Map();

View File

@@ -1,7 +1,7 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { ProcessWrapper, type IProcessLog } from './classes.processwrapper.js'; import { ProcessWrapper, type IProcessLog } from './processwrapper.js';
import { Logger, ProcessError, handleError } from './utils.errorhandler.js'; import { Logger, ProcessError, handleError } from '../shared/common/utils.errorhandler.js';
export interface IMonitorConfig { export interface IMonitorConfig {
name?: string; // Optional name to identify the instance name?: string; // Optional name to identify the instance

View File

@@ -1,6 +1,6 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { Logger, ProcessError, handleError } from './utils.errorhandler.js'; import { Logger, ProcessError, handleError } from '../shared/common/utils.errorhandler.js';
export interface IProcessWrapperOptions { export interface IProcessWrapperOptions {
command: string; command: string;

View File

@@ -1,4 +1,4 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
export class TspmConfig { export class TspmConfig {
public npmextraInstance = new plugins.npmextra.KeyValueStore({ public npmextraInstance = new plugins.npmextra.KeyValueStore({

View File

@@ -1,19 +1,19 @@
import * as plugins from './plugins.js'; import * as plugins from '../plugins.js';
import * as paths from './paths.js'; import * as paths from '../paths.js';
import { Tspm } from './classes.tspm.js'; import { ProcessManager } from './processmanager.js';
import type { import type {
IpcMethodMap, IpcMethodMap,
RequestForMethod, RequestForMethod,
ResponseForMethod, ResponseForMethod,
DaemonStatusResponse, DaemonStatusResponse,
HeartbeatResponse, HeartbeatResponse,
} from './ipc.types.js'; } from '../shared/protocol/ipc.types.js';
/** /**
* Central daemon server that manages all TSPM processes * Central daemon server that manages all TSPM processes
*/ */
export class TspmDaemon { export class TspmDaemon {
private tspmInstance: Tspm; private tspmInstance: ProcessManager;
private ipcServer: plugins.smartipc.IpcServer; private ipcServer: plugins.smartipc.IpcServer;
private startTime: number; private startTime: number;
private isShuttingDown: boolean = false; private isShuttingDown: boolean = false;
@@ -22,7 +22,7 @@ export class TspmDaemon {
private daemonPidFile: string; private daemonPidFile: string;
constructor() { constructor() {
this.tspmInstance = new Tspm(); this.tspmInstance = new ProcessManager();
this.socketPath = plugins.path.join(paths.tspmDir, 'tspm.sock'); this.socketPath = plugins.path.join(paths.tspmDir, 'tspm.sock');
this.daemonPidFile = plugins.path.join(paths.tspmDir, 'daemon.pid'); this.daemonPidFile = plugins.path.join(paths.tspmDir, 'daemon.pid');
this.startTime = Date.now(); this.startTime = Date.now();

View File

@@ -0,0 +1,26 @@
/**
* Standardized error codes for IPC communication
* These are used instead of string messages for better error handling
*/
export enum ErrorCode {
// General errors
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
INVALID_REQUEST = 'INVALID_REQUEST',
// Process errors
PROCESS_NOT_FOUND = 'PROCESS_NOT_FOUND',
PROCESS_ALREADY_EXISTS = 'PROCESS_ALREADY_EXISTS',
PROCESS_START_FAILED = 'PROCESS_START_FAILED',
PROCESS_STOP_FAILED = 'PROCESS_STOP_FAILED',
// Daemon errors
DAEMON_NOT_RUNNING = 'DAEMON_NOT_RUNNING',
DAEMON_ALREADY_RUNNING = 'DAEMON_ALREADY_RUNNING',
// Memory errors
MEMORY_LIMIT_EXCEEDED = 'MEMORY_LIMIT_EXCEEDED',
// Config errors
CONFIG_INVALID = 'CONFIG_INVALID',
CONFIG_SAVE_FAILED = 'CONFIG_SAVE_FAILED',
}

View File

@@ -0,0 +1,5 @@
/**
* Protocol version for client-daemon communication
* This allows for version compatibility checks between client and daemon
*/
export const PROTOCOL_VERSION = '1.0.0';