feat: реализовать EvoFirewall V1 control plane
API, UI, Linux/MikroTik agents, IP lists, политики, stats, CI и интеграция с auth-portal/EvoBGP. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { readFileSync, readdirSync, mkdirSync } from 'node:fs'
|
||||
import Database from 'better-sqlite3'
|
||||
import { drizzle } from 'drizzle-orm/better-sqlite3'
|
||||
import { schema } from './schema.js'
|
||||
|
||||
export type Sqlite = Database.Database
|
||||
export type Db = ReturnType<typeof drizzle<typeof schema>>
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export function resolveDatabasePath(databaseUrl: string): string {
|
||||
const url = databaseUrl.startsWith('sqlite:')
|
||||
? databaseUrl.slice('sqlite:'.length)
|
||||
: databaseUrl
|
||||
return url
|
||||
}
|
||||
|
||||
export function createDb(databaseUrl: string): { db: Db; sqlite: Sqlite } {
|
||||
const path = resolveDatabasePath(databaseUrl)
|
||||
const dir = dirname(path)
|
||||
if (dir && dir !== '.') {
|
||||
try {
|
||||
mkdirSync(dir, { recursive: true })
|
||||
} catch {
|
||||
/* exists */
|
||||
}
|
||||
}
|
||||
const sqlite = new Database(path)
|
||||
sqlite.pragma('journal_mode = WAL')
|
||||
sqlite.pragma('synchronous = NORMAL')
|
||||
sqlite.pragma('foreign_keys = ON')
|
||||
const db = drizzle(sqlite, { schema })
|
||||
return { db, sqlite }
|
||||
}
|
||||
|
||||
export function createMemoryDb(): { db: Db; sqlite: Sqlite } {
|
||||
const sqlite = new Database(':memory:')
|
||||
sqlite.pragma('foreign_keys = ON')
|
||||
const db = drizzle(sqlite, { schema })
|
||||
return { db, sqlite }
|
||||
}
|
||||
|
||||
export function runMigrations(sqlite: Sqlite): void {
|
||||
const migrationsDir = join(__dirname, '..', 'migrations')
|
||||
const files = readdirSync(migrationsDir)
|
||||
.filter((f) => f.endsWith('.sql'))
|
||||
.sort()
|
||||
|
||||
sqlite.exec(
|
||||
`CREATE TABLE IF NOT EXISTS _migrations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)`,
|
||||
)
|
||||
|
||||
for (const file of files) {
|
||||
const applied = sqlite
|
||||
.prepare('SELECT 1 FROM _migrations WHERE name = ?')
|
||||
.get(file)
|
||||
if (applied) continue
|
||||
|
||||
const sql = readFileSync(join(migrationsDir, file), 'utf-8')
|
||||
sqlite.exec(sql)
|
||||
sqlite.prepare('INSERT INTO _migrations (name) VALUES (?)').run(file)
|
||||
}
|
||||
}
|
||||
|
||||
export function healthCheck(sqlite: Sqlite): void {
|
||||
sqlite.prepare('SELECT 1').get()
|
||||
}
|
||||
Reference in New Issue
Block a user