refactor: complete opsserver migration
This commit is contained in:
@@ -1,210 +0,0 @@
|
||||
/**
|
||||
* API Client for communicating with Onebox daemon
|
||||
*
|
||||
* Provides methods for CLI commands to interact with running daemon via HTTP API
|
||||
*/
|
||||
|
||||
import type {
|
||||
IService,
|
||||
IRegistry,
|
||||
IDnsRecord,
|
||||
ISslCertificate,
|
||||
IServiceDeployOptions,
|
||||
} from '../types.ts';
|
||||
import { getErrorMessage } from '../utils/error.ts';
|
||||
|
||||
export class OneboxApiClient {
|
||||
private baseUrl: string;
|
||||
private token?: string;
|
||||
|
||||
constructor(port = 3000) {
|
||||
this.baseUrl = `http://localhost:${port}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if daemon is reachable
|
||||
*/
|
||||
async isReachable(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/status`, {
|
||||
signal: AbortSignal.timeout(5000), // 5 second timeout
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Service Operations ============
|
||||
|
||||
async deployService(config: IServiceDeployOptions): Promise<IService> {
|
||||
return await this.request<IService>('POST', '/api/services', config);
|
||||
}
|
||||
|
||||
async removeService(name: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/services/${name}`);
|
||||
}
|
||||
|
||||
async startService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/start`);
|
||||
}
|
||||
|
||||
async stopService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/stop`);
|
||||
}
|
||||
|
||||
async restartService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/restart`);
|
||||
}
|
||||
|
||||
async listServices(): Promise<IService[]> {
|
||||
return await this.request<IService[]>('GET', '/api/services');
|
||||
}
|
||||
|
||||
async getServiceLogs(name: string, limit = 1000): Promise<string[]> {
|
||||
const result = await this.request<{ logs: string[] }>(
|
||||
'GET',
|
||||
`/api/services/${name}/logs?limit=${limit}`
|
||||
);
|
||||
return result.logs;
|
||||
}
|
||||
|
||||
// ============ Registry Operations ============
|
||||
|
||||
async addRegistry(url: string, username: string, password: string): Promise<void> {
|
||||
await this.request('POST', '/api/registries', { url, username, password });
|
||||
}
|
||||
|
||||
async removeRegistry(url: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/registries/${encodeURIComponent(url)}`);
|
||||
}
|
||||
|
||||
async listRegistries(): Promise<IRegistry[]> {
|
||||
return await this.request<IRegistry[]>('GET', '/api/registries');
|
||||
}
|
||||
|
||||
// ============ DNS Operations ============
|
||||
|
||||
async addDnsRecord(domain: string): Promise<void> {
|
||||
await this.request('POST', '/api/dns', { domain });
|
||||
}
|
||||
|
||||
async removeDnsRecord(domain: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/dns/${domain}`);
|
||||
}
|
||||
|
||||
async listDnsRecords(): Promise<IDnsRecord[]> {
|
||||
return await this.request<IDnsRecord[]>('GET', '/api/dns');
|
||||
}
|
||||
|
||||
async syncDns(): Promise<void> {
|
||||
await this.request('POST', '/api/dns/sync');
|
||||
}
|
||||
|
||||
// ============ SSL Operations ============
|
||||
|
||||
async renewCertificate(domain?: string): Promise<void> {
|
||||
const path = domain ? `/api/ssl/renew/${domain}` : '/api/ssl/renew';
|
||||
await this.request('POST', path);
|
||||
}
|
||||
|
||||
async listCertificates(): Promise<ISslCertificate[]> {
|
||||
return await this.request<ISslCertificate[]>('GET', '/api/ssl');
|
||||
}
|
||||
|
||||
async forceRenewCertificate(domain: string): Promise<void> {
|
||||
await this.request('POST', `/api/ssl/renew/${domain}?force=true`);
|
||||
}
|
||||
|
||||
// ============ Nginx Operations ============
|
||||
|
||||
async reloadNginx(): Promise<void> {
|
||||
await this.request('POST', '/api/nginx/reload');
|
||||
}
|
||||
|
||||
async testNginx(): Promise<{ success: boolean; output: string }> {
|
||||
return await this.request('POST', '/api/nginx/test');
|
||||
}
|
||||
|
||||
async getNginxStatus(): Promise<{ status: string }> {
|
||||
return await this.request('GET', '/api/nginx/status');
|
||||
}
|
||||
|
||||
// ============ Config Operations ============
|
||||
|
||||
async getSettings(): Promise<Record<string, string>> {
|
||||
return await this.request<Record<string, string>>('GET', '/api/config');
|
||||
}
|
||||
|
||||
async setSetting(key: string, value: string): Promise<void> {
|
||||
await this.request('POST', '/api/config', { key, value });
|
||||
}
|
||||
|
||||
// ============ System Operations ============
|
||||
|
||||
async getStatus(): Promise<{
|
||||
services: { total: number; running: number; stopped: number };
|
||||
uptime: number;
|
||||
}> {
|
||||
return await this.request('GET', '/api/status');
|
||||
}
|
||||
|
||||
// ============ Helper Methods ============
|
||||
|
||||
/**
|
||||
* Make HTTP request to daemon
|
||||
*/
|
||||
private async request<T = unknown>(
|
||||
method: string,
|
||||
path: string,
|
||||
body?: unknown
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}${path}`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (this.token) {
|
||||
headers['Authorization'] = `Bearer ${this.token}`;
|
||||
}
|
||||
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers,
|
||||
signal: AbortSignal.timeout(30000), // 30 second timeout
|
||||
};
|
||||
|
||||
if (body) {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: response.statusText }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
// For DELETE and some POST requests, there might be no content
|
||||
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.name === 'TimeoutError') {
|
||||
throw new Error('Request timed out. Daemon might be unresponsive.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication token
|
||||
*/
|
||||
setToken(token: string): void {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@ import { OneboxDnsManager } from './dns.ts';
|
||||
import { OneboxSslManager } from './ssl.ts';
|
||||
import { OneboxDaemon } from './daemon.ts';
|
||||
import { OneboxSystemd } from './systemd.ts';
|
||||
import type { OneboxHttpServer } from './httpserver.ts';
|
||||
import { CloudflareDomainSync } from './cloudflare-sync.ts';
|
||||
import { CertRequirementManager } from './cert-requirement-manager.ts';
|
||||
import { RegistryManager } from './registry.ts';
|
||||
@@ -37,7 +36,6 @@ export class Onebox {
|
||||
public ssl: OneboxSslManager;
|
||||
public daemon: OneboxDaemon;
|
||||
public systemd: OneboxSystemd;
|
||||
public httpServer: OneboxHttpServer | null;
|
||||
public cloudflareDomainSync: CloudflareDomainSync;
|
||||
public certRequirementManager: CertRequirementManager;
|
||||
public registry: RegistryManager;
|
||||
@@ -63,7 +61,6 @@ export class Onebox {
|
||||
this.ssl = new OneboxSslManager(this);
|
||||
this.daemon = new OneboxDaemon(this);
|
||||
this.systemd = new OneboxSystemd();
|
||||
this.httpServer = null;
|
||||
this.registry = new RegistryManager({
|
||||
dataDir: './.nogit/registry-data',
|
||||
port: 4000,
|
||||
|
||||
Reference in New Issue
Block a user