@docker-digital/dockernet-agent 0.0.1
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/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/agent/agent.module.d.ts +2 -0
- package/dist/agent/agent.module.js +47 -0
- package/dist/agent/agent.module.js.map +1 -0
- package/dist/agent/commands/agent.command.d.ts +58 -0
- package/dist/agent/commands/agent.command.js +417 -0
- package/dist/agent/commands/agent.command.js.map +1 -0
- package/dist/agent/services/api.service.d.ts +13 -0
- package/dist/agent/services/api.service.js +116 -0
- package/dist/agent/services/api.service.js.map +1 -0
- package/dist/agent/services/config.service.d.ts +28 -0
- package/dist/agent/services/config.service.js +100 -0
- package/dist/agent/services/config.service.js.map +1 -0
- package/dist/agent/services/docker-event.service.d.ts +44 -0
- package/dist/agent/services/docker-event.service.js +141 -0
- package/dist/agent/services/docker-event.service.js.map +1 -0
- package/dist/agent/services/docker.service.d.ts +16 -0
- package/dist/agent/services/docker.service.js +170 -0
- package/dist/agent/services/docker.service.js.map +1 -0
- package/dist/agent/services/event-websocket-client.service.d.ts +49 -0
- package/dist/agent/services/event-websocket-client.service.js +248 -0
- package/dist/agent/services/event-websocket-client.service.js.map +1 -0
- package/dist/agent/services/event.service.d.ts +27 -0
- package/dist/agent/services/event.service.js +242 -0
- package/dist/agent/services/event.service.js.map +1 -0
- package/dist/agent/services/log.service.d.ts +19 -0
- package/dist/agent/services/log.service.js +176 -0
- package/dist/agent/services/log.service.js.map +1 -0
- package/dist/agent/services/machine.service.d.ts +15 -0
- package/dist/agent/services/machine.service.js +148 -0
- package/dist/agent/services/machine.service.js.map +1 -0
- package/dist/agent/services/profile.service.d.ts +33 -0
- package/dist/agent/services/profile.service.js +438 -0
- package/dist/agent/services/profile.service.js.map +1 -0
- package/dist/agent/services/volume-sync.service.d.ts +9 -0
- package/dist/agent/services/volume-sync.service.js +87 -0
- package/dist/agent/services/volume-sync.service.js.map +1 -0
- package/dist/agent/services/websocket-client.service.d.ts +48 -0
- package/dist/agent/services/websocket-client.service.js +278 -0
- package/dist/agent/services/websocket-client.service.js.map +1 -0
- package/dist/app.module.d.ts +2 -0
- package/dist/app.module.js +31 -0
- package/dist/app.module.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,242 @@
|
|
|
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 EventService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.EventService = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const schedule_1 = require("@nestjs/schedule");
|
|
16
|
+
const api_service_1 = require("./api.service");
|
|
17
|
+
const config_service_1 = require("./config.service");
|
|
18
|
+
const profile_service_1 = require("./profile.service");
|
|
19
|
+
const websocket_client_service_1 = require("./websocket-client.service");
|
|
20
|
+
const event_websocket_client_service_1 = require("./event-websocket-client.service");
|
|
21
|
+
let EventService = EventService_1 = class EventService {
|
|
22
|
+
constructor(apiService, configService, profileService, websocketClientService, eventWebSocketClientService) {
|
|
23
|
+
this.apiService = apiService;
|
|
24
|
+
this.configService = configService;
|
|
25
|
+
this.profileService = profileService;
|
|
26
|
+
this.websocketClientService = websocketClientService;
|
|
27
|
+
this.eventWebSocketClientService = eventWebSocketClientService;
|
|
28
|
+
this.logger = new common_1.Logger(EventService_1.name);
|
|
29
|
+
this.isPolling = false;
|
|
30
|
+
this.useEventDrivenUpdates = false;
|
|
31
|
+
this.isWebSocketListening = false;
|
|
32
|
+
this.useEventDrivenUpdates =
|
|
33
|
+
this.websocketClientService.isWebSocketConnected();
|
|
34
|
+
}
|
|
35
|
+
async startPolling() {
|
|
36
|
+
if (this.isPolling) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.isPolling = true;
|
|
40
|
+
this.logger.log('Starting event listening...');
|
|
41
|
+
try {
|
|
42
|
+
const machineKey = await this.configService.getMachineKey();
|
|
43
|
+
if (machineKey) {
|
|
44
|
+
await this.startWebSocketListening(machineKey);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.logger.warn('Machine key not found, falling back to polling');
|
|
48
|
+
await this.startPollingFallback();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
this.logger.error(`Error starting WebSocket listening: ${error.message}, falling back to polling`);
|
|
53
|
+
await this.startPollingFallback();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async startWebSocketListening(machineKey) {
|
|
57
|
+
if (this.isWebSocketListening) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.logger.log(`Connecting to event WebSocket for machine: ${machineKey}`);
|
|
61
|
+
try {
|
|
62
|
+
await this.eventWebSocketClientService.connect(machineKey);
|
|
63
|
+
this.eventWebSocketClientService.onEvent((event) => {
|
|
64
|
+
this.handleWebSocketEvent(event);
|
|
65
|
+
});
|
|
66
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
67
|
+
if (this.eventWebSocketClientService.isSubscribedToEvents()) {
|
|
68
|
+
const machineId = this.eventWebSocketClientService.getCurrentMachineId();
|
|
69
|
+
this.logger.log(`Successfully connected and subscribed to event WebSocket for machine: ${machineId}`);
|
|
70
|
+
this.isWebSocketListening = true;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
this.logger.warn('Connected to event WebSocket but subscription not confirmed yet');
|
|
74
|
+
this.isWebSocketListening = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
this.logger.error(`Failed to connect to event WebSocket: ${error.message}`);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async startPollingFallback() {
|
|
83
|
+
this.logger.log('Starting event polling as fallback...');
|
|
84
|
+
while (this.isPolling) {
|
|
85
|
+
try {
|
|
86
|
+
await this.pollEvents();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
this.logger.error(`Error polling events: ${error.message}`);
|
|
90
|
+
try {
|
|
91
|
+
}
|
|
92
|
+
catch (updateError) {
|
|
93
|
+
this.logger.error(`Error updating profiles after polling error: ${updateError.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const interval = this.configService.pollIntervalSeconds * 1000;
|
|
97
|
+
await this.sleep(interval);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
handleWebSocketEvent(event) {
|
|
101
|
+
this.logger.log(`Received event via WebSocket: ${event.key} (type: ${event.type}, profile: ${event.profile_id})`);
|
|
102
|
+
try {
|
|
103
|
+
if (!event.key || !event.type || !event.profile_id) {
|
|
104
|
+
this.logger.warn('Invalid event (missing key, type, or profile_id)');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (event.status !== 'scheduled') {
|
|
108
|
+
this.logger.warn(`Skipping event ${event.key} with status=${event.status} (only processing scheduled)`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
let workspaceId = event.workspace_id;
|
|
112
|
+
if (workspaceId === 'null' ||
|
|
113
|
+
workspaceId === 'undefined' ||
|
|
114
|
+
!workspaceId) {
|
|
115
|
+
workspaceId = '';
|
|
116
|
+
}
|
|
117
|
+
this.handleEvent(event.key, event.type, event.profile_id, workspaceId);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.logger.error(`Error handling WebSocket event ${event.key}: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
stopPolling() {
|
|
124
|
+
this.isPolling = false;
|
|
125
|
+
this.logger.log('Stopped event listening');
|
|
126
|
+
if (this.isWebSocketListening) {
|
|
127
|
+
this.eventWebSocketClientService.disconnect();
|
|
128
|
+
this.isWebSocketListening = false;
|
|
129
|
+
this.logger.log('Disconnected from event WebSocket');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
checkSubscriptionStatus() {
|
|
133
|
+
const isConnected = this.eventWebSocketClientService.isWebSocketConnected();
|
|
134
|
+
const isSubscribed = this.eventWebSocketClientService.isSubscribedToEvents();
|
|
135
|
+
const machineId = this.eventWebSocketClientService.getCurrentMachineId();
|
|
136
|
+
this.logger.log(`Event subscription status: connected=${isConnected}, subscribed=${isSubscribed}, machineId=${machineId || 'none'}`);
|
|
137
|
+
}
|
|
138
|
+
async pollEvents() {
|
|
139
|
+
const response = await this.apiService.callApi('GET', '/events?status=scheduled', undefined, -1, 5000);
|
|
140
|
+
if (!response) {
|
|
141
|
+
this.logger.log('No response from server, checking saved profiles status...');
|
|
142
|
+
try {
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.logger.error(`Error updating saved profiles: ${error.message}`);
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const rows = response.data?.rows || response.rows || [];
|
|
150
|
+
const eventsCount = rows?.length || 0;
|
|
151
|
+
if (eventsCount === 0) {
|
|
152
|
+
this.logger.log('No new events, checking saved profiles status...');
|
|
153
|
+
try {
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
this.logger.error(`Error updating saved profiles: ${error.message}`);
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.logger.log(`Received ${eventsCount} event(s) with status=scheduled`);
|
|
161
|
+
for (const event of rows) {
|
|
162
|
+
const eventKey = event.key;
|
|
163
|
+
const eventType = event.type;
|
|
164
|
+
const profileId = event.profile_id;
|
|
165
|
+
let workspaceId = event.workspace_id;
|
|
166
|
+
if (!eventKey || !eventType || !profileId) {
|
|
167
|
+
this.logger.warn('Invalid event (missing key, type, or profile_id)');
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (event.status !== 'scheduled') {
|
|
171
|
+
this.logger.warn(`Skipping event ${eventKey} with status=${event.status} (only processing scheduled)`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (workspaceId === 'null' ||
|
|
175
|
+
workspaceId === 'undefined' ||
|
|
176
|
+
!workspaceId) {
|
|
177
|
+
workspaceId = '';
|
|
178
|
+
}
|
|
179
|
+
this.logger.log(`Processing event: ${eventKey} (type: ${eventType}, profile_id: ${profileId})`);
|
|
180
|
+
try {
|
|
181
|
+
await this.handleEvent(eventKey, eventType, profileId, workspaceId);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
this.logger.error(`Error handling event ${eventKey}: ${error.message}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async handleEvent(eventKey, eventType, profileId, workspaceId) {
|
|
189
|
+
if (eventType === 'start_profile') {
|
|
190
|
+
await this.profileService.startProfile(eventKey, profileId, workspaceId);
|
|
191
|
+
}
|
|
192
|
+
else if (eventType === 'stop_profile') {
|
|
193
|
+
await this.profileService.stopProfile(eventKey, profileId, workspaceId);
|
|
194
|
+
}
|
|
195
|
+
else if (eventType.startsWith('restart_service:')) {
|
|
196
|
+
const serviceName = eventType.replace('restart_service:', '');
|
|
197
|
+
await this.profileService.restartService(eventKey, profileId, workspaceId, serviceName);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this.logger.error(`Unsupported event type: ${eventType}`);
|
|
201
|
+
await this.apiService.callApi('PUT', `/events/${eventKey}`, {
|
|
202
|
+
status: 'failed',
|
|
203
|
+
is_executed: true,
|
|
204
|
+
error: `Unsupported event type: ${eventType}`,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async updateSavedProfiles() {
|
|
209
|
+
if (this.useEventDrivenUpdates) {
|
|
210
|
+
const now = Date.now();
|
|
211
|
+
const seconds = Math.floor(now / 1000);
|
|
212
|
+
if (seconds % 60 !== 0) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
this.logger.debug('Running backup status poll (event-driven updates enabled)');
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
this.logger.error(`Error updating saved profiles: ${error.message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
sleep(ms) {
|
|
224
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
exports.EventService = EventService;
|
|
228
|
+
__decorate([
|
|
229
|
+
(0, schedule_1.Cron)(schedule_1.CronExpression.EVERY_5_SECONDS),
|
|
230
|
+
__metadata("design:type", Function),
|
|
231
|
+
__metadata("design:paramtypes", []),
|
|
232
|
+
__metadata("design:returntype", Promise)
|
|
233
|
+
], EventService.prototype, "updateSavedProfiles", null);
|
|
234
|
+
exports.EventService = EventService = EventService_1 = __decorate([
|
|
235
|
+
(0, common_1.Injectable)(),
|
|
236
|
+
__metadata("design:paramtypes", [api_service_1.ApiService,
|
|
237
|
+
config_service_1.ConfigService,
|
|
238
|
+
profile_service_1.ProfileService,
|
|
239
|
+
websocket_client_service_1.WebSocketClientService,
|
|
240
|
+
event_websocket_client_service_1.EventWebSocketClientService])
|
|
241
|
+
], EventService);
|
|
242
|
+
//# sourceMappingURL=event.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.service.js","sourceRoot":"","sources":["../../../src/agent/services/event.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ApiService } from './api.service';
|
|
3
|
+
import { ConfigService } from './config.service';
|
|
4
|
+
import { DockerService } from './docker.service';
|
|
5
|
+
export declare class LogService extends EventEmitter {
|
|
6
|
+
private apiService;
|
|
7
|
+
private configService;
|
|
8
|
+
private dockerService;
|
|
9
|
+
private readonly logger;
|
|
10
|
+
private readonly logPidDir;
|
|
11
|
+
private readonly streamedContainers;
|
|
12
|
+
constructor(apiService: ApiService, configService: ConfigService, dockerService: DockerService);
|
|
13
|
+
startLogStreamsForProfile(profileId: string, workspaceId: string): Promise<void>;
|
|
14
|
+
stopLogStreamsForProfile(profileId: string): Promise<void>;
|
|
15
|
+
streamLogForContainer(containerName: string, profileId: string, serviceName: string, workspaceId: string): Promise<void>;
|
|
16
|
+
autoStreamLogsForAllContainers(): Promise<void>;
|
|
17
|
+
private processLogStream;
|
|
18
|
+
private sendLogBatch;
|
|
19
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
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 LogService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.LogService = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const events_1 = require("events");
|
|
16
|
+
const fs = require("fs-extra");
|
|
17
|
+
const path = require("path");
|
|
18
|
+
const api_service_1 = require("./api.service");
|
|
19
|
+
const config_service_1 = require("./config.service");
|
|
20
|
+
const docker_service_1 = require("./docker.service");
|
|
21
|
+
let LogService = LogService_1 = class LogService extends events_1.EventEmitter {
|
|
22
|
+
constructor(apiService, configService, dockerService) {
|
|
23
|
+
super();
|
|
24
|
+
this.apiService = apiService;
|
|
25
|
+
this.configService = configService;
|
|
26
|
+
this.dockerService = dockerService;
|
|
27
|
+
this.logger = new common_1.Logger(LogService_1.name);
|
|
28
|
+
this.streamedContainers = new Set();
|
|
29
|
+
this.logPidDir = path.join(this.configService.workDirPath, '.log_pids');
|
|
30
|
+
fs.ensureDirSync(this.logPidDir);
|
|
31
|
+
}
|
|
32
|
+
async startLogStreamsForProfile(profileId, workspaceId) {
|
|
33
|
+
const profileDir = path.join(this.configService.workDirPath, profileId);
|
|
34
|
+
const composeFile = path.join(profileDir, `docker-compose_${profileId}.yaml`);
|
|
35
|
+
if (!fs.existsSync(composeFile)) {
|
|
36
|
+
this.logger.warn(`Compose file not found: ${composeFile}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.logger.log(`Starting log streams for profile: ${profileId}`);
|
|
40
|
+
const containers = await this.dockerService.listContainers({
|
|
41
|
+
label: [`com.docker.compose.project=${profileId}`],
|
|
42
|
+
});
|
|
43
|
+
for (const container of containers) {
|
|
44
|
+
const containerName = container.Names[0]?.replace(/^\//, '') || '';
|
|
45
|
+
const serviceName = container.Labels['com.docker.compose.service'] || containerName;
|
|
46
|
+
if (containerName && container.State === 'running') {
|
|
47
|
+
await this.streamLogForContainer(containerName, profileId, serviceName, workspaceId);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async stopLogStreamsForProfile(profileId) {
|
|
52
|
+
const pidFile = path.join(this.logPidDir, `${profileId}.pids`);
|
|
53
|
+
if (!fs.existsSync(pidFile)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const pids = await fs.readFile(pidFile, 'utf-8');
|
|
57
|
+
const pidList = pids
|
|
58
|
+
.split('\n')
|
|
59
|
+
.map((p) => p.trim())
|
|
60
|
+
.filter((p) => p);
|
|
61
|
+
for (const pidStr of pidList) {
|
|
62
|
+
const pid = parseInt(pidStr, 10);
|
|
63
|
+
if (pid && !isNaN(pid)) {
|
|
64
|
+
try {
|
|
65
|
+
process.kill(pid, 'SIGTERM');
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
await fs.remove(pidFile);
|
|
72
|
+
this.logger.log(`Stopped log streams for profile: ${profileId}`);
|
|
73
|
+
}
|
|
74
|
+
async streamLogForContainer(containerName, profileId, serviceName, workspaceId) {
|
|
75
|
+
if (this.streamedContainers.has(containerName)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.streamedContainers.add(containerName);
|
|
79
|
+
this.logger.log(`Starting log stream for container: ${containerName} (profile: ${profileId}, service: ${serviceName})`);
|
|
80
|
+
try {
|
|
81
|
+
const logStream = await this.dockerService.getContainerLogs(containerName, 50);
|
|
82
|
+
this.processLogStream(logStream, containerName, profileId, serviceName, workspaceId).catch((error) => {
|
|
83
|
+
this.logger.error(`Error processing log stream for ${containerName}: ${error.message}`);
|
|
84
|
+
this.streamedContainers.delete(containerName);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.logger.error(`Error starting log stream for ${containerName}: ${error.message}`);
|
|
89
|
+
this.streamedContainers.delete(containerName);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async autoStreamLogsForAllContainers() {
|
|
93
|
+
const containers = await this.dockerService.listContainers({
|
|
94
|
+
status: ['running'],
|
|
95
|
+
});
|
|
96
|
+
for (const container of containers) {
|
|
97
|
+
const containerName = container.Names[0]?.replace(/^\//, '') || '';
|
|
98
|
+
if (!containerName)
|
|
99
|
+
continue;
|
|
100
|
+
const labels = container.Labels || {};
|
|
101
|
+
const serviceName = labels['com.docker.compose.service'] || '';
|
|
102
|
+
const projectName = labels['com.docker.compose.project'] || '';
|
|
103
|
+
let profileId = projectName;
|
|
104
|
+
if (!profileId && containerName.includes('-')) {
|
|
105
|
+
const parts = containerName.split('-');
|
|
106
|
+
profileId = parts[0];
|
|
107
|
+
}
|
|
108
|
+
if (profileId && !this.streamedContainers.has(containerName)) {
|
|
109
|
+
const profileDir = path.join(this.configService.workDirPath, profileId);
|
|
110
|
+
const metadataFile = path.join(profileDir, '.profile_metadata');
|
|
111
|
+
let workspaceId = '';
|
|
112
|
+
if (fs.existsSync(metadataFile)) {
|
|
113
|
+
const metadata = await fs.readFile(metadataFile, 'utf-8');
|
|
114
|
+
const match = metadata.match(/^workspace_id=(.+)$/m);
|
|
115
|
+
if (match) {
|
|
116
|
+
workspaceId = match[1].trim();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
await this.streamLogForContainer(containerName, profileId, serviceName || containerName, workspaceId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async processLogStream(stream, containerName, profileId, serviceName, workspaceId) {
|
|
124
|
+
const lines = [];
|
|
125
|
+
let buffer = '';
|
|
126
|
+
stream.on('data', async (chunk) => {
|
|
127
|
+
buffer += chunk.toString();
|
|
128
|
+
const newLines = buffer.split('\n');
|
|
129
|
+
buffer = newLines.pop() || '';
|
|
130
|
+
for (const line of newLines) {
|
|
131
|
+
if (line.trim()) {
|
|
132
|
+
lines.push(line);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (lines.length >= 10) {
|
|
136
|
+
await this.sendLogBatch(lines.splice(0), containerName, profileId, serviceName, workspaceId);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
stream.on('end', async () => {
|
|
140
|
+
if (lines.length > 0 || buffer) {
|
|
141
|
+
if (buffer)
|
|
142
|
+
lines.push(buffer);
|
|
143
|
+
await this.sendLogBatch(lines, containerName, profileId, serviceName, workspaceId);
|
|
144
|
+
}
|
|
145
|
+
this.streamedContainers.delete(containerName);
|
|
146
|
+
});
|
|
147
|
+
stream.on('error', (error) => {
|
|
148
|
+
this.logger.error(`Log stream error for ${containerName}: ${error.message}`);
|
|
149
|
+
this.streamedContainers.delete(containerName);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async sendLogBatch(lines, containerName, profileId, serviceName, workspaceId) {
|
|
153
|
+
for (const line of lines) {
|
|
154
|
+
if (!line.trim())
|
|
155
|
+
continue;
|
|
156
|
+
const payload = {
|
|
157
|
+
profile_id: profileId,
|
|
158
|
+
workspace_id: workspaceId,
|
|
159
|
+
service_name: serviceName,
|
|
160
|
+
container_name: containerName,
|
|
161
|
+
line: line,
|
|
162
|
+
stream: 'stdout',
|
|
163
|
+
timestamp: new Date().toISOString(),
|
|
164
|
+
};
|
|
165
|
+
await this.apiService.callApi('POST', '/logs', payload, 3, 1000);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
exports.LogService = LogService;
|
|
170
|
+
exports.LogService = LogService = LogService_1 = __decorate([
|
|
171
|
+
(0, common_1.Injectable)(),
|
|
172
|
+
__metadata("design:paramtypes", [api_service_1.ApiService,
|
|
173
|
+
config_service_1.ConfigService,
|
|
174
|
+
docker_service_1.DockerService])
|
|
175
|
+
], LogService);
|
|
176
|
+
//# sourceMappingURL=log.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.service.js","sourceRoot":"","sources":["../../../src/agent/services/log.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ApiService } from './api.service';
|
|
2
|
+
import { ConfigService } from './config.service';
|
|
3
|
+
export declare class MachineService {
|
|
4
|
+
private apiService;
|
|
5
|
+
private configService;
|
|
6
|
+
private readonly logger;
|
|
7
|
+
constructor(apiService: ApiService, configService: ConfigService);
|
|
8
|
+
generateMachineKey(): string;
|
|
9
|
+
getOsInfo(): string;
|
|
10
|
+
getCurrentUser(): string;
|
|
11
|
+
getTailscaleIp(): Promise<string | null>;
|
|
12
|
+
private isValidIp;
|
|
13
|
+
registerMachine(): Promise<boolean>;
|
|
14
|
+
updateMachineStatus(status: 'live' | 'warning' | 'exit'): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
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 MachineService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MachineService = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const uuid_1 = require("uuid");
|
|
16
|
+
const os = require("os");
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const util_1 = require("util");
|
|
19
|
+
const api_service_1 = require("./api.service");
|
|
20
|
+
const config_service_1 = require("./config.service");
|
|
21
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
22
|
+
let MachineService = MachineService_1 = class MachineService {
|
|
23
|
+
constructor(apiService, configService) {
|
|
24
|
+
this.apiService = apiService;
|
|
25
|
+
this.configService = configService;
|
|
26
|
+
this.logger = new common_1.Logger(MachineService_1.name);
|
|
27
|
+
}
|
|
28
|
+
generateMachineKey() {
|
|
29
|
+
try {
|
|
30
|
+
return (0, uuid_1.v4)();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const hostname = os.hostname();
|
|
34
|
+
const timestamp = Date.now();
|
|
35
|
+
return `machine-${hostname}-${timestamp}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
getOsInfo() {
|
|
39
|
+
const osName = os.type();
|
|
40
|
+
if (osName === 'Darwin') {
|
|
41
|
+
return 'macOS';
|
|
42
|
+
}
|
|
43
|
+
return osName;
|
|
44
|
+
}
|
|
45
|
+
getCurrentUser() {
|
|
46
|
+
return os.userInfo().username;
|
|
47
|
+
}
|
|
48
|
+
async getTailscaleIp() {
|
|
49
|
+
try {
|
|
50
|
+
try {
|
|
51
|
+
const { stdout } = await execAsync('tailscale ip -4');
|
|
52
|
+
const ip = stdout.trim();
|
|
53
|
+
if (ip && this.isValidIp(ip)) {
|
|
54
|
+
this.logger.debug(`Found Tailscale IP via CLI: ${ip}`);
|
|
55
|
+
return ip;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
this.logger.debug('Tailscale CLI not available or failed, trying network interface');
|
|
60
|
+
}
|
|
61
|
+
const networkInterfaces = os.networkInterfaces();
|
|
62
|
+
const tailscaleInterface = networkInterfaces['tailscale0'];
|
|
63
|
+
if (tailscaleInterface) {
|
|
64
|
+
for (const addr of tailscaleInterface) {
|
|
65
|
+
const addrInfo = addr;
|
|
66
|
+
if (addrInfo && addrInfo.family && addrInfo.address) {
|
|
67
|
+
const isIPv4 = addrInfo.family === 'IPv4' ||
|
|
68
|
+
(typeof addrInfo.family === 'number' && addrInfo.family === 4);
|
|
69
|
+
if (isIPv4 && typeof addrInfo.address === 'string') {
|
|
70
|
+
this.logger.debug(`Found Tailscale IP via network interface: ${addrInfo.address}`);
|
|
71
|
+
return addrInfo.address;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const { stdout } = await execAsync('tailscale status --json');
|
|
78
|
+
const status = JSON.parse(stdout);
|
|
79
|
+
if (status.Self &&
|
|
80
|
+
status.Self.TailscaleIPs &&
|
|
81
|
+
status.Self.TailscaleIPs.length > 0) {
|
|
82
|
+
const ipv4 = status.Self.TailscaleIPs.find((ip) => !ip.includes(':'));
|
|
83
|
+
if (ipv4) {
|
|
84
|
+
this.logger.debug(`Found Tailscale IP via status: ${ipv4}`);
|
|
85
|
+
return ipv4;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.logger.debug('Tailscale status command failed');
|
|
91
|
+
}
|
|
92
|
+
this.logger.warn('Could not determine Tailscale IP address');
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
this.logger.error(`Error getting Tailscale IP: ${error.message}`);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
isValidIp(ip) {
|
|
101
|
+
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
102
|
+
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
103
|
+
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
|
104
|
+
}
|
|
105
|
+
async registerMachine() {
|
|
106
|
+
const machineKey = await this.configService.getMachineKey();
|
|
107
|
+
if (!machineKey) {
|
|
108
|
+
this.logger.error('Machine key not found in config');
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const osInfo = this.getOsInfo();
|
|
112
|
+
const userName = this.getCurrentUser();
|
|
113
|
+
const tailscaleIp = await this.getTailscaleIp();
|
|
114
|
+
const payload = {
|
|
115
|
+
key: machineKey,
|
|
116
|
+
os: osInfo,
|
|
117
|
+
user: userName,
|
|
118
|
+
};
|
|
119
|
+
if (tailscaleIp) {
|
|
120
|
+
payload.tailscale_ip = tailscaleIp;
|
|
121
|
+
}
|
|
122
|
+
this.logger.log(`Registering machine with key: ${machineKey}`);
|
|
123
|
+
const response = await this.apiService.callApi('POST', '/machines', payload, -1, 5000);
|
|
124
|
+
if (response) {
|
|
125
|
+
this.logger.log('Machine registered successfully');
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.logger.warn('Failed to register machine, will retry later');
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async updateMachineStatus(status) {
|
|
134
|
+
const machineKey = await this.configService.getMachineKey();
|
|
135
|
+
if (!machineKey) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const payload = { status };
|
|
139
|
+
await this.apiService.callApi('POST', `/machines/${machineKey}/status`, payload, -1, 5000);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
exports.MachineService = MachineService;
|
|
143
|
+
exports.MachineService = MachineService = MachineService_1 = __decorate([
|
|
144
|
+
(0, common_1.Injectable)(),
|
|
145
|
+
__metadata("design:paramtypes", [api_service_1.ApiService,
|
|
146
|
+
config_service_1.ConfigService])
|
|
147
|
+
], MachineService);
|
|
148
|
+
//# sourceMappingURL=machine.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.service.js","sourceRoot":"","sources":["../../../src/agent/services/machine.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,+BAAoC;AACpC,yBAAyB;AACzB,iDAAqC;AACrC,+BAAiC;AACjC,+CAA2C;AAC3C,qDAAiD;AAEjD,MAAM,SAAS,GAAG,IAAA,gBAAS,EAAC,oBAAI,CAAC,CAAC;AAG3B,IAAM,cAAc,sBAApB,MAAM,cAAc;IAGzB,YACU,UAAsB,EACtB,aAA4B;QAD5B,eAAU,GAAV,UAAU,CAAY;QACtB,kBAAa,GAAb,aAAa,CAAe;QAJrB,WAAM,GAAG,IAAI,eAAM,CAAC,gBAAc,CAAC,IAAI,CAAC,CAAC;IAKvD,CAAC;IAEJ,kBAAkB;QAChB,IAAI,CAAC;YACH,OAAO,IAAA,SAAM,GAAE,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAEf,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,OAAO,WAAW,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,SAAS;QACP,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,cAAc;QACZ,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,iBAAiB,CAAC,CAAC;gBACtD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBACzB,IAAI,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC;oBAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;oBACvD,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,iEAAiE,CAClE,CAAC;YACJ,CAAC;YAGD,MAAM,iBAAiB,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;YACjD,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;YAE3D,IAAI,kBAAkB,EAAE,CAAC;gBAGvB,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;oBAEtC,MAAM,QAAQ,GAAG,IAAW,CAAC;oBAC7B,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;wBACpD,MAAM,MAAM,GACV,QAAQ,CAAC,MAAM,KAAK,MAAM;4BAC1B,CAAC,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;wBACjE,IAAI,MAAM,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;4BACnD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,6CAA6C,QAAQ,CAAC,OAAO,EAAE,CAChE,CAAC;4BACF,OAAO,QAAQ,CAAC,OAAO,CAAC;wBAC1B,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAGD,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,yBAAyB,CAAC,CAAC;gBAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAClC,IACE,MAAM,CAAC,IAAI;oBACX,MAAM,CAAC,IAAI,CAAC,YAAY;oBACxB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EACnC,CAAC;oBAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CACxC,CAAC,EAAU,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAClC,CAAC;oBACF,IAAI,IAAI,EAAE,CAAC;wBACT,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;wBAC5D,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACvD,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,EAAU;QAE1B,MAAM,SAAS,GAAG,yBAAyB,CAAC;QAE5C,MAAM,SAAS,GAAG,0CAA0C,CAAC;QAC7D,OAAO,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC;QAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACrD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACvC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAEhD,MAAM,OAAO,GAAQ;YACnB,GAAG,EAAE,UAAU;YACf,EAAE,EAAE,MAAM;YACV,IAAI,EAAE,QAAQ;SACf,CAAC;QAEF,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,YAAY,GAAG,WAAW,CAAC;QACrC,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iCAAiC,UAAU,EAAE,CAAC,CAAC;QAE/D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAC5C,MAAM,EACN,WAAW,EACX,OAAO,EACP,CAAC,CAAC,EACF,IAAI,CACL,CAAC;QAEF,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YAEN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YACjE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB,CACvB,MAAmC;QAEnC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC;QAC5D,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC;QAE3B,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAC3B,MAAM,EACN,aAAa,UAAU,SAAS,EAChC,OAAO,EACP,CAAC,CAAC,EACF,IAAI,CACL,CAAC;IACJ,CAAC;CACF,CAAA;AAxKY,wCAAc;yBAAd,cAAc;IAD1B,IAAA,mBAAU,GAAE;qCAKW,wBAAU;QACP,8BAAa;GAL3B,cAAc,CAwK1B"}
|