This commit is contained in:
2026-03-10 19:18:46 +00:00
parent d8ee723dae
commit 33044fae23
14 changed files with 173 additions and 173 deletions
@@ -20,6 +20,10 @@ export default function ServiceCluster({ service }: Props) {
NormalizedServerObject | undefined
>(cluster_servers?.[0]);
const is_servers_odd_number = cluster_servers?.length
? Boolean(cluster_servers.length % 2)
: false;
return (
<Stack className="w-full grid-cell col-span-1 gap-0">
<Row className="nested-grid-frame xl:grid-cols-2">
@@ -33,6 +37,7 @@ export default function ServiceCluster({ service }: Props) {
/>
);
})}
{is_servers_odd_number ? <div className="grid-cell" /> : null}
</Row>
{/* <Row className="p-4">
@@ -30,23 +30,20 @@ export default function ServiceClusters() {
const cluster_servers = targetCluster?.servers;
const [targetServer, setTargetServer] = useState<
NormalizedServerObject | undefined
>(cluster_servers?.[0]);
// const [targetServer, setTargetServer] = useState<
// NormalizedServerObject | undefined
// >(cluster_servers?.[0]);
function killAllPorts(port: number) {
function killAllPorts() {
ws.sendData({
event: "client:kill-port",
server: targetServer,
service: _.omit(service, ["servers"]),
port,
event: "client:kill-all-ports",
});
}
return (
<Stack className="w-full nested-grid-frame grid-cols-1">
<Stack className="grid-cell gap-0">
<Row className="p-4 flex-nowrap">
<Row className="grid-cell-content flex-nowrap">
<Row className="w-full justify-between">
<Row>
<H2>Cluster #{clusterIndex}</H2>
@@ -62,6 +59,7 @@ export default function ServiceClusters() {
}}
changeHandler={(v) => {
setTargetCluster(undefined);
killAllPorts();
setTimeout(() => {
setTargetCluster(
all_services.find(
+14
View File
@@ -39,6 +39,20 @@ const schema = {
},
],
},
{
tableName: "users_ports",
fields: [
{
fieldName: "user_id",
dataType: "INTEGER",
},
{
fieldName: "port",
dataType: "INTEGER",
unique: true,
},
],
},
],
};
+19 -1
View File
@@ -1,5 +1,6 @@
export const NSQLiteTables = [
"users",
"users_ports",
] as const
export type NSQLITE_TEST_DB_USERS = {
@@ -24,4 +25,21 @@ export type NSQLITE_TEST_DB_USERS = {
is_super_admin?: number;
}
export type NSQLITE_TEST_DB_ALL_TYPEDEFS = NSQLITE_TEST_DB_USERS
export type NSQLITE_TEST_DB_USERS_PORTS = {
/**
* The unique identifier of the record.
*/
id?: number;
/**
* The time when the record was created. (Unix Timestamp)
*/
created_at?: number;
/**
* The time when the record was updated. (Unix Timestamp)
*/
updated_at?: number;
user_id?: number;
port?: number;
}
export type NSQLITE_TEST_DB_ALL_TYPEDEFS = NSQLITE_TEST_DB_USERS & NSQLITE_TEST_DB_USERS_PORTS
+13 -2
View File
@@ -1,4 +1,4 @@
import { AppData } from "@/src/data/app-data";
import { NSQLITE_TEST_DB_USERS_PORTS, NSQLiteTables } from "@/src/db/types";
import {
NormalizedServerObject,
ParsedDeploymentServiceConfig,
@@ -11,6 +11,7 @@ import getNextAvailablePort from "@/src/utils/grab-next-available-port";
import grabSSHPrefix from "@/src/utils/grab-ssh-prefix";
import grabTtydCmd from "@/src/utils/grab-ttyd-cmd";
import grabConnectedWebsocketUserdata from "@/src/websocket/(utils)/grab-connected-websocket-user-data";
import BunSQLite from "@moduletrace/bun-sqlite";
import { exec } from "child_process";
const { TURBOCI_SSH_KEY_FILE } = grabDirNames();
@@ -37,7 +38,9 @@ export default async function grabTtydServerInfo({
const final_log = passed_log_cmd || final_first_log;
if (paradigm == "logs" && !final_log) {
throw new Error(`Service Doesn't have logs.`);
throw new Error(
`Service \`${service?.service_name}\` Doesn't have logs.`,
);
}
const available_port = getNextAvailablePort();
@@ -70,6 +73,14 @@ export default async function grabTtydServerInfo({
const connected_user_data = grabConnectedWebsocketUserdata({ user });
await BunSQLite.insert<
NSQLITE_TEST_DB_USERS_PORTS,
(typeof NSQLiteTables)[number]
>({
data: [{ user_id: user.id, port: available_port }],
table: "users_ports",
});
connected_user_data.child_processes.push(ttyd_exec);
connected_user_data.ports.push(available_port);
+8
View File
@@ -14,4 +14,12 @@ export const AdminAsideLinks: (
title: "Services",
url: "/admin/services",
},
{
title: "Users",
url: "/admin/users",
},
{
title: "Settings",
url: "/admin/settings",
},
];
+10
View File
@@ -0,0 +1,10 @@
import Layout from "@/src/layouts/login";
import H2 from "@/twui/components/layout/H2";
export default function PageNotFound() {
return (
<Layout>
<H2>Page Not Found!</H2>
</Layout>
);
}
+2 -2
View File
@@ -70,9 +70,9 @@ export default async function relayExecSSH({
}
let relayCmd = ``;
relayCmd += `/bin/bash << 'EOF'\n`;
relayCmd += `/bin/bash << 'TURBOCIRELAYEXECEOF'\n`;
relayCmd += `${relaySh}\n`;
relayCmd += `EOF\n`;
relayCmd += `TURBOCIRELAYEXECEOF\n`;
if (detached) {
exec(relayCmd);
+39 -8
View File
@@ -1,20 +1,51 @@
import { AppData } from "@/src/data/app-data";
import { NSQLITE_TEST_DB_USERS_PORTS, NSQLiteTables } from "@/src/db/types";
import { User } from "@/src/types";
import BunSQLite from "@moduletrace/bun-sqlite";
import { execSync, ExecSyncOptions } from "child_process";
import killPort from "./kill-port";
type Params = {
exec_options?: ExecSyncOptions;
user: User;
};
export default async function killAllTtydPorts(params?: Params) {
const start_port = AppData["DynamicPortStart"];
const end_port = start_port + 100;
const kill_ports_cmd = `ss -tlnp | awk 'NR>1 {split($4, a, ":"); port=a[length(a)]; if (port >= ${start_port} && port <= ${end_port}) print $6}' | grep -oP 'pid=\\K[0-9]+' | xargs -r kill -9`;
execSync(kill_ports_cmd, {
...params?.exec_options,
export default async function killAllTtydPorts({ user }: Params) {
const user_ports_res = await BunSQLite.select<
NSQLITE_TEST_DB_USERS_PORTS,
(typeof NSQLiteTables)[number]
>({
table: "users_ports",
query: { query: { user_id: { value: String(user.id) } } },
});
if (user_ports_res?.payload?.[0]) {
for (let i = 0; i < user_ports_res.payload.length; i++) {
const user_port = user_ports_res.payload[i];
if (!user_port.port) {
continue;
}
await killPort({ port: user_port.port });
await BunSQLite.delete<
NSQLITE_TEST_DB_USERS_PORTS,
(typeof NSQLiteTables)[number]
>({
table: "users_ports",
query: { query: { port: { value: String(user_port.port) } } },
});
}
}
}
// const start_port = AppData["DynamicPortStart"];
// const end_port = start_port + 100;
// const kill_ports_cmd = `ss -tlnp | awk 'NR>1 {split($4, a, ":"); port=a[length(a)]; if (port >= ${start_port} && port <= ${end_port}) print $6}' | grep -oP 'pid=\\K[0-9]+' | xargs -r kill -9`;
// execSync(kill_ports_cmd, {
// ...exec_options,
// });
// sudo ss -tlnp | awk 'NR>1 {split($4, a, ":"); port=a[length(a)]; if (port >= 4700 && port <= 4800) print $6}' | grep -oP 'pid=\K[0-9]+' | xargs -r sudo kill -9
// ss -tlnp | awk 'NR>1 {split($4, a, ":"); port=a[length(a)]; if (port >= 4700 && port <= 4800) print $6}' | grep -oP 'pid=\K[0-9]+' | xargs -r sudo kill -9
+2 -14
View File
@@ -1,8 +1,7 @@
import { WebSocketMessageParam } from "@/src/types";
import sendData from "../(utils)/send-data";
import sendError from "../(utils)/send-error";
import grabConnectedWebsocketUserdata from "../(utils)/grab-connected-websocket-user-data";
import killPort from "../(utils)/kill-port";
import killAllTtydPorts from "../(utils)/kill-all-ttyd-ports";
export default async function socketClientKillAllPorts({
ws,
@@ -11,18 +10,7 @@ export default async function socketClientKillAllPorts({
try {
const user = ws.data.user;
const connected_user_data = grabConnectedWebsocketUserdata({ user });
for (let i = 0; i < connected_user_data.ports.length; i++) {
const port = connected_user_data.ports[i];
if (port) {
await killPort({ port, exec_options: { stdio: "inherit" } });
connected_user_data.ports = connected_user_data.ports.filter(
(p) => p != port,
);
}
}
await killAllTtydPorts({ user });
sendData(ws, {
event: "server:killed-all-ports",
+1 -3
View File
@@ -27,7 +27,5 @@ export default async function socketClose({ ws }: Param) {
existing_connected_user_data.child_processes = [];
}
killAllTtydPorts({
exec_options: { stdio: "inherit" },
});
killAllTtydPorts({ user });
}