Skip to content

Commit 7347114

Browse files
Merge pull request #39 from sebastiankrll/infra/cdn
Infra/cdn
2 parents 6f44e51 + a83c51a commit 7347114

File tree

7 files changed

+3307
-1582
lines changed

7 files changed

+3307
-1582
lines changed

apps/updater/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"typescript": "^5.9.3"
1717
},
1818
"dependencies": {
19+
"@aws-sdk/client-s3": "^3.948.0",
1920
"@sr24/db": "*",
2021
"@sr24/types": "*",
2122
"axios": "^1.13.2",

apps/updater/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { updateAirlines } from "./airlines.js";
55
import { updateAirports } from "./airports.js";
66
import { updateFirs } from "./fir.js";
77
import { updateFleets } from "./fleet.js";
8+
import { updateR2Storage } from "./s3.js";
89
import { updateTracons } from "./tracon.js";
910

1011
let dbsInitialized = false;
@@ -23,6 +24,8 @@ CronJob.from({
2324
await updateTracons();
2425
await updateFleets();
2526

27+
await updateR2Storage();
28+
2629
console.log("✅ Static data update completed!");
2730
},
2831
start: true,

apps/updater/src/s3.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
2+
import { rdsGetMultiple } from "@sr24/db/redis";
3+
4+
const accountId = process.env.CF_ACCOUNT_ID || "";
5+
const accessKeyId = process.env.R2_ACCESS_KEY_ID || "";
6+
const secret = process.env.R2_SECRET_ACCESS_KEY || "";
7+
const bucket = process.env.R2_BUCKET_NAME || "";
8+
9+
const r2 = new S3Client({
10+
region: "auto",
11+
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
12+
credentials: { accessKeyId, secretAccessKey: secret },
13+
});
14+
15+
export async function updateR2Storage(): Promise<void> {
16+
const versions: string[] = await rdsGetMultiple("", [
17+
"static_airports:version",
18+
"static_firs:version",
19+
"static_tracons:version",
20+
"static_airlines:version",
21+
]);
22+
const manifest = {
23+
airportsVersion: versions[0],
24+
firsVersion: versions[1],
25+
traconsVersion: versions[2],
26+
airlinesVersion: versions[3],
27+
};
28+
29+
await uploadManifestToR2(manifest);
30+
31+
const datas = await rdsGetMultiple("", ["static_airports:all", "static_firs:all", "static_tracons:all", "static_airlines:all"]);
32+
await uploadDataToR2(`airports_${manifest.airportsVersion}.json`, JSON.stringify(datas[0]));
33+
await uploadDataToR2(`firs_${manifest.firsVersion}.json`, JSON.stringify(datas[1]));
34+
await uploadDataToR2(`tracons_${manifest.traconsVersion}.json`, JSON.stringify(datas[2]));
35+
await uploadDataToR2(`airlines_${manifest.airlinesVersion}.json`, JSON.stringify(datas[3]));
36+
37+
console.log("✅ R2 storage update completed!");
38+
}
39+
40+
async function uploadDataToR2(key: string, body: Buffer | Uint8Array | Blob | string) {
41+
return await r2.send(
42+
new PutObjectCommand({
43+
Bucket: bucket,
44+
Key: key,
45+
Body: body,
46+
}),
47+
);
48+
}
49+
50+
async function uploadManifestToR2(manifest: object) {
51+
const manifestJson = JSON.stringify(manifest);
52+
return await uploadDataToR2("manifest.json", manifestJson);
53+
}

apps/web/storage/dexie.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,47 @@ interface StaticVersions {
88
firsVersion: string;
99
airlinesVersion: string;
1010
}
11-
1211
interface DexieFeature {
1312
id: string;
1413
feature: FIRFeature | SimAwareTraconFeature;
1514
}
15+
type Manifest = { key: string; versions: StaticVersions };
16+
17+
const R2_BUCKET_URL = process.env.NODE_ENV === "development" ? process.env.NEXT_PUBLIC_R2_BUCKET_URL_DEV : process.env.NEXT_PUBLIC_R2_BUCKET_URL;
1618

1719
const db = new Dexie("StaticDatabase") as Dexie & {
1820
airports: EntityTable<StaticAirport, "id">;
1921
firs: EntityTable<DexieFeature, "id">;
2022
tracons: EntityTable<DexieFeature, "id">;
2123
airlines: EntityTable<StaticAirline, "id">;
24+
manifest: EntityTable<Manifest, "key">;
2225
};
2326

2427
db.version(1).stores({
2528
airports: "id",
2629
firs: "id",
2730
tracons: "id",
2831
airlines: "id",
32+
manifest: "key",
2933
});
3034

3135
export async function dxInitDatabases(): Promise<void> {
32-
const serverVersions = await fetchApi<StaticVersions>("/static/versions");
33-
const localVersions: StaticVersions = JSON.parse(localStorage.getItem("databaseVersions") || "{}");
34-
35-
if (serverVersions.airportsVersion !== localVersions.airportsVersion) {
36-
const entries = (await fetchStaticData("airports")) as StaticAirport[];
36+
const latestManifest = await fetchApi<StaticVersions>(`${R2_BUCKET_URL}/manifest.json`, {
37+
cache: "no-store",
38+
});
39+
const storedManifest = (await db.manifest.get("databaseVersions")) as Manifest | undefined;
40+
41+
if (latestManifest.airportsVersion !== storedManifest?.versions.airportsVersion) {
42+
const entries = (await fetchApi<StaticAirport[]>(`${R2_BUCKET_URL}/airports_${latestManifest.airportsVersion}.json`, {
43+
cache: "no-store",
44+
})) as StaticAirport[];
3745
storeData(entries, db.airports as EntityTable<any, "id">);
3846
}
3947

40-
if (serverVersions.firsVersion !== localVersions.firsVersion) {
41-
const features = (await fetchStaticData("firs")) as FIRFeature[];
48+
if (latestManifest.firsVersion !== storedManifest?.versions.firsVersion) {
49+
const features = (await fetchApi<FIRFeature[]>(`${R2_BUCKET_URL}/firs_${latestManifest.firsVersion}.json`, {
50+
cache: "no-store",
51+
})) as FIRFeature[];
4252
const entries: DexieFeature[] = features.map((f) => ({
4353
id: f.properties.id,
4454
feature: f,
@@ -47,8 +57,10 @@ export async function dxInitDatabases(): Promise<void> {
4757
storeData(entries, db.firs as EntityTable<any, "id">);
4858
}
4959

50-
if (serverVersions.traconsVersion !== localVersions.traconsVersion) {
51-
const features = (await fetchStaticData("tracons")) as SimAwareTraconFeature[];
60+
if (latestManifest.traconsVersion !== storedManifest?.versions.traconsVersion) {
61+
const features = (await fetchApi<SimAwareTraconFeature[]>(`${R2_BUCKET_URL}/tracons_${latestManifest.traconsVersion}.json`, {
62+
cache: "no-store",
63+
})) as SimAwareTraconFeature[];
5264
const entries: DexieFeature[] = features.map((f) => ({
5365
id: f.properties.id,
5466
feature: f,
@@ -57,16 +69,14 @@ export async function dxInitDatabases(): Promise<void> {
5769
storeData(entries, db.tracons as EntityTable<any, "id">);
5870
}
5971

60-
if (serverVersions.airlinesVersion !== localVersions.airlinesVersion) {
61-
const entries = (await fetchStaticData("airlines")) as StaticAirline[];
72+
if (latestManifest.airlinesVersion !== storedManifest?.versions.airlinesVersion) {
73+
const entries = (await fetchApi<StaticAirline[]>(`${R2_BUCKET_URL}/airlines_${latestManifest.airlinesVersion}.json`, {
74+
cache: "no-store",
75+
})) as StaticAirline[];
6276
storeData(entries, db.airlines as EntityTable<any, "id">);
6377
}
6478

65-
localStorage.setItem("databaseVersions", JSON.stringify(serverVersions));
66-
}
67-
68-
async function fetchStaticData(type: string): Promise<any> {
69-
return await fetchApi<any>(`/static/${type}`);
79+
await db.manifest.put({ key: "databaseVersions", versions: latestManifest });
7080
}
7181

7282
async function storeData(data: any[], db: EntityTable<any, "id">): Promise<void> {

docker/docker-compose.prod.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ services:
6060
args:
6161
NEXT_PUBLIC_API_URL: "https://${DOMAIN}/api"
6262
NEXT_PUBLIC_WEBSOCKET_URL: "wss://${DOMAIN}/ws"
63+
NEXT_PUBLIC_R2_BUCKET_URL: ${NEXT_PUBLIC_R2_BUCKET_URL}
6364
container_name: sr24_web
6465
restart: always
6566
environment:
@@ -194,6 +195,10 @@ services:
194195
REDIS_PORT: ${REDIS_PORT}
195196
REDIS_PASSWORD: ${REDIS_PASSWORD}
196197
REDIS_DB: ${REDIS_DB}
198+
CF_ACCOUNT_ID: ${CF_ACCOUNT_ID}
199+
R2_ACCESS_KEY_ID: ${R2_ACCESS_KEY_ID}
200+
R2_SECRET_ACCESS_KEY: ${R2_SECRET_ACCESS_KEY}
201+
R2_BUCKET_NAME: ${R2_BUCKET_NAME}
197202
depends_on:
198203
postgres:
199204
condition: service_healthy

0 commit comments

Comments
 (0)