100 lines
2.2 KiB
TypeScript
100 lines
2.2 KiB
TypeScript
|
|
import fs from 'fs';
|
||
|
|
import path from 'path';
|
||
|
|
import crypto from 'crypto';
|
||
|
|
|
||
|
|
export type AccessMode = 'private' | 'public';
|
||
|
|
|
||
|
|
export interface TunnelConfig
|
||
|
|
{
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
description: string;
|
||
|
|
purpose: string;
|
||
|
|
ownerId: string;
|
||
|
|
access: AccessMode;
|
||
|
|
allowedUserIds: string[];
|
||
|
|
localPort: number;
|
||
|
|
createdAt: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const DB_PATH = path.join( __dirname, '..', '..', '..', 'build', 'data', 'db', 'tunnels.json' );
|
||
|
|
|
||
|
|
function ensureDir(): void
|
||
|
|
{
|
||
|
|
fs.mkdirSync( path.dirname( DB_PATH ), { recursive: true } );
|
||
|
|
}
|
||
|
|
|
||
|
|
function readAll(): TunnelConfig[]
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
return JSON.parse( fs.readFileSync( DB_PATH, 'utf-8' ) );
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function writeAll( tunnels: TunnelConfig[] ): void
|
||
|
|
{
|
||
|
|
ensureDir();
|
||
|
|
fs.writeFileSync( DB_PATH, JSON.stringify( tunnels, null, 2 ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
export function createTunnel( data: Omit<TunnelConfig, 'id' | 'createdAt'> ): TunnelConfig
|
||
|
|
{
|
||
|
|
const tunnel: TunnelConfig = {
|
||
|
|
...data,
|
||
|
|
id: crypto.randomUUID(),
|
||
|
|
createdAt: new Date().toISOString(),
|
||
|
|
};
|
||
|
|
const all = readAll();
|
||
|
|
all.push( tunnel );
|
||
|
|
writeAll( all );
|
||
|
|
return tunnel;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getTunnel( id: string ): TunnelConfig | undefined
|
||
|
|
{
|
||
|
|
return readAll().find( t => t.id === id );
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getTunnelsByOwner( ownerId: string ): TunnelConfig[]
|
||
|
|
{
|
||
|
|
return readAll().filter( t => t.ownerId === ownerId );
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getAvailableTunnels( userId: string, purpose?: string ): TunnelConfig[]
|
||
|
|
{
|
||
|
|
let tunnels = readAll().filter( t =>
|
||
|
|
t.ownerId === userId ||
|
||
|
|
t.access === 'public' ||
|
||
|
|
t.allowedUserIds.includes( userId )
|
||
|
|
);
|
||
|
|
if ( purpose ) tunnels = tunnels.filter( t => t.purpose === purpose );
|
||
|
|
return tunnels;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function updateTunnel(
|
||
|
|
id: string,
|
||
|
|
patch: Partial<Pick<TunnelConfig, 'name' | 'description' | 'access' | 'allowedUserIds' | 'purpose'>>
|
||
|
|
): TunnelConfig | undefined
|
||
|
|
{
|
||
|
|
const all = readAll();
|
||
|
|
const idx = all.findIndex( t => t.id === id );
|
||
|
|
if ( idx === -1 ) return undefined;
|
||
|
|
all[ idx ] = { ...all[ idx ], ...patch };
|
||
|
|
writeAll( all );
|
||
|
|
return all[ idx ];
|
||
|
|
}
|
||
|
|
|
||
|
|
export function deleteTunnel( id: string ): boolean
|
||
|
|
{
|
||
|
|
const all = readAll();
|
||
|
|
const filtered = all.filter( t => t.id !== id );
|
||
|
|
if ( filtered.length === all.length ) return false;
|
||
|
|
writeAll( filtered );
|
||
|
|
return true;
|
||
|
|
}
|