Merge pull request 'add meshcentral skeletons in UI' (#2) from feat/meshcentral into main
Reviewed-on: http://203.171.20.94:3000/PhuongDM/TTMT.ManageWebGUI/pulls/2
This commit is contained in:
commit
0d9a1ec002
1086
INTEGRATION_GUIDE_VI.md
Normal file
1086
INTEGRATION_GUIDE_VI.md
Normal file
File diff suppressed because it is too large
Load Diff
0
src/routes/_auth/rooms/$roomName/connect/index.tsx
Normal file
0
src/routes/_auth/rooms/$roomName/connect/index.tsx
Normal file
|
|
@ -15,3 +15,6 @@ export * as permissionService from "./permission.service";
|
||||||
|
|
||||||
// Role API Services
|
// Role API Services
|
||||||
export * as roleService from "./role.service";
|
export * as roleService from "./role.service";
|
||||||
|
|
||||||
|
// Mesh Central API Services
|
||||||
|
export * as meshCentralService from "./meshcentral.service";
|
||||||
310
src/services/meshcentral.service.ts
Normal file
310
src/services/meshcentral.service.ts
Normal file
|
|
@ -0,0 +1,310 @@
|
||||||
|
// services/meshcentral.service.ts
|
||||||
|
export interface MeshCentralConfig {
|
||||||
|
serverUrl: string;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
domain?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeviceGroup {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
desc: string;
|
||||||
|
mtype: number; // 1: FreeAgent, 2: IntelAMT, 3: Mixed
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Device {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
meshid: string;
|
||||||
|
host: string;
|
||||||
|
state: string; // online, offline, unknown
|
||||||
|
rname?: string; // remote name
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MeshCentralService {
|
||||||
|
private ws: WebSocket | null = null;
|
||||||
|
private messageId = 1;
|
||||||
|
private pendingRequests = new Map<number, {
|
||||||
|
resolve: (value: any) => void;
|
||||||
|
reject: (error: any) => void;
|
||||||
|
timeout: ReturnType<typeof setTimeout>;
|
||||||
|
}>();
|
||||||
|
private messageHandlers = new Map<string, (data: any) => void>();
|
||||||
|
|
||||||
|
constructor(private config: MeshCentralConfig) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kết nối đến MeshCentral Server
|
||||||
|
*/
|
||||||
|
async connect(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const wsUrl = `${this.config.serverUrl.replace(/^http/, 'ws')}/control.ashx`;
|
||||||
|
this.ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
this.ws.onopen = () => {
|
||||||
|
console.log('Connected to MeshCentral');
|
||||||
|
this.authenticate().then(resolve).catch(reject);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onmessage = (event) => this.handleMessage(event.data);
|
||||||
|
this.ws.onerror = (error) => {
|
||||||
|
console.error('WebSocket error:', error);
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
this.ws.onclose = () => {
|
||||||
|
console.log('Disconnected from MeshCentral');
|
||||||
|
this.ws = null;
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Xác thực với server
|
||||||
|
*/
|
||||||
|
private async authenticate(): Promise<void> {
|
||||||
|
const authMessage = {
|
||||||
|
action: 'authCookie',
|
||||||
|
username: this.config.username,
|
||||||
|
password: this.config.password,
|
||||||
|
domain: this.config.domain || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.sendMessage(authMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gửi message và chờ response
|
||||||
|
*/
|
||||||
|
private async sendMessage(message: any): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
reject(new Error('WebSocket not connected'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const msgId = this.messageId++;
|
||||||
|
message.sessionid = msgId;
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
this.pendingRequests.delete(msgId);
|
||||||
|
reject(new Error('Request timeout'));
|
||||||
|
}, 30000); // 30 seconds timeout
|
||||||
|
|
||||||
|
this.pendingRequests.set(msgId, { resolve, reject, timeout });
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.ws.send(JSON.stringify(message));
|
||||||
|
} catch (error) {
|
||||||
|
this.pendingRequests.delete(msgId);
|
||||||
|
clearTimeout(timeout);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Xử lý incoming messages
|
||||||
|
*/
|
||||||
|
private handleMessage(data: string): void {
|
||||||
|
try {
|
||||||
|
const message = JSON.parse(data);
|
||||||
|
|
||||||
|
// Handle response to pending request
|
||||||
|
if (message.sessionid && this.pendingRequests.has(message.sessionid)) {
|
||||||
|
const { resolve, reject, timeout } = this.pendingRequests.get(message.sessionid)!;
|
||||||
|
this.pendingRequests.delete(message.sessionid);
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
|
if (message.error) {
|
||||||
|
reject(new Error(message.error));
|
||||||
|
} else {
|
||||||
|
resolve(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle event handlers
|
||||||
|
if (message.action && this.messageHandlers.has(message.action)) {
|
||||||
|
const handler = this.messageHandlers.get(message.action)!;
|
||||||
|
handler(message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing message:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Đăng ký handler cho event
|
||||||
|
*/
|
||||||
|
on(action: string, handler: (data: any) => void): void {
|
||||||
|
this.messageHandlers.set(action, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === TẠIDEVICE GROUP ===
|
||||||
|
* Tạo một device group (Mesh) mới
|
||||||
|
*/
|
||||||
|
async createDeviceGroup(name: string, desc: string = ''): Promise<DeviceGroup> {
|
||||||
|
const response = await this.sendMessage({
|
||||||
|
action: 'createmesh',
|
||||||
|
meshname: name,
|
||||||
|
meshdesc: desc,
|
||||||
|
meshtype: 2 // 2 = Window
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
throw new Error(`Failed to create device group: ${response.error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.meshid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lấy danh sách device groups
|
||||||
|
*/
|
||||||
|
async getDeviceGroups(): Promise<DeviceGroup[]> {
|
||||||
|
const response = await this.sendMessage({
|
||||||
|
action: 'meshes'
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.meshes || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === THÊM DEVICE ===
|
||||||
|
* Lấy Agent invite link để install trên device
|
||||||
|
*/
|
||||||
|
async getAgentInviteLink(meshId: string, platform: string = 'linux'): Promise<string> {
|
||||||
|
const response = await this.sendMessage({
|
||||||
|
action: 'getmesh',
|
||||||
|
meshid: meshId
|
||||||
|
});
|
||||||
|
|
||||||
|
// Agent download URL format:
|
||||||
|
// /meshagents?id=<meshid>&installflags=<flags>&exeType=<type>
|
||||||
|
const flags = 0; // Windows install flags
|
||||||
|
return `/meshagents?id=4&meshid=${meshId}&installflags=${flags}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lấy danh sách devices trong group
|
||||||
|
*/
|
||||||
|
async getDevices(meshId: string): Promise<Device[]> {
|
||||||
|
const response = await this.sendMessage({
|
||||||
|
action: 'getmesh',
|
||||||
|
meshid: meshId
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.nodes || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === QUẢN LÝ DEVICE ===
|
||||||
|
* Vô hiệu hóa/kích hoạt device
|
||||||
|
*/
|
||||||
|
async setDeviceState(deviceId: string, enabled: boolean): Promise<void> {
|
||||||
|
await this.sendMessage({
|
||||||
|
action: 'changedevice',
|
||||||
|
nodeid: deviceId,
|
||||||
|
enabled: enabled
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Xóa device khỏi group
|
||||||
|
*/
|
||||||
|
async removeDevice(deviceId: string): Promise<void> {
|
||||||
|
await this.sendMessage({
|
||||||
|
action: 'removenode',
|
||||||
|
nodeids: [deviceId]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === QUẢN LÝ NGƯỜI DÙNG ===
|
||||||
|
* Tạo user mới
|
||||||
|
*/
|
||||||
|
async createUser(username: string, password: string, email?: string): Promise<any> {
|
||||||
|
const response = await this.sendMessage({
|
||||||
|
action: 'createuser',
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
email: email || ''
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gán quyền truy cập device group cho user
|
||||||
|
* rights: bitmask của permissions
|
||||||
|
* - 1: Edit mesh
|
||||||
|
* - 2: Manage users
|
||||||
|
* - 4: Manage computers
|
||||||
|
* - 8: Remote control
|
||||||
|
* - 16: Agent console
|
||||||
|
* - 32: Server files
|
||||||
|
* - 64: Wake device
|
||||||
|
* - 128: Set notes
|
||||||
|
* - 256: Remote view only
|
||||||
|
*/
|
||||||
|
async addUserToMesh(meshId: string, username: string, rights: number): Promise<void> {
|
||||||
|
await this.sendMessage({
|
||||||
|
action: 'editmesh',
|
||||||
|
meshid: meshId,
|
||||||
|
usernames: [username],
|
||||||
|
rights: rights
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === ĐIỀU KHIỂN THIẾT BỊ ===
|
||||||
|
* Gửi command đến device
|
||||||
|
*/
|
||||||
|
async sendDeviceCommand(deviceId: string, command: string, parameters?: any): Promise<any> {
|
||||||
|
return this.sendMessage({
|
||||||
|
action: 'runcommand',
|
||||||
|
nodeid: deviceId,
|
||||||
|
command: command,
|
||||||
|
params: parameters || {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Khởi động lại device
|
||||||
|
*/
|
||||||
|
async rebootDevice(deviceId: string): Promise<void> {
|
||||||
|
await this.sendMessage({
|
||||||
|
action: 'poweraction',
|
||||||
|
nodeid: deviceId,
|
||||||
|
actiontype: 1 // 1 = reboot
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tắt device
|
||||||
|
*/
|
||||||
|
async shutdownDevice(deviceId: string): Promise<void> {
|
||||||
|
await this.sendMessage({
|
||||||
|
action: 'poweraction',
|
||||||
|
nodeid: deviceId,
|
||||||
|
actiontype: 2 // 2 = shutdown
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect user session từ MeshCentral
|
||||||
|
*/
|
||||||
|
disconnect(): void {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
this.ws = null;
|
||||||
|
}
|
||||||
|
this.pendingRequests.clear();
|
||||||
|
this.messageHandlers.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user