@kadi.build/file-sharing 1.0.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/README.md +477 -0
- package/package.json +60 -0
- package/src/DownloadMonitor.js +199 -0
- package/src/EventNotifier.js +178 -0
- package/src/FileSharingServer.js +598 -0
- package/src/HttpServerProvider.js +538 -0
- package/src/MonitoringDashboard.js +181 -0
- package/src/S3Server.js +984 -0
- package/src/ShutdownManager.js +135 -0
- package/src/index.js +69 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ShutdownManager - Graceful shutdown for @kadi.build/file-sharing
|
|
3
|
+
*
|
|
4
|
+
* Manages ordered shutdown of components with priority-based callback execution,
|
|
5
|
+
* timeout handling, and process signal integration.
|
|
6
|
+
*
|
|
7
|
+
* Migrated from src/shutdownManager.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
|
|
12
|
+
export class ShutdownManager extends EventEmitter {
|
|
13
|
+
constructor(config = {}) {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
this.config = {
|
|
17
|
+
gracefulTimeout: 30000,
|
|
18
|
+
finishActiveDownloads: true,
|
|
19
|
+
forceKillTimeout: 60000,
|
|
20
|
+
...config
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.isShuttingDown = false;
|
|
24
|
+
this.shutdownCallbacks = [];
|
|
25
|
+
this._signalHandlersInstalled = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register a shutdown callback with priority
|
|
30
|
+
* Lower priority numbers execute first.
|
|
31
|
+
* @param {Function} callback - Async callback to execute during shutdown
|
|
32
|
+
* @param {number} priority - Execution priority (lower = earlier, default 10)
|
|
33
|
+
*/
|
|
34
|
+
register(callback, priority = 10) {
|
|
35
|
+
this.shutdownCallbacks.push({ callback, priority });
|
|
36
|
+
this.shutdownCallbacks.sort((a, b) => a.priority - b.priority);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Unregister a previously registered callback
|
|
41
|
+
* @param {Function} callback - The callback to remove
|
|
42
|
+
*/
|
|
43
|
+
unregister(callback) {
|
|
44
|
+
this.shutdownCallbacks = this.shutdownCallbacks.filter(
|
|
45
|
+
(entry) => entry.callback !== callback
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Install process signal handlers (SIGINT, SIGTERM)
|
|
51
|
+
*/
|
|
52
|
+
installSignalHandlers() {
|
|
53
|
+
if (this._signalHandlersInstalled) return;
|
|
54
|
+
|
|
55
|
+
const handler = () => {
|
|
56
|
+
this.shutdown().catch((err) => {
|
|
57
|
+
this.emit('shutdown:error', err);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
process.on('SIGINT', handler);
|
|
62
|
+
process.on('SIGTERM', handler);
|
|
63
|
+
this._signalHandlersInstalled = true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Perform graceful shutdown
|
|
68
|
+
* Executes all registered callbacks in priority order with timeout.
|
|
69
|
+
*/
|
|
70
|
+
async shutdown() {
|
|
71
|
+
if (this.isShuttingDown) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.isShuttingDown = true;
|
|
76
|
+
this.emit('shutdown:start');
|
|
77
|
+
|
|
78
|
+
const total = this.shutdownCallbacks.length;
|
|
79
|
+
let completed = 0;
|
|
80
|
+
|
|
81
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
82
|
+
setTimeout(
|
|
83
|
+
() => reject(new Error('Shutdown timeout exceeded')),
|
|
84
|
+
this.config.gracefulTimeout
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await Promise.race([
|
|
90
|
+
this._executeCallbacks((count) => {
|
|
91
|
+
completed = count;
|
|
92
|
+
this.emit('shutdown:progress', { completed, total });
|
|
93
|
+
}),
|
|
94
|
+
timeoutPromise
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
this.emit('shutdown:complete');
|
|
98
|
+
} catch (error) {
|
|
99
|
+
this.emit('shutdown:timeout', error);
|
|
100
|
+
await this.forceShutdown();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Force shutdown - skip remaining callbacks
|
|
106
|
+
*/
|
|
107
|
+
async forceShutdown() {
|
|
108
|
+
this.emit('shutdown:force');
|
|
109
|
+
this.isShuttingDown = true;
|
|
110
|
+
// Clear remaining callbacks
|
|
111
|
+
this.shutdownCallbacks = [];
|
|
112
|
+
this.emit('shutdown:complete');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Execute all registered callbacks in order
|
|
117
|
+
* @param {Function} onProgress - Progress callback
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
async _executeCallbacks(onProgress) {
|
|
121
|
+
let completed = 0;
|
|
122
|
+
|
|
123
|
+
for (const { callback } of this.shutdownCallbacks) {
|
|
124
|
+
try {
|
|
125
|
+
await callback();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.emit('shutdown:error', error);
|
|
128
|
+
}
|
|
129
|
+
completed++;
|
|
130
|
+
if (onProgress) onProgress(completed);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default ShutdownManager;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @kadi.build/file-sharing - Main entry point
|
|
3
|
+
*
|
|
4
|
+
* File sharing service with tunneling and local S3-compatible interface.
|
|
5
|
+
* Integrates @kadi.build/file-manager and @kadi.build/tunnel-services.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Core classes
|
|
9
|
+
export { FileSharingServer } from './FileSharingServer.js';
|
|
10
|
+
export { HttpServerProvider } from './HttpServerProvider.js';
|
|
11
|
+
export { S3Server } from './S3Server.js';
|
|
12
|
+
export { DownloadMonitor } from './DownloadMonitor.js';
|
|
13
|
+
export { ShutdownManager } from './ShutdownManager.js';
|
|
14
|
+
export { MonitoringDashboard } from './MonitoringDashboard.js';
|
|
15
|
+
export { EventNotifier } from './EventNotifier.js';
|
|
16
|
+
|
|
17
|
+
// Re-export from dependencies for convenience
|
|
18
|
+
export { FileManager, createFileManager } from '@kadi.build/file-manager';
|
|
19
|
+
export { TunnelManager } from '@kadi.build/tunnel-services';
|
|
20
|
+
|
|
21
|
+
// Default export
|
|
22
|
+
export { FileSharingServer as default } from './FileSharingServer.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create a FileSharingServer with default options
|
|
26
|
+
* @param {object} options - Configuration options
|
|
27
|
+
* @returns {FileSharingServer}
|
|
28
|
+
*/
|
|
29
|
+
export function createFileSharingServer(options = {}) {
|
|
30
|
+
return new FileSharingServer(options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Quick share - one-liner to share a directory
|
|
35
|
+
* @param {string} directory - Directory to share
|
|
36
|
+
* @param {object} options - Options
|
|
37
|
+
* @param {number} [options.port=3000] - HTTP port
|
|
38
|
+
* @param {boolean} [options.tunnel=false] - Enable tunnel
|
|
39
|
+
* @param {string} [options.tunnelService='kadi'] - Tunnel service name
|
|
40
|
+
* @param {string} [options.kadiToken] - KĀDI auth token (or set KADI_TUNNEL_TOKEN env)
|
|
41
|
+
* @param {string} [options.ngrokAuthToken] - Ngrok auth token (or set NGROK_AUTHTOKEN env)
|
|
42
|
+
* @param {object} [options.auth] - HTTP auth config ({apiKey} or {username,password})
|
|
43
|
+
* @param {object} [options.tunnelOptions] - Extra options passed to TunnelManager
|
|
44
|
+
* @returns {Promise<{ server: FileSharingServer, localUrl: string, publicUrl?: string }>}
|
|
45
|
+
*/
|
|
46
|
+
export async function createQuickShare(directory, options = {}) {
|
|
47
|
+
const server = new FileSharingServer({
|
|
48
|
+
staticDir: directory,
|
|
49
|
+
port: options.port || 3000,
|
|
50
|
+
auth: options.auth || null,
|
|
51
|
+
tunnel: options.tunnel
|
|
52
|
+
? {
|
|
53
|
+
enabled: true,
|
|
54
|
+
service: options.tunnelService || 'kadi',
|
|
55
|
+
kadiToken: options.kadiToken,
|
|
56
|
+
ngrokAuthToken: options.ngrokAuthToken,
|
|
57
|
+
...(options.tunnelOptions || {})
|
|
58
|
+
}
|
|
59
|
+
: { enabled: false }
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const info = await server.start();
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
server,
|
|
66
|
+
localUrl: info.localUrl,
|
|
67
|
+
publicUrl: info.publicUrl || undefined
|
|
68
|
+
};
|
|
69
|
+
}
|