2026-02-09 00:04:45 -05:00
|
|
|
import Database from 'better-sqlite3';
|
2026-02-09 00:17:44 -05:00
|
|
|
import type BetterSqlite3 from 'better-sqlite3';
|
2026-02-09 00:04:45 -05:00
|
|
|
import path from 'path';
|
|
|
|
|
import fs from 'fs';
|
|
|
|
|
|
2026-02-09 00:17:44 -05:00
|
|
|
let db: BetterSqlite3.Database | null = null;
|
|
|
|
|
let insertStmt: BetterSqlite3.Statement | null = null;
|
2026-02-09 00:04:45 -05:00
|
|
|
|
2026-02-09 00:17:44 -05:00
|
|
|
function getDb() {
|
|
|
|
|
if (db) return db;
|
2026-02-09 00:04:45 -05:00
|
|
|
|
2026-02-09 00:17:44 -05:00
|
|
|
try {
|
|
|
|
|
const SERVER_STORAGE = '/server_storage';
|
|
|
|
|
let dbDir: string;
|
|
|
|
|
try {
|
|
|
|
|
fs.accessSync(SERVER_STORAGE, fs.constants.W_OK);
|
|
|
|
|
dbDir = SERVER_STORAGE;
|
|
|
|
|
} catch {
|
|
|
|
|
dbDir = process.cwd();
|
|
|
|
|
}
|
2026-02-09 00:04:45 -05:00
|
|
|
|
2026-02-09 00:17:44 -05:00
|
|
|
const dbPath = path.join(dbDir, 'visitors.db');
|
|
|
|
|
db = new Database(dbPath);
|
|
|
|
|
db.pragma('journal_mode = WAL');
|
|
|
|
|
|
|
|
|
|
db.exec(`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS visits (
|
|
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
|
ip_address TEXT NOT NULL,
|
|
|
|
|
path TEXT NOT NULL,
|
|
|
|
|
visited_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
|
|
|
);
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
insertStmt = db.prepare(
|
|
|
|
|
'INSERT INTO visits (ip_address, path) VALUES (?, ?)'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return db;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Failed to initialize SQLite database:', e);
|
|
|
|
|
db = null;
|
|
|
|
|
insertStmt = null;
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-09 00:04:45 -05:00
|
|
|
|
|
|
|
|
export function logVisit(ip: string, visitPath: string) {
|
2026-02-09 00:17:44 -05:00
|
|
|
const database = getDb();
|
|
|
|
|
if (!database || !insertStmt) return;
|
2026-02-09 00:04:45 -05:00
|
|
|
insertStmt.run(ip, visitPath);
|
|
|
|
|
}
|