mirror of
https://github.com/mblanke/Dashboard.git
synced 2026-03-01 20:10:20 -05:00
Initial commit: ATLAS Dashboard (Next.js)
This commit is contained in:
62
src/app/api/containers/route.ts
Normal file
62
src/app/api/containers/route.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import Docker from "dockerode";
|
||||
|
||||
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
|
||||
const enriched = await Promise.all(
|
||||
containers.map(async (c: any) => {
|
||||
let statsText = "";
|
||||
let cpu = "0%";
|
||||
let memory = "0 MB";
|
||||
|
||||
if (c.State === "running") {
|
||||
try {
|
||||
const container = docker.getContainer(c.Id);
|
||||
const stats = await container.stats({ stream: false });
|
||||
|
||||
const cpuDelta =
|
||||
stats.cpu_stats?.cpu_usage?.total_usage -
|
||||
(stats.precpu_stats?.cpu_usage?.total_usage || 0);
|
||||
const systemDelta =
|
||||
stats.cpu_stats?.system_cpu_usage -
|
||||
(stats.precpu_stats?.system_cpu_usage || 0);
|
||||
const online = stats.cpu_stats?.online_cpus || 1;
|
||||
const cpuPercent = systemDelta > 0 ? (cpuDelta / systemDelta) * 100 * online : 0;
|
||||
|
||||
const memUsage = stats.memory_stats?.usage || 0;
|
||||
const memLimit = stats.memory_stats?.limit || 0;
|
||||
const memMB = (memUsage / 1024 / 1024).toFixed(1);
|
||||
const memLimitMB = (memLimit / 1024 / 1024).toFixed(0);
|
||||
|
||||
cpu = `${cpuPercent.toFixed(1)}%`;
|
||||
memory = `${memMB} MB / ${memLimitMB} MB`;
|
||||
statsText = `${cpu}, ${memory}`;
|
||||
} catch (err) {
|
||||
statsText = "n/a";
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: c.Id.slice(0, 12),
|
||||
name: c.Names?.[0]?.replace(/^\//, "") || "unknown",
|
||||
image: c.Image,
|
||||
state: c.State,
|
||||
status: c.Status,
|
||||
ports: c.Ports || [],
|
||||
cpu,
|
||||
memory,
|
||||
stats: statsText,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return NextResponse.json(enriched);
|
||||
} catch (error) {
|
||||
console.error("Containers API error:", error);
|
||||
return NextResponse.json({ error: "Failed to fetch containers" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
70
src/app/api/synology/route.ts
Normal file
70
src/app/api/synology/route.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import axios from "axios";
|
||||
|
||||
const SYNOLOGY_HOST = process.env.SYNOLOGY_HOST;
|
||||
const SYNOLOGY_PORT = process.env.SYNOLOGY_PORT || "5001";
|
||||
const SYNOLOGY_USERNAME = process.env.SYNOLOGY_USERNAME;
|
||||
const SYNOLOGY_PASSWORD = process.env.SYNOLOGY_PASSWORD;
|
||||
|
||||
export async function GET() {
|
||||
if (!SYNOLOGY_HOST || !SYNOLOGY_USERNAME || !SYNOLOGY_PASSWORD) {
|
||||
return NextResponse.json(
|
||||
{ error: "Synology credentials not configured" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const protocol = SYNOLOGY_PORT === "5000" ? "http" : "https";
|
||||
const baseUrl = `${protocol}://${SYNOLOGY_HOST}:${SYNOLOGY_PORT}`;
|
||||
|
||||
// Login to Synology
|
||||
const loginResponse = await axios.get(`${baseUrl}/webapi/auth.cgi`, {
|
||||
params: {
|
||||
api: "SYNO.API.Auth",
|
||||
version: 3,
|
||||
method: "login",
|
||||
account: SYNOLOGY_USERNAME,
|
||||
passwd: SYNOLOGY_PASSWORD,
|
||||
session: "FileStation",
|
||||
format: "sid",
|
||||
},
|
||||
httpsAgent: new (require("https").Agent)({
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
});
|
||||
|
||||
const sid = loginResponse.data.data.sid;
|
||||
|
||||
// Get storage info
|
||||
const storageResponse = await axios.get(`${baseUrl}/webapi/entry.cgi`, {
|
||||
params: {
|
||||
api: "SYNO.Storage.CGI.Storage",
|
||||
version: 1,
|
||||
method: "load_info",
|
||||
_sid: sid,
|
||||
},
|
||||
httpsAgent: new (require("https").Agent)({
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
});
|
||||
|
||||
const volumes = storageResponse.data.data.volumes.map((vol: any) => ({
|
||||
volume: vol.volume_path,
|
||||
size: vol.size_total_byte,
|
||||
used: vol.size_used_byte,
|
||||
available: vol.size_free_byte,
|
||||
percentUsed: ((vol.size_used_byte / vol.size_total_byte) * 100).toFixed(
|
||||
2
|
||||
),
|
||||
}));
|
||||
|
||||
return NextResponse.json(volumes);
|
||||
} catch (error) {
|
||||
console.error("Synology API error:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch Synology storage" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
59
src/app/api/unifi/route.ts
Normal file
59
src/app/api/unifi/route.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import axios from "axios";
|
||||
|
||||
const UNIFI_HOST = process.env.UNIFI_HOST;
|
||||
const UNIFI_PORT = process.env.UNIFI_PORT || "8443";
|
||||
const UNIFI_USERNAME = process.env.UNIFI_USERNAME;
|
||||
const UNIFI_PASSWORD = process.env.UNIFI_PASSWORD;
|
||||
|
||||
export async function GET() {
|
||||
if (!UNIFI_HOST || !UNIFI_USERNAME || !UNIFI_PASSWORD) {
|
||||
return NextResponse.json(
|
||||
{ error: "UniFi credentials not configured" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// Login to UniFi Controller
|
||||
const loginUrl = `https://${UNIFI_HOST}:${UNIFI_PORT}/api/login`;
|
||||
await axios.post(
|
||||
loginUrl,
|
||||
{
|
||||
username: UNIFI_USERNAME,
|
||||
password: UNIFI_PASSWORD,
|
||||
},
|
||||
{
|
||||
httpsAgent: new (require("https").Agent)({
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Get device list
|
||||
const devicesUrl = `https://${UNIFI_HOST}:${UNIFI_PORT}/api/s/default/stat/device`;
|
||||
const response = await axios.get(devicesUrl, {
|
||||
httpsAgent: new (require("https").Agent)({
|
||||
rejectUnauthorized: false,
|
||||
}),
|
||||
});
|
||||
|
||||
const devices = response.data.data.map((device: any) => ({
|
||||
name: device.name || device.model,
|
||||
mac: device.mac,
|
||||
ip: device.ip,
|
||||
model: device.model,
|
||||
state: device.state,
|
||||
uptime: device.uptime,
|
||||
clients: device.num_sta || 0,
|
||||
}));
|
||||
|
||||
return NextResponse.json(devices);
|
||||
} catch (error) {
|
||||
console.error("UniFi API error:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch UniFi devices" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user