Skip to content

Commit 3fc17cb

Browse files
authored
Merge pull request #122 from PFConnect/canary
Automatic route generation
2 parents 5d150a8 + e03ae59 commit 3fc17cb

9 files changed

Lines changed: 487 additions & 46 deletions

File tree

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
}
6565
}
6666
</script>
67+
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3075420086521736" crossorigin="anonymous"></script>
6768
</head>
6869
<body>
6970
<div id="root"></div>

public/ads.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
google.com, pub-3075420086521736, DIRECT, f08c47fec0942fa0

server/data/waypointData.json

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
[
2+
{ "name": "MDPC", "x": 87.44, "y": 102.59, "type": "AIRPORT" },
3+
{ "name": "EGKK", "x": 130.0, "y": 33.0, "type": "AIRPORT" },
4+
{ "name": "LCLK", "x": 159.82, "y": 91.21, "type": "AIRPORT" },
5+
{ "name": "LCPH", "x": 131.80, "y": 99.33, "type": "AIRPORT" },
6+
{ "name": "LCRA", "x": 147.70, "y": 101.35, "type": "AIRPORT" },
7+
{ "name": "GCLP", "x": 90.0, "y": 70.30, "type": "AIRPORT" },
8+
{ "name": "EGHI", "x": 125.90, "y": 39.30, "type": "AIRPORT" },
9+
{ "name": "EFKT", "x": 165.80, "y": 12.90, "type": "AIRPORT" },
10+
{ "name": "LEMH", "x": 126.80, "y": 65.80, "type": "AIRPORT" },
11+
{ "name": "MDST", "x": 68.65, "y": 93.37, "type": "AIRPORT" },
12+
{ "name": "MDAB", "x": 81.15, "y": 95.27, "type": "AIRPORT" },
13+
{ "name": "MTCA", "x": 34.56, "y": 103.60, "type": "AIRPORT" },
14+
{ "name": "MDCR", "x": 56.90, "y": 109.02, "type": "AIRPORT" },
15+
{ "name": "MAROG", "x": 92.37, "y": 102.59, "type": "WAYPOINT" },
16+
{ "name": "PC199", "x": 84.97, "y": 102.75, "type": "WAYPOINT" },
17+
{ "name": "PC103", "x": 94.16, "y": 105.85, "type": "WAYPOINT" },
18+
{ "name": "PC106", "x": 90.57, "y": 108.19, "type": "WAYPOINT" },
19+
{ "name": "MIBNI", "x": 83.77, "y": 107.16, "type": "WAYPOINT" },
20+
{ "name": "PC200", "x": 73.71, "y": 105.63, "type": "WAYPOINT" },
21+
{ "name": "ETBOD", "x": 62.45, "y": 103.08, "type": "WAYPOINT" },
22+
{ "name": "KATOK", "x": 107.06, "y": 93.72, "type": "WAYPOINT" },
23+
{ "name": "PC114", "x": 92.64, "y": 94.53, "type": "WAYPOINT" },
24+
{ "name": "PC201", "x": 84.43, "y": 93.55, "type": "WAYPOINT" },
25+
{ "name": "CHUMA", "x": 93.35, "y": 83.87, "type": "WAYPOINT" },
26+
{ "name": "PC202", "x": 83.72, "y": 84.96, "type": "WAYPOINT" },
27+
{ "name": "PIXAR", "x": 79.86, "y": 77.39, "type": "WAYPOINT" },
28+
{ "name": "AGNAL", "x": 74.74, "y": 102.31, "type": "WAYPOINT" },
29+
{ "name": "BEREL", "x": 71.24, "y": 94.06, "type": "WAYPOINT" },
30+
{ "name": "VOGEP", "x": 63.06, "y": 85.38, "type": "WAYPOINT" },
31+
{ "name": "POKEG", "x": 67.24, "y": 75, "type": "WAYPOINT" },
32+
{ "name": "BETIR", "x": 87.68, "y": 80, "type": "WAYPOINT" },
33+
{ "name": "ILOBI", "x": 79.93, "y": 82.88, "type": "WAYPOINT" },
34+
{ "name": "DASVO", "x": 77.99, "y": 93.81, "type": "WAYPOINT" },
35+
{ "name": "PC203", "x": 88.74, "y": 98.31, "type": "WAYPOINT" },
36+
{ "name": "LETAD", "x": 100.56, "y": 96.22, "type": "WAYPOINT" },
37+
{ "name": "VIRTO", "x": 99.24, "y": 101.25, "type": "WAYPOINT" },
38+
{ "name": "MESPA", "x": 99.61, "y": 103.25, "type": "WAYPOINT" },
39+
{ "name": "ANTEX", "x": 117.99, "y": 101.88, "type": "WAYPOINT" },
40+
{ "name": "PIXES", "x": 73.93, "y": 85.06, "type": "WAYPOINT" },
41+
{ "name": "MUNOZ", "x": 109.75, "y": 89.25, "type": "WAYPOINT" },
42+
{ "name": "ELTAN", "x": 109.75, "y": 75.94, "type": "WAYPOINT" },
43+
{ "name": "GINRE", "x": 136.95, "y": 73.81, "type": "WAYPOINT" },
44+
{ "name": "MORSS", "x": 148.82, "y": 61.44, "type": "WAYPOINT" },
45+
{ "name": "RIXOT", "x": 148.82, "y": 44.56, "type": "WAYPOINT" },
46+
{ "name": "MEROS", "x": 136.7, "y": 49.81, "type": "WAYPOINT" },
47+
{ "name": "SARGO", "x": 121.2, "y": 49.81, "type": "WAYPOINT" },
48+
{ "name": "MADAS", "x": 100.45, "y": 53.56, "type": "WAYPOINT" },
49+
{ "name": "CANDE", "x": 79.08, "y": 53.56, "type": "WAYPOINT" },
50+
{ "name": "PELIN", "x": 67.24, "y": 60.31, "type": "WAYPOINT" },
51+
{ "name": "TUGPU", "x": 174.82, "y": 37.44, "type": "WAYPOINT" },
52+
{ "name": "AMULU", "x": 151.94, "y": 31.44, "type": "WAYPOINT" },
53+
{ "name": "CARBO", "x": 143.99, "y": 0, "type": "WAYPOINT" },
54+
{ "name": "RATSU", "x": 79.08, "y": 0, "type": "WAYPOINT" },
55+
{ "name": "AMUBA", "x": 210, "y": 37.44, "type": "WAYPOINT" },
56+
{ "name": "BODLO", "x": 15, "y": 75, "type": "WAYPOINT" },
57+
{ "name": "NEGON", "x": 109.75, "y": 120, "type": "WAYPOINT" },
58+
{ "name": "PCA", "x": 87.44, "y": 102.59, "type": "VOR-DME" },
59+
{ "name": "BONEK", "x": 140.93, "y": 86.24, "type": "WAYPOINT" },
60+
{ "name": "LUBES", "x": 136.19, "y": 91.4, "type": "WAYPOINT" },
61+
{ "name": "KURSA", "x": 135.96, "y": 98.25, "type": "WAYPOINT" },
62+
{ "name": "DAROS", "x": 146.57, "y": 87.84, "type": "WAYPOINT" },
63+
{ "name": "ADLAS", "x": 151.13, "y": 89.03, "type": "WAYPOINT" },
64+
{ "name": "NORDI", "x": 145.45, "y": 94.71, "type": "WAYPOINT" },
65+
{ "name": "OTESA", "x": 161.69, "y": 85.65, "type": "WAYPOINT" },
66+
{ "name": "LK400", "x": 161.65, "y": 88.59, "type": "WAYPOINT" },
67+
{ "name": "SOBOS", "x": 167.26, "y": 89.15, "type": "WAYPOINT" },
68+
{ "name": "RUDER", "x": 171.94, "y": 87.96, "type": "WAYPOINT" },
69+
{ "name": "REXAL", "x": 166.51, "y": 95.53, "type": "WAYPOINT" },
70+
{ "name": "EMEDA", "x": 164.63, "y": 103.46, "type": "WAYPOINT" },
71+
{ "name": "ROKIK", "x": 164.38, "y": 86.15, "type": "WAYPOINT" },
72+
{ "name": "MURAT", "x": 171.57, "y": 85.15, "type": "WAYPOINT" },
73+
{ "name": "KRASI", "x": 176.44, "y": 78.94, "type": "WAYPOINT" },
74+
{ "name": "AMAKO", "x": 167.32, "y": 93.53, "type": "WAYPOINT" },
75+
{ "name": "BOSIS", "x": 162.69, "y": 99.15, "type": "WAYPOINT" },
76+
{ "name": "BETID", "x": 151.76, "y": 105.46, "type": "WAYPOINT" },
77+
{ "name": "ESERI", "x": 134.7, "y": 106.59, "type": "WAYPOINT" },
78+
{ "name": "NIMSI", "x": 124.76, "y": 103.21, "type": "WAYPOINT" },
79+
{ "name": "LK601", "x": 157.29, "y": 93.78, "type": "WAYPOINT" },
80+
{ "name": "RIMEX", "x": 153.07, "y": 97.96, "type": "WAYPOINT" },
81+
{ "name": "PEEKO", "x": 148.38, "y": 95.9, "type": "WAYPOINT" },
82+
{ "name": "GIPRO", "x": 147.26, "y": 98.09, "type": "WAYPOINT" },
83+
{ "name": "KOBER", "x": 171.94, "y": 94.95, "type": "WAYPOINT" },
84+
{ "name": "LCA", "x": 159.82, "y": 91.21, "type": "VOR-DME" },
85+
{ "name": "BELOW", "x": 150, "y": 50, "type": "NDB" },
86+
{ "name": "HAZEL", "x": 123.140625, "y": 35.015625, "type": "WAYPOINT" },
87+
{ "name": "MAYFIELD", "x": 129.59375, "y": 40.6875, "type": "VOR-DME" },
88+
{ "name": "TEBRA", "x": 138.75, "y": 31.625, "type": "NDB" },
89+
{ "name": "BODSO", "x": 134.375, "y": 23.8125, "type": "WAYPOINT" },
90+
{ "name": "KONAN", "x": 162.06, "y": 40.71, "type": "WAYPOINT" },
91+
{ "name": "MIKEL", "x": 114.25, "y": 27.75, "type": "WAYPOINT" },
92+
{ "name": "LEDGO", "x": 105.4375, "y": 42.4375, "type": "WAYPOINT" },
93+
{ "name": "KITTL", "x": 163.34375, "y": 7.6875, "type": "WAYPOINT" },
94+
{ "name": "HTML", "x": 161.59375, "y": 2.3125, "type": "WAYPOINT" },
95+
{ "name": "KRDSH", "x": 158, "y": 6.25, "type": "WAYPOINT" },
96+
{ "name": "KETF", "x": 150.3125, "y": 4.15625, "type": "WAYPOINT" },
97+
{ "name": "DELTA", "x": 159.53125, "y": 14.06, "type": "WAYPOINT" },
98+
{ "name": "ROSE", "x": 152.34375, "y": 18.84, "type": "WAYPOINT" },
99+
{ "name": "ROBUX", "x": 169, "y": 19.625, "type": "NDB" },
100+
{ "name": "LIMA", "x": 163.25, "y": 25, "type": "WAYPOINT" },
101+
{ "name": "SUDIP", "x": 173.1875, "y": 27.1875, "type": "WAYPOINT" },
102+
{ "name": "KIT", "x": 186.5625, "y": 27.1875, "type": "WAYPOINT" },
103+
{ "name": "BRAVO", "x": 178.5625, "y": 35.5, "type": "WAYPOINT" },
104+
{ "name": "EFLA", "x": 190.4375, "y": 42.25, "type": "WAYPOINT" },
105+
{ "name": "KKWO6", "x": 125.49, "y": 34.57, "type": "WAYPOINT" },
106+
{ "name": "KKWO8", "x": 121.56, "y": 35.46, "type": "WAYPOINT" },
107+
{ "name": "KKS11", "x": 121.96, "y": 37.22, "type": "WAYPOINT" },
108+
{ "name": "KKS2O", "x": 122.68, "y": 39.93, "type": "WAYPOINT" },
109+
{ "name": "KKS25", "x": 123.34, "y": 42.32, "type": "WAYPOINT" },
110+
{ "name": "BOGNA", "x": 127.46, "y": 46.54, "type": "WAYPOINT" },
111+
{ "name": "KKWO7", "x": 124.91, "y": 34.72, "type": "WAYPOINT" },
112+
{ "name": "KKWO9", "x": 120.05, "y": 37.19, "type": "WAYPOINT" },
113+
{ "name": "NOVMA", "x": 114.1, "y": 39.09, "type": "WAYPOINT" },
114+
{ "name": "KKWO4", "x": 124.46, "y": 34.94, "type": "WAYPOINT" },
115+
{ "name": "KKSO6", "x": 124.7, "y": 36.02, "type": "WAYPOINT" },
116+
{ "name": "KKSO9", "x": 125.89, "y": 36.16, "type": "WAYPOINT" },
117+
{ "name": "KKS14", "x": 133.76, "y": 37.92, "type": "WAYPOINT" },
118+
{ "name": "KKS33", "x": 138.07, "y": 37.12, "type": "WAYPOINT" },
119+
{ "name": "WIZAD", "x": 142.78, "y": 36.28, "type": "WAYPOINT" },
120+
{ "name": "VASUX", "x": 118.65, "y": 47.12, "type": "WAYPOINT" },
121+
{ "name": "DISVO", "x": 120.35, "y": 45.08, "type": "WAYPOINT" },
122+
{ "name": "TELTU", "x": 122.63, "y": 43.14, "type": "WAYPOINT" },
123+
{ "name": "HOLLY", "x": 128.4, "y": 39.78, "type": "WAYPOINT" },
124+
{ "name": "WILLO", "x": 122.81, "y": 36.63, "type": "WAYPOINT" },
125+
{ "name": "TIMBA", "x": 131.84, "y": 34.74, "type": "WAYPOINT" },
126+
{ "name": "KKE64", "x": 134.63, "y": 36.88, "type": "WAYPOINT" },
127+
{ "name": "AMDUT", "x": 137.45, "y": 39.11, "type": "WAYPOINT" },
128+
{ "name": "KUNAV", "x": 143.19, "y": 44.26, "type": "WAYPOINT" },
129+
{ "name": "IMVUR", "x": 118.39, "y": 31.35, "type": "WAYPOINT" },
130+
{ "name": "KKEO5", "x": 134.54, "y": 32.49, "type": "WAYPOINT" },
131+
{ "name": "KKNO9", "x": 133.48, "y": 28.13, "type": "WAYPOINT" },
132+
{ "name": "KKW19", "x": 126.2, "y": 29.65, "type": "WAYPOINT" },
133+
{ "name": "KKEO3", "x": 132.93, "y": 32.89, "type": "WAYPOINT" },
134+
{ "name": "SEAFORD", "x": 134.21, "y": 43.74, "type": "VOR-DME" },
135+
{ "name": "TUNBY", "x": 142.44, "y": 32.97, "type": "WAYPOINT" },
136+
{ "name": "DETLING", "x": 142.99, "y": 30.5, "type": "VOR-DME" },
137+
{ "name": "FRANE", "x": 144.28, "y": 27.19, "type": "WAYPOINT" },
138+
{ "name": "ACORN", "x": 129.19, "y": 30.62, "type": "WAYPOINT" },
139+
{ "name": "EPSOM", "x": 124.8, "y": 31.71, "type": "WAYPOINT" },
140+
{ "name": "VALDI", "x": 129.71, "y": -0.06, "type": "WAYPOINT" },
141+
{ "name": "BEKET", "x": 122.2, "y": 2.29, "type": "WAYPOINT" },
142+
{ "name": "OVDAN", "x": 134.17, "y": 11.59, "type": "WAYPOINT" },
143+
{ "name": "BEREP", "x": 143.79, "y": 10.11, "type": "WAYPOINT" },
144+
{ "name": "RIMOL", "x": 117.04, "y": 12.46, "type": "WAYPOINT" },
145+
{ "name": "GOSAM", "x": 116.41, "y": 21.06, "type": "WAYPOINT" },
146+
{ "name": "NEXUS", "x": 123.84, "y": 19.5, "type": "WAYPOINT" },
147+
{ "name": "LAKEY", "x": 120.79, "y": 25.36, "type": "WAYPOINT" },
148+
{ "name": "GASKO", "x": 125.09, "y": 25.05, "type": "WAYPOINT" },
149+
{ "name": "DUFFY", "x": 110.7, "y": 25.68, "type": "WAYPOINT" },
150+
{ "name": "LUSAT", "x": 110.7, "y": 31.78, "type": "WAYPOINT" },
151+
{ "name": "ERABI", "x": 103.03, "y": 33.34, "type": "WAYPOINT" },
152+
{ "name": "WATERFORD", "x": 109.06, "y": 38.27, "type": "NDB" }
153+
]

server/routes/data.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { getActiveNotifications } from '../db/notifications.js';
77
import { mainDb, flightsDb, redisConnection } from '../db/connection.js';
88
import { getTopUsers, STATS_KEYS } from '../db/leaderboard.js';
99
import { getUserById } from '../db/users.js';
10+
import { getWaypointData } from '../utils/getData.js';
11+
import { findPath } from '../utils/findRoute.js';
1012
import { sql } from 'kysely';
1113

1214
import dotenv from 'dotenv';
@@ -22,6 +24,7 @@ const __dirname = path.dirname(__filename);
2224
const airportsPath = path.join(__dirname, '..', 'data', 'airportData.json');
2325
const aircraftPath = path.join(__dirname, '..', 'data', 'aircraftData.json');
2426
const airlinesPath = path.join(__dirname, '..', 'data', 'airlineData.json');
27+
const waypointsPath = path.join(__dirname, '..', 'data', 'waypointData.json');
2528
const backgroundsPath = path.join(
2629
process.cwd(),
2730
'public',
@@ -34,6 +37,7 @@ if (
3437
!fs.existsSync(airportsPath) ||
3538
!fs.existsSync(aircraftPath) ||
3639
!fs.existsSync(airlinesPath) ||
40+
!fs.existsSync(waypointsPath) ||
3741
!fs.existsSync(backgroundsPath)
3842
) {
3943
console.error(`Data file missing`);
@@ -59,6 +63,10 @@ interface Airport {
5963
departures: Record<string, Record<string, string>>;
6064
stars: string[];
6165
arrivals: Record<string, Record<string, string>>;
66+
location?: {
67+
x: number;
68+
y: number;
69+
};
6270
}
6371

6472
const router = express.Router();
@@ -564,4 +572,62 @@ router.get('/tester-settings', async (req, res) => {
564572
}
565573
});
566574

575+
router.get('/findRoute', async (req, res) => {
576+
const from = typeof req.query.from === 'string' ? req.query.from : '';
577+
const to = typeof req.query.to === 'string' ? req.query.to : '';
578+
579+
if (!from || !to) {
580+
return res.status(400).json({ error: 'Missing required query parameters: from, to' });
581+
}
582+
583+
const cacheKey = `route:${from}:${to}`;
584+
585+
try {
586+
const cachedRoute = await redisConnection.get(cacheKey);
587+
if (cachedRoute) {
588+
return res.json(JSON.parse(cachedRoute));
589+
}
590+
} catch (error) {
591+
if (error instanceof Error) {
592+
console.warn('[Redis] Failed to read cache for route:', error.message);
593+
}
594+
}
595+
596+
try {
597+
if (!fs.existsSync(waypointsPath)) {
598+
return res.status(404).json({ error: 'Waypoint data not found' });
599+
}
600+
601+
const waypointData = getWaypointData();
602+
603+
const allPoints = [
604+
...waypointData,
605+
];
606+
607+
const { path, distance, success } = findPath(from, to, allPoints);
608+
609+
if (!success) {
610+
return res.status(404).json({ error: 'Route not found' });
611+
}
612+
613+
const routeData = { path, distance };
614+
615+
try {
616+
await redisConnection.set(cacheKey, JSON.stringify(routeData), 'EX', 43200); // Cache for 12 hours
617+
} catch (error) {
618+
if (error instanceof Error) {
619+
console.warn('[Redis] Failed to set cache for route:', error.message);
620+
}
621+
}
622+
623+
res.json(routeData);
624+
} catch (error) {
625+
console.error('Error finding route:', error);
626+
res.status(500).json({
627+
error: 'Internal server error',
628+
message: 'Error finding route',
629+
});
630+
}
631+
});
632+
567633
export default router;

0 commit comments

Comments
 (0)