Files
openclaw-market/app/api/v1/heatmap/route.ts
richarjiang fa4c458eda init
2026-03-13 11:00:01 +08:00

62 lines
1.6 KiB
TypeScript

import { NextResponse } from "next/server";
import { gte, and, isNotNull, sql } from "drizzle-orm";
import { db } from "@/lib/db";
import { lobsters } from "@/lib/db/schema";
import { getCacheHeatmap, setCacheHeatmap } from "@/lib/redis";
export async function GET() {
try {
const cached = await getCacheHeatmap();
if (cached) {
return NextResponse.json(JSON.parse(cached));
}
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
const activeLobsters = await db
.select({
city: lobsters.city,
country: lobsters.country,
latitude: lobsters.latitude,
longitude: lobsters.longitude,
count: sql<number>`count(*)`,
})
.from(lobsters)
.where(
and(
gte(lobsters.lastHeartbeat, fiveMinutesAgo),
isNotNull(lobsters.latitude),
isNotNull(lobsters.longitude)
)
)
.groupBy(
lobsters.city,
lobsters.country,
lobsters.latitude,
lobsters.longitude
);
const points = activeLobsters.map((row) => ({
lat: Number(row.latitude),
lng: Number(row.longitude),
weight: row.count,
lobsterCount: row.count,
city: row.city,
country: row.country,
}));
const lastUpdated = new Date().toISOString();
const responseData = { points, lastUpdated };
await setCacheHeatmap(JSON.stringify(responseData));
return NextResponse.json(responseData);
} catch (error) {
console.error("Heatmap error:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}