@docker-digital/dockernet-agent 0.1.0 → 0.1.2

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.
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var TerminalService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.TerminalService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const socket_io_client_1 = require("socket.io-client");
16
+ const config_service_1 = require("./config.service");
17
+ const docker_service_1 = require("./docker.service");
18
+ let TerminalService = TerminalService_1 = class TerminalService {
19
+ constructor(configService, dockerService) {
20
+ this.configService = configService;
21
+ this.dockerService = dockerService;
22
+ this.logger = new common_1.Logger(TerminalService_1.name);
23
+ this.socket = null;
24
+ this.isConnected = false;
25
+ this.activeSessions = new Map();
26
+ }
27
+ async onModuleInit() {
28
+ }
29
+ async connect() {
30
+ if (this.isConnected && this.socket?.connected) {
31
+ this.logger.debug('Terminal WebSocket already connected');
32
+ return;
33
+ }
34
+ try {
35
+ const wsUrl = await this.getWebSocketUrl();
36
+ const apiKey = await this.configService.getApiKey();
37
+ if (!apiKey) {
38
+ this.logger.warn('Cannot connect Terminal WebSocket: API key not configured');
39
+ return;
40
+ }
41
+ this.logger.log(`Connecting to Terminal WebSocket: ${wsUrl}`);
42
+ this.socket = (0, socket_io_client_1.io)(`${wsUrl}/ws-agent`, {
43
+ auth: {
44
+ api_key: apiKey,
45
+ machine_key: await this.configService.getMachineKey(),
46
+ },
47
+ reconnection: true,
48
+ reconnectionDelay: 1000,
49
+ reconnectionDelayMax: 5000,
50
+ reconnectionAttempts: 10,
51
+ timeout: 10000,
52
+ transports: ['websocket', 'polling'],
53
+ path: '/socket.io/',
54
+ });
55
+ this.setupSocketHandlers();
56
+ }
57
+ catch (error) {
58
+ this.logger.error(`Failed to connect to Terminal WebSocket: ${error.message}`);
59
+ throw error;
60
+ }
61
+ }
62
+ setupSocketHandlers() {
63
+ if (!this.socket) {
64
+ this.logger.warn('[AGENT] setupSocketHandlers called but socket is null');
65
+ return;
66
+ }
67
+ this.logger.log(`[AGENT] Setting up socket handlers. Socket ID: ${this.socket.id}, connected: ${this.socket.connected}`);
68
+ this.socket.on('connect', () => {
69
+ this.logger.debug(`Terminal WebSocket transport connected (socket ID: ${this.socket?.id}), waiting for authentication...`);
70
+ });
71
+ this.socket.on('connected', (data) => {
72
+ this.isConnected = true;
73
+ this.logger.log(`[AGENT] ✅ Terminal WebSocket connected and authenticated (socket ID: ${this.socket?.id})`);
74
+ this.logger.debug(`[AGENT] All event listeners should now be active, including 'new_session' listener`);
75
+ });
76
+ this.socket.on('connect_error', (error) => {
77
+ this.logger.error(`Terminal WebSocket connection error: ${error.message}`);
78
+ this.isConnected = false;
79
+ });
80
+ this.socket.on('error', (error) => {
81
+ const errorMessage = typeof error === 'string'
82
+ ? error
83
+ : error?.message || error?.toString() || 'Unknown error';
84
+ if (errorMessage.includes('API key') ||
85
+ errorMessage.includes('API key required')) {
86
+ this.logger.error(`Terminal WebSocket authentication error: ${errorMessage}`);
87
+ this.isConnected = false;
88
+ }
89
+ else {
90
+ this.logger.error(`Terminal WebSocket error: ${errorMessage}`);
91
+ }
92
+ });
93
+ this.socket.on('disconnect', (reason) => {
94
+ if (reason === 'io client disconnect') {
95
+ this.logger.debug(`Terminal WebSocket disconnected: ${reason}`);
96
+ }
97
+ else {
98
+ this.logger.warn(`Terminal WebSocket disconnected: ${reason}`);
99
+ }
100
+ this.isConnected = false;
101
+ this.cleanupAllSessions();
102
+ });
103
+ this.logger.debug(`[AGENT] Registering listener for 'new_session' event. Socket connected: ${this.socket?.connected}`);
104
+ this.socket.on('new_session', async (data) => {
105
+ this.logger.log(`[AGENT] ✅ Received new_session event: ${data.session_id} for service: ${data.service_name}`);
106
+ this.logger.debug(`[AGENT] new_session data: ${JSON.stringify(data)}`);
107
+ try {
108
+ const containerId = await this.dockerService.getContainerId(data.profile_id, data.service_name);
109
+ if (!containerId) {
110
+ this.logger.warn(`Container ID not found for profile ${data.profile_id}, service ${data.service_name}`);
111
+ this.socket?.emit('error', {
112
+ session_id: data.session_id,
113
+ message: 'Container not found',
114
+ });
115
+ return;
116
+ }
117
+ this.logger.log(`[AGENT] Emitting attach_session for session ${data.session_id} with container ${containerId}`);
118
+ this.logger.debug(`[AGENT] Socket connected: ${this.socket?.connected}, Socket ID: ${this.socket?.id}`);
119
+ const attachData = {
120
+ session_id: data.session_id,
121
+ container_id: containerId,
122
+ };
123
+ this.logger.debug(`[AGENT] Emitting attach_session with data: ${JSON.stringify(attachData)}`);
124
+ this.socket?.emit('attach_session', attachData);
125
+ this.logger.log(`[AGENT] attach_session event emitted for session ${data.session_id}`);
126
+ this.logger.log(`[AGENT] Calling handleAttachSession directly to create session ${data.session_id}`);
127
+ await this.handleAttachSession(attachData);
128
+ }
129
+ catch (error) {
130
+ this.logger.error(`Failed to attach to session ${data.session_id}: ${error.message}`);
131
+ this.socket?.emit('error', {
132
+ session_id: data.session_id,
133
+ message: error.message || 'Failed to attach session',
134
+ });
135
+ }
136
+ });
137
+ this.socket.on('attach_session', async (data) => {
138
+ await this.handleAttachSession(data);
139
+ });
140
+ this.socket.on('input', async (data) => {
141
+ this.logger.debug(`Received input event for session ${data.session_id}, data length: ${data.data?.length || 0}`);
142
+ await this.handleInput(data);
143
+ });
144
+ this.socket.on('resize', async (data) => {
145
+ await this.handleResize(data);
146
+ });
147
+ this.socket.on('close', async (data) => {
148
+ await this.handleClose(data.session_id);
149
+ });
150
+ }
151
+ async handleAttachSession(data) {
152
+ const { session_id, container_id } = data;
153
+ if (this.activeSessions.has(session_id)) {
154
+ this.logger.warn(`[AGENT] ⚠️ Session ${session_id} already exists in activeSessions. Skipping duplicate attach.`);
155
+ return;
156
+ }
157
+ this.logger.log(`[AGENT] Handling attach_session request: ${session_id} for container: ${container_id}`);
158
+ try {
159
+ let targetContainerId = container_id;
160
+ if (!targetContainerId) {
161
+ this.logger.warn(`No container_id provided for session ${session_id}. Container resolution requires additional context.`);
162
+ this.socket?.emit('error', {
163
+ session_id,
164
+ message: 'Container ID is required. Please ensure the service is running.',
165
+ });
166
+ return;
167
+ }
168
+ const isRunning = await this.dockerService.isContainerRunning(targetContainerId);
169
+ if (!isRunning) {
170
+ this.logger.warn(`Container ${targetContainerId} is not running`);
171
+ this.socket?.emit('error', {
172
+ session_id,
173
+ message: 'Container is not running. Please start the service first.',
174
+ });
175
+ return;
176
+ }
177
+ const exec = await this.dockerService.createTerminalExec(targetContainerId);
178
+ const streams = await this.dockerService.startExec(exec);
179
+ if (this.activeSessions.has(session_id)) {
180
+ this.logger.warn(`[AGENT] ⚠️ Session ${session_id} already exists. Cleaning up old session before creating new one.`);
181
+ const oldSession = this.activeSessions.get(session_id);
182
+ if (oldSession?.streams) {
183
+ oldSession.streams.stdout.removeAllListeners('data');
184
+ oldSession.streams.stderr.removeAllListeners('data');
185
+ oldSession.streams.stdout.removeAllListeners('end');
186
+ oldSession.streams.stderr.removeAllListeners('end');
187
+ }
188
+ this.activeSessions.delete(session_id);
189
+ }
190
+ this.activeSessions.set(session_id, {
191
+ sessionId: session_id,
192
+ containerId: targetContainerId,
193
+ exec,
194
+ streams,
195
+ });
196
+ this.logger.log(`[AGENT] ✅ Session ${session_id} created and stored. Total active sessions: ${this.activeSessions.size}`);
197
+ this.logger.debug(`[AGENT] Active sessions: ${Array.from(this.activeSessions.keys()).join(', ')}`);
198
+ streams.stdout.removeAllListeners('data');
199
+ streams.stdout.removeAllListeners('end');
200
+ streams.stdout.on('data', (chunk) => {
201
+ this.sendOutput(session_id, chunk.toString('utf8'));
202
+ });
203
+ streams.stdout.on('end', () => {
204
+ this.logger.log(`Exec session ${session_id} ended`);
205
+ this.closeSession(session_id);
206
+ });
207
+ this.socket?.emit('session_attached', {
208
+ session_id: session_id,
209
+ container_id: targetContainerId,
210
+ });
211
+ this.logger.log(`Successfully attached to session ${session_id}`);
212
+ }
213
+ catch (error) {
214
+ this.logger.error(`Failed to attach to session ${session_id}: ${error.message}`);
215
+ this.socket?.emit('error', {
216
+ session_id,
217
+ message: error.message,
218
+ });
219
+ }
220
+ }
221
+ async handleInput(data) {
222
+ const { session_id, data: inputData } = data;
223
+ this.logger.debug(`[AGENT] Handling input for session ${session_id}, data: ${JSON.stringify(inputData.substring(0, 50))}`);
224
+ const session = this.activeSessions.get(session_id);
225
+ if (!session) {
226
+ this.logger.warn(`[AGENT] ⚠️ Received input for unknown session: ${session_id}`);
227
+ this.logger.warn(`[AGENT] Active sessions: ${Array.from(this.activeSessions.keys()).join(', ') || 'none'}`);
228
+ this.logger.warn(`[AGENT] This usually means the session was not created. Check if 'new_session' event was received and 'attach_session' was successful.`);
229
+ return;
230
+ }
231
+ try {
232
+ session.streams.stdin.write(inputData);
233
+ this.logger.debug(`Successfully wrote input to container for session ${session_id}`);
234
+ }
235
+ catch (error) {
236
+ this.logger.error(`Failed to write input to session ${session_id}: ${error.message}`);
237
+ }
238
+ }
239
+ async handleResize(data) {
240
+ const { session_id, cols, rows } = data;
241
+ const session = this.activeSessions.get(session_id);
242
+ if (!session) {
243
+ this.logger.warn(`Received resize for unknown session: ${session_id}`);
244
+ return;
245
+ }
246
+ try {
247
+ await this.dockerService.resizeExec(session.exec, cols, rows);
248
+ this.logger.debug(`Resized session ${session_id} to ${cols}x${rows}`);
249
+ }
250
+ catch (error) {
251
+ this.logger.error(`Failed to resize session ${session_id}: ${error.message}`);
252
+ }
253
+ }
254
+ async handleClose(sessionId) {
255
+ this.logger.log(`Closing session: ${sessionId}`);
256
+ this.closeSession(sessionId);
257
+ }
258
+ sendOutput(sessionId, data) {
259
+ if (this.socket?.connected) {
260
+ this.socket.emit('output', {
261
+ session_id: sessionId,
262
+ data: data,
263
+ });
264
+ }
265
+ }
266
+ closeSession(sessionId) {
267
+ const session = this.activeSessions.get(sessionId);
268
+ if (!session) {
269
+ return;
270
+ }
271
+ this.logger.log(`Closing terminal session: ${sessionId}`);
272
+ try {
273
+ session.streams.stdin.end();
274
+ }
275
+ catch (error) {
276
+ }
277
+ this.activeSessions.delete(sessionId);
278
+ this.socket?.emit('detach_session', {
279
+ session_id: sessionId,
280
+ });
281
+ this.logger.log(`Session ${sessionId} closed`);
282
+ }
283
+ cleanupAllSessions() {
284
+ this.logger.log(`Cleaning up ${this.activeSessions.size} active sessions`);
285
+ for (const sessionId of this.activeSessions.keys()) {
286
+ this.closeSession(sessionId);
287
+ }
288
+ }
289
+ async getWebSocketUrl() {
290
+ const serverUrl = this.configService.websocketUrl;
291
+ let wsUrl = serverUrl.replace(/^http/, 'ws');
292
+ wsUrl = wsUrl.replace(/\/$/, '');
293
+ return wsUrl;
294
+ }
295
+ onModuleDestroy() {
296
+ this.logger.debug('TerminalService onModuleDestroy called');
297
+ this.cleanupAllSessions();
298
+ if (this.socket) {
299
+ this.socket.disconnect();
300
+ this.socket = null;
301
+ }
302
+ this.isConnected = false;
303
+ }
304
+ isTerminalConnected() {
305
+ return this.isConnected && this.socket?.connected === true;
306
+ }
307
+ disconnect() {
308
+ if (this.socket && (this.socket.connected || this.isConnected)) {
309
+ this.logger.log('Disconnecting Terminal WebSocket...');
310
+ }
311
+ this.isConnected = false;
312
+ if (this.socket) {
313
+ this.socket.disconnect();
314
+ this.socket = null;
315
+ }
316
+ this.cleanupAllSessions();
317
+ }
318
+ };
319
+ exports.TerminalService = TerminalService;
320
+ exports.TerminalService = TerminalService = TerminalService_1 = __decorate([
321
+ (0, common_1.Injectable)(),
322
+ __metadata("design:paramtypes", [config_service_1.ConfigService,
323
+ docker_service_1.DockerService])
324
+ ], TerminalService);
325
+ //# sourceMappingURL=terminal.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.service.js","sourceRoot":"","sources":["../../../src/agent/services/terminal.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { ApiService } from './api.service';
2
+ import { ConfigService } from './config.service';
3
+ export declare class VolumeBackupService {
4
+ private apiService;
5
+ private configService;
6
+ private readonly logger;
7
+ private readonly tempDir;
8
+ constructor(apiService: ApiService, configService: ConfigService);
9
+ processVolumeBackupJobs(): Promise<void>;
10
+ private findVolumePath;
11
+ private compressVolume;
12
+ private uploadToStorage;
13
+ private uploadToR2;
14
+ }
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var VolumeBackupService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.VolumeBackupService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const schedule_1 = require("@nestjs/schedule");
16
+ const fs = require("fs-extra");
17
+ const path = require("path");
18
+ const child_process_1 = require("child_process");
19
+ const util_1 = require("util");
20
+ const api_service_1 = require("./api.service");
21
+ const config_service_1 = require("./config.service");
22
+ const client_s3_1 = require("@aws-sdk/client-s3");
23
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
24
+ var StoragePlatform;
25
+ (function (StoragePlatform) {
26
+ StoragePlatform["R2"] = "r2";
27
+ StoragePlatform["S3"] = "s3";
28
+ StoragePlatform["GOOGLE_DRIVE"] = "google_drive";
29
+ StoragePlatform["DROPBOX"] = "dropbox";
30
+ })(StoragePlatform || (StoragePlatform = {}));
31
+ let VolumeBackupService = VolumeBackupService_1 = class VolumeBackupService {
32
+ constructor(apiService, configService) {
33
+ this.apiService = apiService;
34
+ this.configService = configService;
35
+ this.logger = new common_1.Logger(VolumeBackupService_1.name);
36
+ this.tempDir = '/tmp/dockernet-backups';
37
+ fs.ensureDirSync(this.tempDir);
38
+ }
39
+ async processVolumeBackupJobs() {
40
+ const machineKey = await this.configService.getMachineKey();
41
+ if (!machineKey) {
42
+ return;
43
+ }
44
+ const jobJson = await this.apiService.callApi('GET', `/volume-backup/jobs?machine_key=${machineKey}`, undefined, -1, 5000);
45
+ if (!jobJson || !jobJson.id) {
46
+ return;
47
+ }
48
+ const jobId = jobJson.id;
49
+ const profileKey = jobJson.profile_key;
50
+ const profileName = jobJson.profile_name;
51
+ const serviceKey = jobJson.service_key;
52
+ const serviceName = jobJson.service_name;
53
+ const volumeName = jobJson.volume_name;
54
+ const storageConfigKey = jobJson.storage_config_key;
55
+ const storagePlatform = jobJson.storage_platform;
56
+ if (!jobId || !profileKey || !profileName || !serviceKey || !serviceName || !volumeName || !storageConfigKey) {
57
+ return;
58
+ }
59
+ this.logger.log(`Volume backup job ${jobId}: profile ${profileName} (${profileKey}), service ${serviceName} (${serviceKey}), volume ${volumeName}`);
60
+ let status = 'compressing';
61
+ let message = '';
62
+ try {
63
+ await this.apiService.callApi('POST', `/volume-backup/jobs/${jobId}/complete`, { status: 'compressing' });
64
+ const storageConfigResponse = await this.apiService.callApi('GET', `/storage?key=${storageConfigKey}`, undefined, 3, 5000);
65
+ if (!storageConfigResponse || !storageConfigResponse.config) {
66
+ throw new Error('Storage config not found');
67
+ }
68
+ if (!storageConfigResponse || !storageConfigResponse.config) {
69
+ throw new Error('Storage config not found or invalid');
70
+ }
71
+ const storageConfig = storageConfigResponse.config;
72
+ const volumePath = await this.findVolumePath(profileKey, serviceKey, volumeName);
73
+ if (!volumePath) {
74
+ throw new Error(`Volume path not found for volume ${volumeName}`);
75
+ }
76
+ if (!(await fs.pathExists(volumePath))) {
77
+ throw new Error(`Volume path does not exist: ${volumePath}`);
78
+ }
79
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
80
+ const archiveName = `${profileName}+${serviceName}+${timestamp}.tar.gz`;
81
+ const archivePath = path.join(this.tempDir, archiveName);
82
+ this.logger.log(`Compressing ${volumePath} to ${archivePath}`);
83
+ await this.compressVolume(volumePath, archivePath);
84
+ status = 'uploading';
85
+ await this.apiService.callApi('POST', `/volume-backup/jobs/${jobId}/complete`, { status: 'uploading' });
86
+ this.logger.log(`Uploading ${archivePath} to ${storagePlatform}`);
87
+ await this.uploadToStorage(storagePlatform, storageConfig, archivePath, archiveName, profileKey, profileName, serviceKey, serviceName, volumeName);
88
+ await fs.remove(archivePath);
89
+ status = 'completed';
90
+ message = `Backup completed successfully: ${archiveName}`;
91
+ }
92
+ catch (error) {
93
+ status = 'failed';
94
+ message = error.message || 'Backup failed';
95
+ this.logger.error(`Volume backup job ${jobId} failed: ${message}`);
96
+ }
97
+ await this.apiService.callApi('POST', `/volume-backup/jobs/${jobId}/complete`, { status, message });
98
+ if (status === 'completed') {
99
+ this.logger.log(`Volume backup job ${jobId} completed`);
100
+ }
101
+ }
102
+ async findVolumePath(profileKey, serviceKey, volumeName) {
103
+ const possiblePaths = [
104
+ path.join(process.cwd(), '.dockernet-agent', 'profiles', profileKey, 'services', serviceKey, 'volumes', volumeName),
105
+ path.join('/', 'dockernet-agent', 'profiles', profileKey, 'services', serviceKey, 'volumes', volumeName),
106
+ path.join(process.env.HOME || '/root', '.dockernet-agent', 'profiles', profileKey, 'services', serviceKey, 'volumes', volumeName),
107
+ ];
108
+ for (const possiblePath of possiblePaths) {
109
+ if (await fs.pathExists(possiblePath)) {
110
+ return possiblePath;
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ async compressVolume(sourcePath, archivePath) {
116
+ try {
117
+ await execAsync(`tar -czf "${archivePath}" -C "${path.dirname(sourcePath)}" "${path.basename(sourcePath)}"`);
118
+ }
119
+ catch (error) {
120
+ throw new Error(`Compression failed: ${error.message}`);
121
+ }
122
+ }
123
+ async uploadToStorage(platform, config, filePath, fileName, profileKey, profileName, serviceKey, serviceName, volumeName) {
124
+ if (platform === StoragePlatform.R2) {
125
+ await this.uploadToR2(config, filePath, fileName, profileKey, profileName, serviceKey, serviceName, volumeName);
126
+ }
127
+ else {
128
+ throw new Error(`Platform ${platform} is not yet supported`);
129
+ }
130
+ }
131
+ async uploadToR2(config, filePath, fileName, profileKey, profileName, serviceKey, serviceName, volumeName) {
132
+ if (!config.access_key_id || !config.secret_access_key || !config.bucket) {
133
+ throw new Error('Invalid R2 configuration: missing required fields');
134
+ }
135
+ let endpoint;
136
+ if (config.account_id) {
137
+ endpoint = config.endpoint || `https://${config.account_id}.r2.cloudflarestorage.com`;
138
+ }
139
+ else if (config.endpoint) {
140
+ endpoint = config.endpoint;
141
+ }
142
+ else {
143
+ throw new Error('Invalid R2 configuration: endpoint or account_id required');
144
+ }
145
+ const s3Client = new client_s3_1.S3Client({
146
+ region: 'auto',
147
+ endpoint: endpoint,
148
+ credentials: {
149
+ accessKeyId: config.access_key_id,
150
+ secretAccessKey: config.secret_access_key,
151
+ },
152
+ forcePathStyle: false,
153
+ });
154
+ const fileContent = await fs.readFile(filePath);
155
+ const fileStats = await fs.stat(filePath);
156
+ const objectKey = `backups/${profileKey}/${serviceKey}/${volumeName}/${fileName}`;
157
+ this.logger.log(`Uploading ${fileStats.size} bytes to R2: ${objectKey}`);
158
+ const command = new client_s3_1.PutObjectCommand({
159
+ Bucket: config.bucket,
160
+ Key: objectKey,
161
+ Body: fileContent,
162
+ ContentType: 'application/gzip',
163
+ });
164
+ await s3Client.send(command);
165
+ this.logger.log(`Successfully uploaded to R2: ${objectKey}`);
166
+ }
167
+ };
168
+ exports.VolumeBackupService = VolumeBackupService;
169
+ __decorate([
170
+ (0, schedule_1.Cron)(schedule_1.CronExpression.EVERY_5_SECONDS),
171
+ __metadata("design:type", Function),
172
+ __metadata("design:paramtypes", []),
173
+ __metadata("design:returntype", Promise)
174
+ ], VolumeBackupService.prototype, "processVolumeBackupJobs", null);
175
+ exports.VolumeBackupService = VolumeBackupService = VolumeBackupService_1 = __decorate([
176
+ (0, common_1.Injectable)(),
177
+ __metadata("design:paramtypes", [api_service_1.ApiService,
178
+ config_service_1.ConfigService])
179
+ ], VolumeBackupService);
180
+ //# sourceMappingURL=volume-backup.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume-backup.service.js","sourceRoot":"","sources":["../../../src/agent/services/volume-backup.service.ts"],"names":[],"mappings":"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"}
package/dist/main.js CHANGED
@@ -43,7 +43,7 @@ class NestStyleLogger extends common_1.ConsoleLogger {
43
43
  }
44
44
  async function bootstrap() {
45
45
  const logger = new NestStyleLogger();
46
- await nest_commander_1.CommandFactory.run(app_module_1.AppModule, {
46
+ await nest_commander_1.CommandFactory.runWithoutClosing(app_module_1.AppModule, {
47
47
  logger: logger,
48
48
  });
49
49
  }
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;AAEA,mDAAgD;AAChD,2CAA+C;AAC/C,6CAAyC;AAEzC,MAAM,eAAgB,SAAQ,sBAAa;IACjC,eAAe;QACrB,OAAO,IAAI,IAAI,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE;YACxC,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;IACL,CAAC;IAES,aAAa,CACrB,KAAa,EACb,OAAY,EACZ,OAAgB;QAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,WAAW,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED,GAAG,CAAC,OAAY,EAAE,OAAgB;QAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,KAAc,EAAE,OAAgB;QAClD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAY,EAAE,OAAgB;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,OAAgB;QAClC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,CAAC,OAAY,EAAE,OAAgB;QACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC;CACF;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,MAAM,+BAAc,CAAC,GAAG,CAAC,sBAAS,EAAE;QAClC,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;AACL,CAAC;AAED,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;AAEA,mDAAgD;AAChD,2CAA+C;AAC/C,6CAAyC;AAEzC,MAAM,eAAgB,SAAQ,sBAAa;IACjC,eAAe;QACrB,OAAO,IAAI,IAAI,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE;YACxC,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;IACL,CAAC;IAES,aAAa,CACrB,KAAa,EACb,OAAY,EACZ,OAAgB;QAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,OAAO,WAAW,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED,GAAG,CAAC,OAAY,EAAE,OAAgB;QAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,KAAc,EAAE,OAAgB;QAClD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAY,EAAE,OAAgB;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,OAAY,EAAE,OAAgB;QAClC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,CAAC,OAAY,EAAE,OAAgB;QACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC;CACF;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IAIrC,MAAM,+BAAc,CAAC,iBAAiB,CAAC,sBAAS,EAAE;QAChD,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;AAIL,CAAC;AAED,SAAS,EAAE,CAAC"}