mirror of
https://github.com/louislam/dockge.git
synced 2024-11-27 21:24:02 +00:00
WIP
This commit is contained in:
parent
37f261480a
commit
7d91c8d037
9 changed files with 153 additions and 14 deletions
|
@ -2,7 +2,9 @@ import { DockgeSocket } from "./util-server";
|
||||||
import { io, Socket as SocketClient } from "socket.io-client";
|
import { io, Socket as SocketClient } from "socket.io-client";
|
||||||
import { log } from "./log";
|
import { log } from "./log";
|
||||||
import { Agent } from "./models/agent";
|
import { Agent } from "./models/agent";
|
||||||
import { LooseObject } from "../common/util-common";
|
import { isDev, LooseObject } from "../common/util-common";
|
||||||
|
import semver from "semver";
|
||||||
|
import { R } from "redbean-node";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dockge Instance Manager
|
* Dockge Instance Manager
|
||||||
|
@ -16,6 +18,74 @@ export class AgentManager {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test(url : string, username : string, password : string) : Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let obj = new URL(url);
|
||||||
|
let endpoint = obj.host;
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
|
reject(new Error("Invalid Dockge URL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.instanceSocketList[endpoint]) {
|
||||||
|
reject(new Error("The Dockge URL already exists"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let client = io(url, {
|
||||||
|
reconnection: false,
|
||||||
|
extraHeaders: {
|
||||||
|
endpoint,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("connect", () => {
|
||||||
|
client.emit("login", {
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
}, (res : LooseObject) => {
|
||||||
|
if (res.ok) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(new Error(res.msg));
|
||||||
|
}
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("connect_error", (err) => {
|
||||||
|
if (err.message === "xhr poll error") {
|
||||||
|
reject(new Error("Unable to connect to the Dockge instance"));
|
||||||
|
} else {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
client.disconnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
*/
|
||||||
|
async add(url : string, username : string, password : string) : Promise<Agent> {
|
||||||
|
let bean = R.dispense("agent") as Agent;
|
||||||
|
bean.url = url;
|
||||||
|
bean.username = username;
|
||||||
|
bean.password = password;
|
||||||
|
await R.store(bean);
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param endpoint
|
||||||
|
*/
|
||||||
|
remove(endpoint : string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
connect(url : string, username : string, password : string) {
|
connect(url : string, username : string, password : string) {
|
||||||
let obj = new URL(url);
|
let obj = new URL(url);
|
||||||
let endpoint = obj.host;
|
let endpoint = obj.host;
|
||||||
|
@ -48,7 +118,7 @@ export class AgentManager {
|
||||||
client.emit("login", {
|
client.emit("login", {
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
}, (res) => {
|
}, (res : LooseObject) => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
log.info("agent-manager", "Logged in to the socket server: " + endpoint);
|
log.info("agent-manager", "Logged in to the socket server: " + endpoint);
|
||||||
this.socket.emit("agentStatus", {
|
this.socket.emit("agentStatus", {
|
||||||
|
@ -65,9 +135,9 @@ export class AgentManager {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on("error", (err) => {
|
client.on("connect_error", (err) => {
|
||||||
log.error("agent-manager", "Error from the socket server: " + endpoint);
|
log.error("agent-manager", "Error from the socket server: " + endpoint);
|
||||||
log.error("agent-manager", err);
|
log.debug("agent-manager", err);
|
||||||
this.socket.emit("agentStatus", {
|
this.socket.emit("agentStatus", {
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
status: "offline",
|
status: "offline",
|
||||||
|
@ -87,6 +157,20 @@ export class AgentManager {
|
||||||
this.socket.emit("agent", ...args);
|
this.socket.emit("agent", ...args);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
client.on("info", (res) => {
|
||||||
|
log.debug("agent-manager", res);
|
||||||
|
|
||||||
|
// Disconnect if the version is lower than 1.4.0
|
||||||
|
if (!isDev && semver.satisfies(res.version, "< 1.4.0")) {
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "offline",
|
||||||
|
msg: `${endpoint}: Unsupported version: ` + res.version,
|
||||||
|
});
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.instanceSocketList[endpoint] = client;
|
this.instanceSocketList[endpoint] = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ export class DockgeServer {
|
||||||
let obj2 = obj as LooseObject;
|
let obj2 = obj as LooseObject;
|
||||||
obj2.endpoint = dockgeSocket.endpoint;
|
obj2.endpoint = dockgeSocket.endpoint;
|
||||||
}
|
}
|
||||||
this.io.to(dockgeSocket.userID + "").emit("agent", event, ...args);
|
dockgeSocket.emit("agent", event, ...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof(socket.request.headers.endpoint) === "string") {
|
if (typeof(socket.request.headers.endpoint) === "string") {
|
||||||
|
@ -601,7 +601,7 @@ export class DockgeServer {
|
||||||
map.set(stackName, stack.toSimpleJSON(dockgeSocket.endpoint));
|
map.set(stackName, stack.toSimpleJSON(dockgeSocket.endpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("server", "Send stack list");
|
log.debug("server", "Send stack list to user: " + dockgeSocket.id + " (" + dockgeSocket.endpoint + ")");
|
||||||
dockgeSocket.emitAgent("stackList", {
|
dockgeSocket.emitAgent("stackList", {
|
||||||
ok: true,
|
ok: true,
|
||||||
stackList: Object.fromEntries(map),
|
stackList: Object.fromEntries(map),
|
||||||
|
|
|
@ -1,13 +1,46 @@
|
||||||
import { SocketHandler } from "../socket-handler.js";
|
import { SocketHandler } from "../socket-handler.js";
|
||||||
import { DockgeServer } from "../dockge-server";
|
import { DockgeServer } from "../dockge-server";
|
||||||
import { log } from "../log";
|
import { log } from "../log";
|
||||||
import { checkLogin, DockgeSocket } from "../util-server";
|
import { callbackError, checkLogin, DockgeSocket } from "../util-server";
|
||||||
import { AgentSocket } from "../../common/agent-socket";
|
|
||||||
import { ALL_ENDPOINTS } from "../../common/util-common";
|
|
||||||
|
|
||||||
export class ManageAgentSocketHandler extends SocketHandler {
|
export class ManageAgentSocketHandler extends SocketHandler {
|
||||||
|
|
||||||
create(socket : DockgeSocket, server : DockgeServer) {
|
create(socket : DockgeSocket, server : DockgeServer) {
|
||||||
|
// addAgent
|
||||||
|
socket.on("addAgent", async (data : unknown, callback : unknown) => {
|
||||||
|
try {
|
||||||
|
log.debug("manage-agent-socket-handler", "addAgent");
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
let manager = socket.instanceManager;
|
||||||
|
await manager.test(data.url, data.username, data.password);
|
||||||
|
await manager.add(data.url, data.username, data.password);
|
||||||
|
|
||||||
|
// connect to the agent
|
||||||
|
manager.connect(data.url, data.username, data.password);
|
||||||
|
|
||||||
|
manager.sendAgentList();
|
||||||
|
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "agentAddedSuccessfully",
|
||||||
|
msgi18n: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
callbackError(e, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// removeAgent
|
||||||
|
socket.on("removeAgent", async (data : unknown, callback : unknown) => {
|
||||||
|
try {
|
||||||
|
log.debug("manage-agent-socket-handler", "removeAgent");
|
||||||
|
checkLogin(socket);
|
||||||
|
await socket.instanceManager.remove(data.endpoint);
|
||||||
|
} catch (e) {
|
||||||
|
callbackError(e, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,14 @@ export function callbackError(error : unknown, callback : unknown) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: error.message,
|
msg: error.message,
|
||||||
|
msgi18n: true,
|
||||||
});
|
});
|
||||||
} else if (error instanceof ValidationError) {
|
} else if (error instanceof ValidationError) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
type: ERROR_TYPE_VALIDATION,
|
type: ERROR_TYPE_VALIDATION,
|
||||||
msg: error.message,
|
msg: error.message,
|
||||||
|
msgi18n: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log.debug("console", "Unknown error: " + error);
|
log.debug("console", "Unknown error: " + error);
|
||||||
|
|
|
@ -107,5 +107,6 @@
|
||||||
"agentOffline": "Offline",
|
"agentOffline": "Offline",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"connect": "Connect",
|
"connect": "Connect",
|
||||||
"addAgent": "Add Agent"
|
"addAgent": "Add Agent",
|
||||||
|
"agentAddedSuccessfully": "Agent added successfully."
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,10 @@ export default defineComponent({
|
||||||
|
|
||||||
socket.on("agentStatus", (res) => {
|
socket.on("agentStatus", (res) => {
|
||||||
this.agentStatusList[res.endpoint] = res.status;
|
this.agentStatusList[res.endpoint] = res.status;
|
||||||
|
|
||||||
|
if (res.msg) {
|
||||||
|
this.toastError(res.msg);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("agentList", (res) => {
|
socket.on("agentList", (res) => {
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
<span v-if="endpoint === ''">{{ $t("currentEndpoint") }}</span>
|
<span v-if="endpoint === ''">{{ $t("currentEndpoint") }}</span>
|
||||||
<span v-else>{{ endpoint }}</span>
|
<span v-else>{{ endpoint }}</span>
|
||||||
|
|
||||||
|
<!-- Remove Button -->
|
||||||
<font-awesome-icon v-if="endpoint !== ''" class="ms-2 remove-agent" icon="trash" @click="removeAgent(agent.url)" />
|
<font-awesome-icon v-if="endpoint !== ''" class="ms-2 remove-agent" icon="trash" @click="removeAgent(agent.url)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -74,7 +75,10 @@
|
||||||
<input id="password" v-model="agent.password" type="password" class="form-control" required autocomplete="new-password">
|
<input id="password" v-model="agent.password" type="password" class="form-control" required autocomplete="new-password">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-normal">{{ $t("connect") }}</button>
|
<button type="submit" class="btn btn-primary" :disabled="connectingAgent">
|
||||||
|
<template v-if="connectingAgent">{{ $t("connecting") }}</template>
|
||||||
|
<template v-else>{{ $t("connect") }}</template>
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,6 +114,7 @@ export default {
|
||||||
displayedRecords: [],
|
displayedRecords: [],
|
||||||
dockerRunCommand: "",
|
dockerRunCommand: "",
|
||||||
showAgentForm: false,
|
showAgentForm: false,
|
||||||
|
connectingAgent: false,
|
||||||
agent: {
|
agent: {
|
||||||
url: "http://",
|
url: "http://",
|
||||||
username: "",
|
username: "",
|
||||||
|
@ -156,14 +161,16 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
addAgent() {
|
addAgent() {
|
||||||
|
this.connectingAgent = true;
|
||||||
this.$root.getSocket().emit("addAgent", this.agent, (res) => {
|
this.$root.getSocket().emit("addAgent", this.agent, (res) => {
|
||||||
if (res.ok) {
|
|
||||||
this.$root.toastRes(res);
|
this.$root.toastRes(res);
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
this.showAgentForm = false;
|
this.showAgentForm = false;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
this.showAgentForm = false;
|
this.connectingAgent = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
removeAgent(url) {
|
removeAgent(url) {
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
"mysql2": "~3.6.5",
|
"mysql2": "~3.6.5",
|
||||||
"promisify-child-process": "~4.1.2",
|
"promisify-child-process": "~4.1.2",
|
||||||
"redbean-node": "~0.3.3",
|
"redbean-node": "~0.3.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
"socket.io": "~4.7.2",
|
"socket.io": "~4.7.2",
|
||||||
"socket.io-client": "~4.7.2",
|
"socket.io-client": "~4.7.2",
|
||||||
"timezones-list": "~3.0.2",
|
"timezones-list": "~3.0.2",
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
"@types/command-exists": "~1.2.3",
|
"@types/command-exists": "~1.2.3",
|
||||||
"@types/express": "~4.17.21",
|
"@types/express": "~4.17.21",
|
||||||
"@types/jsonwebtoken": "~9.0.5",
|
"@types/jsonwebtoken": "~9.0.5",
|
||||||
|
"@types/semver": "^7.5.6",
|
||||||
"@typescript-eslint/eslint-plugin": "~6.8.0",
|
"@typescript-eslint/eslint-plugin": "~6.8.0",
|
||||||
"@typescript-eslint/parser": "~6.8.0",
|
"@typescript-eslint/parser": "~6.8.0",
|
||||||
"@vitejs/plugin-vue": "~4.5.2",
|
"@vitejs/plugin-vue": "~4.5.2",
|
||||||
|
|
|
@ -68,6 +68,9 @@ dependencies:
|
||||||
redbean-node:
|
redbean-node:
|
||||||
specifier: ~0.3.3
|
specifier: ~0.3.3
|
||||||
version: 0.3.3(mysql2@3.6.5)
|
version: 0.3.3(mysql2@3.6.5)
|
||||||
|
semver:
|
||||||
|
specifier: ^7.5.4
|
||||||
|
version: 7.5.4
|
||||||
socket.io:
|
socket.io:
|
||||||
specifier: ~4.7.2
|
specifier: ~4.7.2
|
||||||
version: 4.7.2
|
version: 4.7.2
|
||||||
|
@ -124,6 +127,9 @@ devDependencies:
|
||||||
'@types/jsonwebtoken':
|
'@types/jsonwebtoken':
|
||||||
specifier: ~9.0.5
|
specifier: ~9.0.5
|
||||||
version: 9.0.5
|
version: 9.0.5
|
||||||
|
'@types/semver':
|
||||||
|
specifier: ^7.5.6
|
||||||
|
version: 7.5.6
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ~6.8.0
|
specifier: ~6.8.0
|
||||||
version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.50.0)(typescript@5.2.2)
|
version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.50.0)(typescript@5.2.2)
|
||||||
|
|
Loading…
Reference in a new issue