add all needed routes and stuff

This commit is contained in:
Darius
2026-02-05 00:53:23 +01:00
parent bd87929593
commit fd7a80f525
8 changed files with 236 additions and 78 deletions

4
package-lock.json generated
View File

@@ -25,8 +25,8 @@
}
},
"node_modules/@dpu/shared": {
"version": "1.4.1",
"resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#b55e1dd0a651c4cc3a7aabd8a44d49eb654f0189",
"version": "1.5.3",
"resolved": "git+https://git.dariusbag.dev/DarDarBinks/dpu-shared.git#3dd61ab4e801744d92b68138e4fe2a1655d21877",
"dependencies": {
"axios": "^1.7.9",
"chalk": "^5.6.2",

View File

@@ -42,14 +42,7 @@ export async function homeAssistantRoutes(
return { error: service_result.result };
}
const position_result =
service_result.result as HomeAssistantDeskPositionResult;
return {
position: position_result.as_text(),
is_standing: position_result.as_boolean,
last_changed: position_result.last_changed.toReadable(true),
};
return haService.convertPosResultToApiAnswer(service_result.result as HomeAssistantDeskPositionResult);
},
);

View File

@@ -1,4 +1,5 @@
import {
API_HA_DeskPosition,
BaseService,
type HomeAssistantDeskPositionResult,
type HomeAssistantEntity,
@@ -74,6 +75,14 @@ export class HomeAssistantService extends BaseService<HomeAssistantClient> {
}
}
convertPosResultToApiAnswer(position: HomeAssistantDeskPositionResult): API_HA_DeskPosition {
return {
position: position.as_text(),
is_standing: position.as_boolean,
last_changed: position.last_changed.toReadable(true),
}
}
async getTemperatureText(): Promise<ServiceResult<string>> {
try {
const entities = await this.getTemperatures();

52
src/homepage/routes.ts Normal file
View File

@@ -0,0 +1,52 @@
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import type { TidalService } from "../tidal/service.js";
import { HomeAssistantService } from "../homeassistant/service.js";
import { HomepageService } from "./service.js";
export async function homepageRoutes(
fastify: FastifyInstance,
{
hpService,
verifyAPIKey,
}: {
hpService: HomepageService
verifyAPIKey: (
request: FastifyRequest,
reply: FastifyReply,
) => Promise<void>;
},
) {
fastify.get(
"/homepage/status",
{
schema: {
description: "Get all current information for dpu status page",
tags: ["homepage"],
response: {
200: z.object({
title: z.string(),
artists: z.string(),
status: z.string(),
current: z.string(),
duration: z.string(),
url: z.string(),
}),
418: z.object({
error: z.string(),
}),
},
},
},
async (_request, reply) => {
const service_result = await hpService.getFullInformation();
if (!service_result.successful) {
reply.code(418);
return { error: service_result.result };
}
return service_result.result;
},
);
}

47
src/homepage/service.ts Normal file
View File

@@ -0,0 +1,47 @@
import {
BaseClient,
BaseService,
FullInformation,
HomeAssistantDeskPositionResult,
SseService,
TidalGetCurrent,
type ServiceResult,
} from "@dpu/shared";
import { logWarning } from "@dpu/shared/dist/logger.js";
import { HomeAssistantService } from "../homeassistant/service";
import { TidalService } from "../tidal/service";
export class HomepageService extends BaseService<null> {
private haService: HomeAssistantService;
private tidalService: TidalService;
private sseService: SseService;
constructor(haService: HomeAssistantService, tidalService: TidalService, sseService: SseService) {
super(null);
this.haService = haService;
this.tidalService = tidalService;
this.sseService = sseService;
}
async getFullInformation(): Promise<ServiceResult<FullInformation | string>> {
try {
const [desk, temp, song] = await Promise.all([
this.haService.getDeskPosition(),
this.haService.getTemperatureText(),
this.tidalService.getSong()
]);
const result = {
ha_desk_position: desk.successful ? this.haService.convertPosResultToApiAnswer(desk.result as HomeAssistantDeskPositionResult) : null,
ha_temp: temp.successful ? temp.result : null,
tidal_current: song ? song.result as TidalGetCurrent : null,
}
return this.getSuccessfulResult(result);
} catch {
const error_message = "error getting all information";
logWarning(error_message);
return this.getErrorResult(error_message);
}
}
}

View File

@@ -17,8 +17,12 @@ import { HomeAssistantClient } from "./homeassistant/client.js";
import { homeAssistantRoutes } from "./homeassistant/routes.js";
import { HomeAssistantService } from "./homeassistant/service.js";
import { TidalClient } from "./tidal/client.js";
import { tidalRoutes } from "./tidal/routes.js";
import { TidalService } from "./tidal/service.js";
import { tidalRoutes } from "./tidal/routes.js";
import { sseRoutes } from "./sse/routes.js";
import { SseService } from "@dpu/shared";
import { HomepageService } from "./homepage/service.js";
import { homepageRoutes } from "./homepage/routes.js";
const fastify = Fastify().withTypeProvider<ZodTypeProvider>();
@@ -75,6 +79,10 @@ const haService = new HomeAssistantService(haClient);
const tidalClient = new TidalClient(fastify.axios.tidal);
const tidalService = new TidalService(tidalClient);
const sseService = new SseService();
const hpService = new HomepageService(haService, tidalService, sseService);
async function verifyAPIKey(
request: FastifyRequest,
reply: FastifyReply,
@@ -92,6 +100,8 @@ const port = parseInt(Config.port, 10);
// Register routes
await fastify.register(homeAssistantRoutes, { haService, verifyAPIKey });
await fastify.register(tidalRoutes, { tidalService, verifyAPIKey });
await fastify.register(sseRoutes, { sseService, verifyAPIKey });
await fastify.register(homepageRoutes, { hpService, verifyAPIKey });
fastify.get(
"/ping",

45
src/sse/routes.ts Normal file
View File

@@ -0,0 +1,45 @@
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { SseService } from "@dpu/shared";
export async function sseRoutes(
fastify: FastifyInstance,
{
sseService,
verifyAPIKey,
}: {
sseService: SseService;
verifyAPIKey: (
request: FastifyRequest,
reply: FastifyReply,
) => Promise<void>;
},
) {
fastify.get(
"/events",
{
schema: {
description: "Register for SSE",
tags: ["sse"],
},
},
async (request, reply) => {
reply.raw.setHeader("Content-Type", "text/event-stream");
reply.raw.setHeader("Cache-Control", "no-cache");
reply.raw.setHeader("Connection", "keep-alive");
const clientId = Date.now();
const sendEvent = (data: unknown) => {
reply.raw.write(`data: ${JSON.stringify(data)}\n\n`);
};
sseService.addClient({ id: clientId, send: sendEvent });
sendEvent({ type: "connected", message: "SSE connected" });
request.raw.on("close", () => {
sseService.removeClient(clientId);
});
},
);
}

View File

@@ -11,15 +11,17 @@ export class TidalService extends BaseService<TidalClient> {
const req = await this.getSong();
if (req.successful) {
const song = req.result as TidalGetCurrent;
const status = song.status === "playing" ? "▶️" : "⏸️";
return this.getSuccessfulResult(
`listening to ${song.title} by ${song.artists}. ${status} ${song.current}/${song.duration}. link: ${song.url}`,
);
return this.getSuccessfulResult(this.formatSong(song));
} else {
return this.getErrorResult(req.result as string);
}
}
formatSong(song: TidalGetCurrent): string {
const status = song.status === "playing" ? "▶️" : "⏸️";
return `listening to ${song.title} by ${song.artists}. ${status} ${song.current}/${song.duration}. link: ${song.url}`;
}
async getSong(): Promise<ServiceResult<TidalGetCurrent | string>> {
try {
const response = await this.getClient().get<TidalGetCurrent>("current");