Files
2025-10-05 00:58:08 -07:00

119 lines
4.3 KiB
TypeScript

import { App } from "@tinyhttp/app";
import { authMiddleware } from "../middleware/auth.js";
import { conditionalPaintCaptchaMiddleware } from "../middleware/captcha.js";
import { captchaConfig } from "../config/captcha.js";
import { handleServiceError } from "../middleware/errorHandler.js";
import { PixelService } from "../services/pixel.js";
import { validateSeason, validateTileCoordinates } from "../validators/common.js";
import { validatePaintPixels, validatePixelInfo } from "../validators/pixel.js";
import { createErrorResponse, HTTP_STATUS } from "../utils/response.js";
import { prisma } from "../config/database.js";
const pixelService = new PixelService(prisma);
export default function (app: App) {
app.get("/:season/tile/random", async (req: any, res: any) => {
try {
const season = req.params["season"];
if (!validateSeason(season)) {
return res.status(HTTP_STATUS.BAD_REQUEST)
.json(createErrorResponse("Bad Request", HTTP_STATUS.BAD_REQUEST));
}
const result = await pixelService.getRandomTile();
return res.json(result);
} catch (error) {
console.error("Error getting random tile:", error);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR)
.json(createErrorResponse("Internal Server Error", HTTP_STATUS.INTERNAL_SERVER_ERROR));
}
});
app.get("/:season/pixel/:tileX/:tileY", async (req: any, res: any) => {
try {
const season = req.params["season"];
const tileX = Number.parseInt(req.params["tileX"]);
const tileY = Number.parseInt(req.params["tileY"]);
const x = Number.parseInt(req.query["x"] as string);
const y = Number.parseInt(req.query["y"] as string);
const validationError = validatePixelInfo({ season, tileX, tileY, x, y });
if (validationError) {
return res.status(HTTP_STATUS.BAD_REQUEST)
.json(createErrorResponse(validationError, HTTP_STATUS.BAD_REQUEST));
}
const result = await pixelService.getPixelInfo(tileX, tileY, x, y);
return res.json(result);
} catch (error) {
console.error("Error getting pixel info:", error);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR)
.json(createErrorResponse("Internal Server Error", HTTP_STATUS.INTERNAL_SERVER_ERROR));
}
});
app.get("/files/:season/tiles/:tileX/:tileY.png", async (req: any, res: any) => {
try {
const season = req.params["season"];
const tileX = Number.parseInt(req.params["tileX"]);
const tileY = Number.parseInt(req.params["tileY"]);
if (!validateSeason(season)) {
return res.status(HTTP_STATUS.BAD_REQUEST)
.json(createErrorResponse("Bad Request", HTTP_STATUS.BAD_REQUEST));
}
if (!validateTileCoordinates(tileX, tileY)) {
return res.status(HTTP_STATUS.BAD_REQUEST)
.json(createErrorResponse("Bad Request", HTTP_STATUS.BAD_REQUEST));
}
const imageBuffer = await pixelService.getTileImage(tileX, tileY);
res.setHeader("Content-Type", "image/png");
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
res.setHeader("Pragma", "no-cache");
res.setHeader("Expires", "0");
return res.send(imageBuffer);
} catch (error) {
console.error("Error generating tile image:", error);
return res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR)
.json(createErrorResponse("Internal Server Error", HTTP_STATUS.INTERNAL_SERVER_ERROR));
}
});
app.post("/:season/pixel/:tileX/:tileY",
authMiddleware,
conditionalPaintCaptchaMiddleware(captchaConfig.paint),
async (req: any, res: any) => {
try {
const season = req.params["season"];
const tileX = Number.parseInt(req.params["tileX"]);
const tileY = Number.parseInt(req.params["tileY"]);
const { colors, coords } = req.body;
const validationError = validatePaintPixels({ season, tileX, tileY, colors, coords });
if (validationError) {
return res.status(HTTP_STATUS.BAD_REQUEST)
.json(createErrorResponse(validationError, HTTP_STATUS.BAD_REQUEST));
}
// Get captcha counter flags from middleware
const shouldResetCaptchaCounter = req.shouldResetCaptchaCounter || false;
const skipCaptchaCounterReset = req.skipCaptchaCounterReset || false;
const result = await pixelService.paintPixels(
req.user!.id,
{ tileX, tileY, colors, coords },
0,
shouldResetCaptchaCounter,
skipCaptchaCounterReset
);
return res.json(result);
} catch (error) {
return handleServiceError(error as Error, res);
}
}
);
}