196 lines
5.9 KiB
TypeScript
196 lines
5.9 KiB
TypeScript
import db from '../lib/db';
|
|
import * as satellite from 'satellite.js';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { CosmicEvent } from '@/types/space';
|
|
|
|
const MY_LAT = 55.6683;
|
|
const MY_LON = 12.5333;
|
|
const MY_ALT = 0;
|
|
|
|
|
|
async function updateISSData() {
|
|
console.log("🛰️ Fetching TLE data...");
|
|
|
|
const response = await fetch('https://celestrak.org/NORAD/elements/gp.php?CATNR=25544&FORMAT=tle');
|
|
const data = await response.text();
|
|
const lines = data.split('\n').filter(line => line.trim().length > 0);
|
|
|
|
const line1 = lines[1];
|
|
const line2 = lines[2];
|
|
const satrec = satellite.twoline2satrec(line1, line2);
|
|
|
|
const observerGd = {
|
|
longitude: satellite.degreesToRadians(MY_LON),
|
|
latitude: satellite.degreesToRadians(MY_LAT),
|
|
height: MY_ALT
|
|
};
|
|
|
|
const passesFound: { start: Date, end: Date }[] = [];
|
|
const now = new Date();
|
|
const searchTime = new Date(now.getTime());
|
|
|
|
const maxSearchMinutes = 2880;
|
|
let minutesSearched = 0;
|
|
|
|
while (passesFound.length < 2 && minutesSearched < maxSearchMinutes) {
|
|
const checkTime = new Date(searchTime.getTime() + (minutesSearched * 60000));
|
|
const positionAndVelocity = satellite.propagate(satrec, checkTime);
|
|
const gmst = satellite.gstime(checkTime);
|
|
|
|
if (typeof positionAndVelocity?.position !== 'boolean') {
|
|
const positionEcf = satellite.eciToEcf(positionAndVelocity!.position, gmst);
|
|
const lookAngles = satellite.ecfToLookAngles(observerGd, positionEcf);
|
|
const elevation = satellite.radiansToDegrees(lookAngles.elevation);
|
|
|
|
if (elevation > 0) {
|
|
const aos = checkTime;
|
|
let los = new Date(aos.getTime() + 5 * 60000);
|
|
|
|
for (let j = 1; j < 20; j++) {
|
|
const exitTime = new Date(aos.getTime() + j * 60000);
|
|
const pos = satellite.propagate(satrec, exitTime);
|
|
const gmstExit = satellite.gstime(exitTime);
|
|
if (typeof pos?.position !== 'boolean') {
|
|
const lookExit = satellite.ecfToLookAngles(observerGd, satellite.eciToEcf(pos!.position, gmstExit));
|
|
if (satellite.radiansToDegrees(lookExit.elevation) < 0) {
|
|
los = exitTime;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
passesFound.push({ start: aos, end: los });
|
|
|
|
minutesSearched += 90;
|
|
continue;
|
|
}
|
|
}
|
|
minutesSearched++;
|
|
}
|
|
|
|
db.prepare('DELETE FROM iss_passes').run();
|
|
const insert = db.prepare('INSERT INTO iss_passes (pass_time, end_time) VALUES (?, ?)');
|
|
|
|
for (const pass of passesFound) {
|
|
insert.run(pass.start.toISOString(), pass.end.toISOString());
|
|
}
|
|
|
|
console.log(`✅ Stored ${passesFound.length} future passes with start and end times.`);
|
|
}
|
|
|
|
function updateMoonPhase() {
|
|
const LUNAR_CYCLE = 29.53059;
|
|
const KNOWN_NEW_MOON = new Date('2024-01-11T11:57:00Z');
|
|
|
|
const now = new Date();
|
|
const daysSince = (now.getTime() - KNOWN_NEW_MOON.getTime()) / 86400000;
|
|
const progress = daysSince % LUNAR_CYCLE;
|
|
|
|
const daysToFull = (LUNAR_CYCLE / 2) - progress;
|
|
const daysToNew = LUNAR_CYCLE - progress;
|
|
|
|
const moon = daysToFull > 0
|
|
? { title: "Next Full Moon", date: new Date(now.getTime() + daysToFull * 86400000) }
|
|
: { title: "Next New Moon", date: new Date(now.getTime() + daysToNew * 86400000) };
|
|
|
|
db.prepare(`
|
|
INSERT INTO global_events (id, title, event_time) VALUES ('moon_phase', ?, ?)
|
|
ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time
|
|
`).run(moon.title, moon.date.toISOString());
|
|
|
|
console.log(`🌙 Moon: ${moon.title}`);
|
|
}
|
|
|
|
function updateCosmicEvents() {
|
|
const configPath = path.resolve(process.cwd(), 'config/events.json');
|
|
if (!fs.existsSync(configPath)) return;
|
|
|
|
const events: CosmicEvent[] = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
const now = new Date();
|
|
|
|
const next = events
|
|
.filter((e) => new Date(e.event_time) > now)
|
|
.sort((a, b) => new Date(a.event_time).getTime() - new Date(b.event_time).getTime())[0];
|
|
|
|
if (next) {
|
|
db.prepare(`
|
|
INSERT INTO global_events (id, title, event_time) VALUES ('next_cosmic_event', ?, ?)
|
|
ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time
|
|
`).run(next.title, next.event_time);
|
|
console.log(`✨ Cosmic: ${next.title}`);
|
|
}
|
|
}
|
|
|
|
async function updateRocketLaunches() {
|
|
try {
|
|
const nowISO = new Date().toISOString();
|
|
const url = `https://lldev.thespacedevs.com/2.2.0/launch/upcoming/?limit=1&mode=list&net__gt=${nowISO}`;
|
|
|
|
const response = await fetch(url);
|
|
const data = await response.json();
|
|
|
|
if (data.results && data.results.length > 0) {
|
|
const launch = data.results[0];
|
|
|
|
db.prepare(`
|
|
INSERT INTO global_events (id, title, event_time)
|
|
VALUES ('next_launch', ?, ?)
|
|
ON CONFLICT(id) DO UPDATE SET title=excluded.title, event_time=excluded.event_time
|
|
`).run(
|
|
`Launch: ${launch.name}`,
|
|
launch.net
|
|
);
|
|
|
|
console.log(`🚀 Rocket Sync: ${launch.name}`);
|
|
}
|
|
} catch (error) {
|
|
console.error("❌ Rocket Fetch Error:", error);
|
|
}
|
|
}
|
|
|
|
async function updateAllData() {
|
|
console.log("📡 Starting Ground Station sync...");
|
|
|
|
try {
|
|
await updateISSData();
|
|
} catch (e) {
|
|
console.error("⚠️ ISS sync failed (Timeout/Network)", e);
|
|
}
|
|
|
|
try {
|
|
updateMoonPhase();
|
|
} catch (e) {
|
|
console.error("⚠️ Moon sync failed", e);
|
|
}
|
|
|
|
try {
|
|
updateCosmicEvents();
|
|
} catch (e) {
|
|
console.error("⚠️ Cosmic sync failed", e);
|
|
}
|
|
|
|
try {
|
|
await updateRocketLaunches();
|
|
} catch (e) {
|
|
console.error("⚠️ Rocket sync failed", e);
|
|
}
|
|
}
|
|
|
|
async function startWorker() {
|
|
console.log("🛰️ Ground Station Worker started...");
|
|
|
|
while (true) {
|
|
try {
|
|
await updateAllData();
|
|
console.log("✅ Sync complete. Sleeping for 1 hour...");
|
|
} catch (err) {
|
|
console.error("❌ Worker loop error:", err);
|
|
}
|
|
|
|
// Sleep for 3600000ms (1 hour)
|
|
await new Promise(resolve => setTimeout(resolve, 3600000));
|
|
}
|
|
}
|
|
|
|
startWorker(); |