// @ts-check
/**
* @import {ExpressRequestAuthorized, ExpressResponse} from '../../types.js'
*/
import { sendOk, sendErrorFrom } from '../../utils/apiEnvelope.js';
import * as service from './service.js';
/**
* GET /api/nodes?role=&group_uid=
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const listNodes = async (req, res) => {
try {
const role = typeof req.query?.role === 'string' && req.query.role ? req.query.role : undefined;
const groupUid =
typeof req.query?.group_uid === 'string' && req.query.group_uid
? req.query.group_uid
: undefined;
sendOk(res, await service.listNodes(req, { role, groupUid }));
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* POST /api/nodes — neuen Node anlegen (role=runner|gateway|dev-pc).
* Runner verlangen `publicKey`; Gateways/Dev-PCs nicht.
*/
export const createNode = async (req, res) => {
try {
const result = await service.createNode(req, req.body || {});
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* POST /api/nodes/upsert — idempotenter Sync aus dem project-bot.
*
* Legt Gateway/Dev-PC/Runner als Node-Objekt an bzw. zieht Tailnet-Fakten nach
* (Match über `tailnetNodeId` → `hostname` → `tailnetIp`). Die Rolle eines
* bestehenden Objekts wird nie überschrieben; ein neues erbt die Sichtbarkeit
* seines Netzes. Bewusst kein `checkObjectAdmin`: das Objekt entsteht ggf.
* erst — der Service prüft die Sichtbarkeit des Netzes.
*/
export const upsertNode = async (req, res) => {
try {
const result = await service.upsertNodeByHostname(req, req.body || {});
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* GET /api/nodes/:UID
*/
export const getNode = async (req, res) => {
try {
const result = await service.getNode(req, req.params.UID);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* POST /api/nodes/:UID — Data/Netzbindung ändern.
*/
export const updateNode = async (req, res) => {
try {
const result = await service.updateNode(req, req.params.UID, req.body || {});
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* POST /api/nodes/:UID/revoke
*/
export const revokeNode = async (req, res) => {
try {
const result = await service.revokeNode(req, req.params.UID);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* POST /api/nodes/:UID/drain
*/
export const drainNode = async (req, res) => {
try {
const result = await service.drainNode(req, req.params.UID);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* DELETE /api/nodes/:UID
* Hard-delete (cleanup; `revoke` ist der Soft-Pfad).
*/
export const deleteNode = async (req, res) => {
try {
const result = await service.deleteNode(req, req.params.UID);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};