From be2febcb8d1e8b34c8f7f2cf45397197414a02d9 Mon Sep 17 00:00:00 2001 From: Emma Ruby Date: Sun, 24 Nov 2024 18:44:19 -0600 Subject: [PATCH] more crap --- .gitignore | 3 +- Cron-Docker/Dockerfile | 17 ++++ Cron-Docker/crontab | 1 + app/api/controllers/[cid]/route.ts | 23 +++++ app/api/controllers/route.ts | 109 +++-------------------- app/api/cron/update-controllers/route.ts | 61 ++++++------- app/controllers/[cid]/page.tsx | 14 +-- app/controllers/page.tsx | 22 +---- bun.lockb | Bin 238837 -> 226844 bytes components/controller-table.tsx | 4 +- lib/prisma.ts | 9 ++ package.json | 10 ++- prisma/schema.prisma | 25 ++++++ 13 files changed, 132 insertions(+), 166 deletions(-) create mode 100644 Cron-Docker/Dockerfile create mode 100644 Cron-Docker/crontab create mode 100644 app/api/controllers/[cid]/route.ts create mode 100644 lib/prisma.ts create mode 100644 prisma/schema.prisma diff --git a/.gitignore b/.gitignore index 8f322f0..309ba42 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,8 @@ yarn-debug.log* yarn-error.log* # local env files -.env*.local +.env +*.local # vercel .vercel diff --git a/Cron-Docker/Dockerfile b/Cron-Docker/Dockerfile new file mode 100644 index 0000000..ca3f598 --- /dev/null +++ b/Cron-Docker/Dockerfile @@ -0,0 +1,17 @@ +FROM ubuntu:latest + +# Install necessary software +RUN apt-get update && \ + apt-get -y install cron curl + +# Add crontab file +COPY crontab /etc/cron.d/crontab + +# Give execution rights on the cron job +RUN chmod 0644 /etc/cron.d/crontab + +# Create the log file to be able to run tail +RUN touch /var/log/cron.log + +# Start the cron service +CMD cron && tail -f /var/log/cron.log diff --git a/Cron-Docker/crontab b/Cron-Docker/crontab new file mode 100644 index 0000000..92873de --- /dev/null +++ b/Cron-Docker/crontab @@ -0,0 +1 @@ +* * * * * curl localhost:3000/api/cron/update-controllers > /var/log/cron.log \ No newline at end of file diff --git a/app/api/controllers/[cid]/route.ts b/app/api/controllers/[cid]/route.ts new file mode 100644 index 0000000..65607f7 --- /dev/null +++ b/app/api/controllers/[cid]/route.ts @@ -0,0 +1,23 @@ +import { NextResponse } from 'next/server' +import { prisma } from '@/lib/prisma' + +export async function GET( + request: Request, + { params }: { params: { cid: string } } +) { + try { + const sessions = await prisma.controllerSession.findMany({ + where: { + cid: params.cid, + }, + orderBy: { + lastSeen: 'desc', + }, + }) + + return NextResponse.json(sessions) + } catch (error) { + console.error('Failed to fetch controller sessions:', error) + return NextResponse.json({ error: 'Failed to fetch controller sessions' }, { status: 500 }) + } +} \ No newline at end of file diff --git a/app/api/controllers/route.ts b/app/api/controllers/route.ts index 9ba24ec..d95f131 100644 --- a/app/api/controllers/route.ts +++ b/app/api/controllers/route.ts @@ -1,104 +1,19 @@ -import { NextResponse } from 'next/server'; - -interface Controller { - callsign: string; - frequency: string; - facility: number; -} - -const facilityTypes = { - 0: "OBS", - 1: "FSS", - 2: "DEL", - 3: "GND", - 4: "TWR", - 5: "APP", - 6: "CTR", -} as const; - -const facilityLongNames = { - OBS: "Observer", - FSS: "Flight Service Station", - DEL: "Clearance Delivery", - GND: "Ground", - TWR: "Tower", - APP: "Approach/Departure", - CTR: "Centre", -} as const; - -// Define FIR coverage for airports -const firCoverage: Record = { - CZQM: ["CYHZ", "CYFC", "CYQM", "CYSJ", "CYZX", "CYYG", "CYYT", "CYQX", "CYYR", "LFVP", "CYQI", "CYAY", "CYDF", "CYJT"], - CZUL: ["CYZV"], -}; +import { NextResponse } from 'next/server' +import { prisma } from '@/lib/prisma' export async function GET() { try { - const response = await fetch('https://data.vatsim.net/v3/vatsim-data.json', { - next: { revalidate: 60 } - }); - - if (!response.ok) { - throw new Error('Failed to fetch VATSIM data'); - } + // Get unique controllers with their latest session + const controllers = await prisma.controllerSession.findMany({ + orderBy: { + lastSeen: 'desc', + }, + distinct: ['cid'], + }) - const data = await response.json(); - - // First, get all controllers including CTR - const allControllers = data.controllers.map((controller: Controller) => { - const shortFacility = facilityTypes[controller.facility as keyof typeof facilityTypes] || "Unknown"; - return { - callsign: controller.callsign, - frequency: controller.frequency, - facility: shortFacility, - facilityLong: facilityLongNames[shortFacility as keyof typeof facilityLongNames] || "Unknown", - facilityType: controller.facility, - airport: controller.callsign.split('_')[0] - }; - }); - - // Separate CTR controllers - const ctrControllers = allControllers.filter(c => c.facilityType === 6); - - // Get non-CTR controllers - const localControllers = allControllers.filter(c => c.facilityType < 6 && c.facilityType > 0 && !c.callsign.includes("ATIS")); - - // Group local controllers by airport - const controllersByAirport = localControllers.reduce((acc: any, controller) => { - if (!acc[controller.airport]) { - acc[controller.airport] = []; - } - acc[controller.airport].push(controller); - return acc; - }, {}); - - // Sort controllers at each airport by facility type (higher number = higher priority) - Object.values(controllersByAirport).forEach((controllers: any) => { - controllers.sort((a: any, b: any) => b.facilityType - a.facilityType); - }); - - // Add CTR coverage for airports without local controllers - ctrControllers.forEach(ctr => { - const fir = ctr.callsign.split('_')[0]; - const coveredAirports = firCoverage[fir] || []; - - coveredAirports.forEach(airport => { - // Only add CTR if no local controllers are available - if (!controllersByAirport[airport] || controllersByAirport[airport].length === 0) { - controllersByAirport[airport] = [{ - callsign: ctr.callsign, - frequency: ctr.frequency, - facility: ctr.facility, - facilityLong: "Centre (Top-down)", - airport: airport - }]; - } - }); - }); - - return NextResponse.json(controllersByAirport); + return NextResponse.json(controllers) } catch (error) { - console.error(error); - return NextResponse.json({ error: 'Failed to fetch controller data' }, { status: 500 }); + console.error('Failed to fetch controller data:', error) + return NextResponse.json({ error: 'Failed to fetch controller data' }, { status: 500 }) } } \ No newline at end of file diff --git a/app/api/cron/update-controllers/route.ts b/app/api/cron/update-controllers/route.ts index 75ed94d..5879893 100644 --- a/app/api/cron/update-controllers/route.ts +++ b/app/api/cron/update-controllers/route.ts @@ -1,6 +1,5 @@ -import { createClient } from '@supabase/supabase-js' - import { NextResponse } from 'next/server' +import { prisma } from '@/lib/prisma' const facilityTypes = { 0: "OBS", @@ -12,61 +11,55 @@ const facilityTypes = { 6: "CTR", } as const; -// Define FIR coverage -const CZQM_AIRPORTS = ["CYHZ", "CYFC", "CYQM", "CYSJ", "CYZX", "CYYG", "CYYT", "CYQX", "CYYR", "LFVP", "CYQI", "CYAY", "CYDF", "CYJT"]; +const CZQM_AIRPORTS = ["CYHZ", "CYFC", "CYQM", "CYSJ", "CYZX", "CYYG", "CYYT", "CYQX", "CYYR", "LFVP", "CYQI", "CYAY", "CYDF", "CYJT", "BOS"]; export async function GET() { try { - // Fetch current VATSIM data const response = await fetch('https://data.vatsim.net/v3/vatsim-data.json'); if (!response.ok) throw new Error('Failed to fetch VATSIM data'); const data = await response.json(); - const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_SECRET_SUPABASE_KEY) - // Filter controllers in CZQM airspace const czqmControllers = data.controllers.filter((controller: any) => { const callsign = controller.callsign; - // console.log(callsign) - return callsign.startsWith('CZQM_') || - callsign.startsWith('CZQX_') || + return callsign.startsWith('CZQM_') || CZQM_AIRPORTS.some(airport => callsign.startsWith(airport)); }); - + // Process each controller for (const controller of czqmControllers) { const facilityType = facilityTypes[controller.facility as keyof typeof facilityTypes]; const airport = CZQM_AIRPORTS.find(ap => controller.callsign.startsWith(ap)) || 'CZQM'; - // Insert or update controller session - const { error } = await supabase - .from('controller_sessions') - .upsert({ - cid: controller.cid, + await prisma.controllerSession.upsert({ + where: { + id: parseInt(controller.cid), + }, + create: { + cid: String(controller.cid), name: controller.name, callsign: controller.callsign, - facility_type: facilityType, + facilityType: facilityType, frequency: controller.frequency, airport: airport, - last_seen: new Date().toISOString(), - logon_time: controller.logon_time, - }); - - if (error) { - console.error('Error updating controller session:', error); - } + lastSeen: new Date(), + logonTime: new Date(controller.logon_time), + }, + update: { + lastSeen: new Date(), + }, + }); } - // Clean up old sessions (controllers who have logged off) - const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString(); - const { error: cleanupError } = await supabase - .from('controller_sessions') - .delete() - .lt('last_seen', fiveMinutesAgo); - - if (cleanupError) { - console.error('Error cleaning up old sessions:', cleanupError); - } + // Clean up old sessions + const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); + await prisma.controllerSession.deleteMany({ + where: { + lastSeen: { + lt: fiveMinutesAgo, + }, + }, + }); return NextResponse.json({ success: true }); } catch (error) { diff --git a/app/controllers/[cid]/page.tsx b/app/controllers/[cid]/page.tsx index 7117854..954d06d 100644 --- a/app/controllers/[cid]/page.tsx +++ b/app/controllers/[cid]/page.tsx @@ -5,25 +5,19 @@ import { useParams } from "next/navigation"; import { Card } from "@/components/ui/card"; import { Header } from "@/components/header"; import { ControllerProfile } from "@/components/controller-profile"; -import { createClient } from "@/lib/supabase/client"; export default function ControllerProfilePage() { const params = useParams(); const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); - const supabase = createClient(); useEffect(() => { async function loadControllerData() { try { - const { data, error } = await supabase - .from('controller_sessions') - .select('*') - .eq('cid', params.cid) - .order('last_seen', { ascending: false }); - - if (error) throw error; - setSessions(data || []); + const response = await fetch(`/api/controllers/${params.cid}`); + if (!response.ok) throw new Error('Failed to fetch controller data'); + const data = await response.json(); + setSessions(data); } catch (error) { console.error("Error fetching controller data:", error); } finally { diff --git a/app/controllers/page.tsx b/app/controllers/page.tsx index 13832c5..9f6abfa 100644 --- a/app/controllers/page.tsx +++ b/app/controllers/page.tsx @@ -4,33 +4,19 @@ import { useEffect, useState } from "react"; import { Card } from "@/components/ui/card"; import { Header } from "@/components/header"; import { ControllerTable } from "@/components/controller-table"; -import { createClient } from "@/lib/supabase/client"; +import { prisma } from '@/lib/prisma' export default function ControllersPage() { const [controllers, setControllers] = useState([]); const [loading, setLoading] = useState(true); - const supabase = createClient(); useEffect(() => { async function loadControllers() { try { - // Get unique controllers with their latest session - const { data, error } = await supabase - .from('controller_sessions') - .select('*') - .order('last_seen', { ascending: false }); + const response = await fetch('/api/controllers'); + if (!response.ok) throw new Error('Failed to fetch METAR data'); + const uniqueControllers = await response.json(); - if (error) throw error; - - // Group by CID and take the most recent session - const uniqueControllers = data.reduce((acc: any[], curr) => { - const existingIndex = acc.findIndex(c => c.cid === curr.cid); - if (existingIndex === -1) { - acc.push(curr); - } - return acc; - }, []); - setControllers(uniqueControllers); } catch (error) { console.error("Error fetching controller data:", error); diff --git a/bun.lockb b/bun.lockb index 070e31be7dd2790b67f430038e084c1645c9d0da..47bae056cdb0ca5dfab36fba87b0b3905628a78a 100644 GIT binary patch delta 45468 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

Y=XOU^iyhgFZd9`J1nl z@mXU5e8@)#W5K9VAe>&p=MTBUiLoy!^+T?q;rz%m_?dl6+g4clvesSNBY?^A<$hj7 zbGFP7hhDnxi5@#==-&iXifBLMMf1|_S{~ZNfB_Rkl|8VOzA9{clpv4sc*4g^JV}dc zg)e`1PXf&84Dh#iXNVjEOTcuk#EgU-+EGVtP^ zNJ}rSQ?*B2V#>L8hzY{;QTXG5IbuU0+JYykH<5?(_8d`RKT1>Q>ZLVk)6IT;^2)}t zchG!1H6BO{Gj6^%LZ0IqeE<5{^G(|-<`BO?%yb-H=8IOZBCodd#cTT^htC%u@5fgt zQ<0)NQW)|2!!TFH&~>{&vE>yd2%~l36?~~Mdx5BW08baSXR);^25DbbmikgyiCicq z9KbL~i|q%LWRJZI^;KlqrINZ8d(=#kYIVl zYG%@Io*0>G7no{!>M_9;Fr-NH)Rs}1Z@oIHrk)1AV;U^#AHo-&SuoJ9(Os+FXl2D3 zif(|JZCWh)!9c(4R7*@hq*TyvJQ?Na-S&_!(yl@o*7}90dM*|9Hq7~SdVajyZhXGN z;y_<6-Jy?g^-H_xRF@A_|Es%BmF|C&rVX)vZK#$QaTM(9udrmiHPQO6bMh@SE+wCU;`&y9$P9%PT zVJ7F5dRc|8$1a~f{pS~m;h`xY%;dgORDByu>r&D2ZF~t-wgJ`6vyqesozhphO5cCf zZ#*hjR*6rqV^a zGY^Z%2$!2h<^}A9wN{HNC;vgyO5MgQzBzY4w{q^e72jVhuUne_=Wh96jrjBwx5+Yh zcB`AU@BeY}s=->}_dX6Dt=H<0!Y@=@{MC?oi??ac8OYBF4~~%@Q=&_iTI<9vWGA~; zX|+yF{}}30@yGj^uJTrFslk1OR>*Q>AN;FKl%j7SYUBgfGek`{Oif=lXJGJEuk$s^1arra+(MMBXV9IuSsms*G z?o(dpKYB?ed%5_Yww|Rjb-ifx3Ffq%+yC`)Ri=l-Hi$njBfE$7ba9hQ`?KuTe_Nq{ zxKR986@SR3__AAstd4Z&a{b6?v9V)3`x%dj&|vOedIrdc!Xhn zqzNVcQm)^nEAvRMSE~E|uWBXFPL(zbk8l3IGybckt^B3D*!%vAd0MKoiXFA|w0+3L zd<0kfhYQm~T=L=G_pds(^tvJc;72Jvg#Yq1Blo{Dd6st5f98+nR=&)iDaqdXKV0+5 zE#UuVjVs=?W$%<%>;I2EPl6Lxy$#=Y!+iWh4G@c|3} z2Y~FP2}$E}viC2Y=`!cm{QRqqc$B06ec$&;#LvG$Lp#p!_QfB66({2Vdx@W8tL7KF z&Tf&Hc0Z=JjL9FpwaL-NKRMiwi9-w@OSj$GxpQ@8(G!Z<2Mj(u7nCd~zjQ$*qe{p8 zlY(}=hd;)|EAyl-D@9~yCHkd~%g(W4rJ#pv(wfxD|%^PSSLvGzZf zMJ>gjZ91jx>Q%GsUo73KAufKWG-&rVp8WEn)ulmGwhVc$k=u{Z`Mh_A%b==%)egGK z-iP^a#@O#C(nm(+Jl9R?IW#J;Wi1}V=?yQro6Vp;LMui36 zD=U@4?msCb{6yhAhkAu4S~}Epsg$0Zg?}mb?3BWbog5U4xa8x|zVK3ahxJY(-^*b{ z;iPB>#}1;ylMdBI)t{6Kg}<$I_}1CIRNk$9Wg)(B4EzLyLu2t`xI-mz_i2Z;$_crt zX`@=FjvJLUN!S}WG-xK1`nJ{sOv6v>Imwed$f%@o$*JRnXS_rG{8Cg>HcHYWld{W6 zHYzD0H`z!qIw>bH#aA~rxa6c9-^?_7&ghJ+biGvHAlv}<4-RM>+9o)_-X<|DVbrML zw!!w%fujQLZ4(mvw($=PPDr!|g(cYojckk>Oi0SgPR$tiAF?Q!gXmbr!6U9@E71^{ zO^K#SMmF(3)v-hYqF)^cPj8uj$<`wCk}7l7#>vfSlh${z(qwV8pAlWMH(^y$m9^yf K@&6^g`u_o>gZMcB delta 52556 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 diff --git a/components/controller-table.tsx b/components/controller-table.tsx index 0b7b613..b9c1a53 100644 --- a/components/controller-table.tsx +++ b/components/controller-table.tsx @@ -53,10 +53,10 @@ export function ControllerTable({ data, loading }: ControllerTableProps) { {controller.airport} {controller.frequency} - {formatDistanceToNow(new Date(controller.last_seen), { addSuffix: true })} + {formatDistanceToNow(new Date(controller.lastSeen), { addSuffix: true })} - {formatSessionDuration(controller.logon_time, controller.last_seen)} + {formatSessionDuration(controller.logonTime, controller.lastSeen)} ))} diff --git a/lib/prisma.ts b/lib/prisma.ts new file mode 100644 index 0000000..16dfe88 --- /dev/null +++ b/lib/prisma.ts @@ -0,0 +1,9 @@ +import { PrismaClient } from '@prisma/client' + +const globalForPrisma = globalThis as unknown as { + prisma: PrismaClient | undefined +} + +export const prisma = globalForPrisma.prisma ?? new PrismaClient() + +if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma \ No newline at end of file diff --git a/package.json b/package.json index eff36f8..f3c3c98 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,13 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "postinstall": "prisma generate" }, "dependencies": { "@hookform/resolvers": "^3.9.0", "@next/swc-wasm-nodejs": "13.5.1", + "@prisma/client": "^5.10.2", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-aspect-ratio": "^1.1.0", @@ -38,8 +40,6 @@ "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", - "@supabase/auth-helpers-nextjs": "^0.9.0", - "@supabase/supabase-js": "^2.39.0", "@types/node": "20.6.2", "@types/react": "18.2.22", "@types/react-dom": "18.2.7", @@ -63,12 +63,14 @@ "react-resizable-panels": "^2.1.3", "recharts": "^2.12.7", "sonner": "^1.5.0", - "supabase": "^1.223.10", "tailwind-merge": "^2.5.2", "tailwindcss": "3.3.3", "tailwindcss-animate": "^1.0.7", "typescript": "5.2.2", "vaul": "^0.9.9", "zod": "^3.23.8" + }, + "devDependencies": { + "prisma": "^5.10.2" } } \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..99c6c75 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,25 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model ControllerSession { + id Int @id @default(autoincrement()) + cid String + name String + callsign String + facilityType String + frequency String + airport String + lastSeen DateTime @map("last_seen") + logonTime DateTime @map("logon_time") + createdAt DateTime @default(now()) @map("created_at") + + @@map("controller_sessions") + @@index([cid]) + @@index([lastSeen]) +} \ No newline at end of file