Files
cloudly/ts/manager.settings/classes.settingsmanager.ts

255 lines
9.1 KiB
TypeScript
Raw Normal View History

import * as plugins from '../plugins.js';
import type { Cloudly } from '../classes.cloudly.js';
import * as servezoneInterfaces from '@serve.zone/interfaces';
export class CloudlySettingsManager {
public cloudlyRef: Cloudly;
public readyDeferred = plugins.smartpromise.defer();
public settingsStore: plugins.smartdata.EasyStore<servezoneInterfaces.data.ICloudlySettings>;
constructor(cloudlyRefArg: Cloudly) {
this.cloudlyRef = cloudlyRefArg;
}
/**
* Initialize the settings manager and create the EasyStore
*/
public async init() {
this.settingsStore = await this.cloudlyRef.mongodbConnector.smartdataDb
.createEasyStore('cloudly-settings') as plugins.smartdata.EasyStore<servezoneInterfaces.data.ICloudlySettings>;
// Setup API route handlers
await this.setupRoutes();
this.readyDeferred.resolve();
}
/**
* Get all settings
*/
public async getSettings(): Promise<servezoneInterfaces.data.ICloudlySettings> {
await this.readyDeferred.promise;
return await this.settingsStore.readAll();
}
/**
* Get all settings with masked sensitive values (for API responses)
*/
public async getSettingsMasked(): Promise<servezoneInterfaces.data.ICloudlySettingsMasked> {
await this.readyDeferred.promise;
const settings = await this.getSettings();
const masked: servezoneInterfaces.data.ICloudlySettingsMasked = {};
for (const [key, value] of Object.entries(settings)) {
if (typeof value === 'string' && value.length > 4) {
// Mask the token, showing only last 4 characters
masked[key] = '****' + value.slice(-4);
} else {
masked[key] = value;
}
}
return masked;
}
/**
* Update multiple settings at once
*/
public async updateSettings(updates: Partial<servezoneInterfaces.data.ICloudlySettings>): Promise<void> {
await this.readyDeferred.promise;
for (const [key, value] of Object.entries(updates)) {
if (value !== undefined && value !== '') {
await this.settingsStore.writeKey(key as keyof servezoneInterfaces.data.ICloudlySettings, value);
} else if (value === '') {
// Empty string means clear the setting
await this.settingsStore.deleteKey(key as keyof servezoneInterfaces.data.ICloudlySettings);
}
}
}
/**
* Get a specific setting value
*/
public async getSetting<K extends keyof servezoneInterfaces.data.ICloudlySettings>(key: K): Promise<servezoneInterfaces.data.ICloudlySettings[K]> {
await this.readyDeferred.promise;
return await this.settingsStore.readKey(key);
}
/**
* Set a specific setting value
*/
public async setSetting<K extends keyof servezoneInterfaces.data.ICloudlySettings>(key: K, value: servezoneInterfaces.data.ICloudlySettings[K]): Promise<void> {
await this.readyDeferred.promise;
if (value !== undefined && value !== '') {
await this.settingsStore.writeKey(key, value);
}
}
/**
* Clear a specific setting
*/
public async clearSetting(key: keyof servezoneInterfaces.data.ICloudlySettings): Promise<void> {
await this.readyDeferred.promise;
await this.settingsStore.deleteKey(key);
}
/**
* Clear all settings
*/
public async clearAllSettings(): Promise<void> {
await this.readyDeferred.promise;
await this.settingsStore.wipe();
}
/**
* Test connection for a specific provider
*/
public async testProviderConnection(provider: string): Promise<{success: boolean; message: string}> {
await this.readyDeferred.promise;
try {
switch (provider) {
case 'hetzner':
const hetznerToken = await this.getSetting('hetznerToken');
if (!hetznerToken) {
return { success: false, message: 'No Hetzner token configured' };
}
// TODO: Implement actual Hetzner API test
return { success: true, message: 'Hetzner connection test successful' };
case 'cloudflare':
const cloudflareToken = await this.getSetting('cloudflareToken');
if (!cloudflareToken) {
return { success: false, message: 'No Cloudflare token configured' };
}
// TODO: Implement actual Cloudflare API test
return { success: true, message: 'Cloudflare connection test successful' };
case 'aws':
const awsKey = await this.getSetting('awsAccessKey');
const awsSecret = await this.getSetting('awsSecretKey');
if (!awsKey || !awsSecret) {
return { success: false, message: 'AWS credentials not configured' };
}
// TODO: Implement actual AWS API test
return { success: true, message: 'AWS connection test successful' };
case 'digitalocean':
const doToken = await this.getSetting('digitalOceanToken');
if (!doToken) {
return { success: false, message: 'No DigitalOcean token configured' };
}
// TODO: Implement actual DigitalOcean API test
return { success: true, message: 'DigitalOcean connection test successful' };
case 'azure':
const azureClientId = await this.getSetting('azureClientId');
const azureClientSecret = await this.getSetting('azureClientSecret');
const azureTenantId = await this.getSetting('azureTenantId');
if (!azureClientId || !azureClientSecret || !azureTenantId) {
return { success: false, message: 'Azure credentials not configured' };
}
// TODO: Implement actual Azure API test
return { success: true, message: 'Azure connection test successful' };
default:
return { success: false, message: `Unknown provider: ${provider}` };
}
} catch (error) {
return { success: false, message: `Connection test failed: ${error.message}` };
}
}
/**
* Setup API route handlers for settings management
*/
private async setupRoutes() {
// Get Settings Handler
this.cloudlyRef.typedrouter.addTypedHandler<servezoneInterfaces.requests.settings.IRequest_GetSettings>(
new plugins.typedrequest.TypedHandler<servezoneInterfaces.requests.settings.IRequest_GetSettings>(
'getSettings',
async (requestData) => {
// TODO: Add authentication check for admin users
const maskedSettings = await this.getSettingsMasked();
return {
settings: maskedSettings
};
}
)
);
// Update Settings Handler
this.cloudlyRef.typedrouter.addTypedHandler<servezoneInterfaces.requests.settings.IRequest_UpdateSettings>(
new plugins.typedrequest.TypedHandler<servezoneInterfaces.requests.settings.IRequest_UpdateSettings>(
'updateSettings',
async (requestData) => {
// TODO: Add authentication check for admin users
try {
await this.updateSettings(requestData.updates);
return {
success: true,
message: 'Settings updated successfully'
};
} catch (error) {
return {
success: false,
message: `Failed to update settings: ${error.message}`
};
}
}
)
);
// Clear Setting Handler
this.cloudlyRef.typedrouter.addTypedHandler<servezoneInterfaces.requests.settings.IRequest_ClearSetting>(
new plugins.typedrequest.TypedHandler<servezoneInterfaces.requests.settings.IRequest_ClearSetting>(
'clearSetting',
async (requestData) => {
// TODO: Add authentication check for admin users
try {
await this.clearSetting(requestData.key);
return {
success: true,
message: `Setting ${requestData.key} cleared successfully`
};
} catch (error) {
return {
success: false,
message: `Failed to clear setting: ${error.message}`
};
}
}
)
);
// Test Provider Connection Handler
this.cloudlyRef.typedrouter.addTypedHandler<servezoneInterfaces.requests.settings.IRequest_TestProviderConnection>(
new plugins.typedrequest.TypedHandler<servezoneInterfaces.requests.settings.IRequest_TestProviderConnection>(
'testProviderConnection',
async (requestData) => {
// TODO: Add authentication check for admin users
const testResult = await this.testProviderConnection(requestData.provider);
return {
success: testResult.success,
message: testResult.message,
connectionValid: testResult.success
};
}
)
);
// Get Single Setting Handler (for internal use)
this.cloudlyRef.typedrouter.addTypedHandler<servezoneInterfaces.requests.settings.IRequest_GetSetting>(
new plugins.typedrequest.TypedHandler<servezoneInterfaces.requests.settings.IRequest_GetSetting>(
'getSetting',
async (requestData) => {
// TODO: Add authentication check for admin users
const value = await this.getSetting(requestData.key);
return {
value
};
}
)
);
}
}