agmission/Development/server/helpers/partner_config.js

349 lines
12 KiB
JavaScript

'use strict';
/**
* Partner System Configuration Helper
* Manages environment-based configuration for partner integrations
*/
const env = require('./env');
const utils = require('./utils');
const { AuthMethods } = require('./constants');
class PartnerConfig {
constructor() {
this.configs = {
SATLOC: {
apiEndpoint: env.SATLOC_API_ENDPOINT,
authMethod: AuthMethods.USERNAME_PASSWORD,
// Optional: Global fallback credentials (rarely used in production)
defaultApiKey: env.SATLOC_API_KEY || null,
defaultApiSecret: env.SATLOC_API_SECRET || null,
timeout: parseInt(env.SATLOC_API_TIMEOUT) || 30000,
retryAttempts: parseInt(env.SATLOC_RETRY_ATTEMPTS) || 3,
retryDelay: parseInt(env.SATLOC_RETRY_DELAY) || 1000,
rateLimit: {
requestsPerMinute: parseInt(env.SATLOC_RATE_LIMIT) || 60,
burstLimit: parseInt(env.SATLOC_BURST_LIMIT) || 10
},
features: {
supportsRealTime: utils.stringToBoolean(env.SATLOC_REALTIME_ENABLED),
supportsFileUpload: env.SATLOC_FILE_UPLOAD_ENABLED !== 'false',
maxFileSize: parseInt(env.SATLOC_MAX_FILE_SIZE) || 10485760 // 10MB
},
storage: {
basePath: env.SATLOC_STORAGE_PATH || '/data/partners/satloc',
tempPath: env.SATLOC_TEMP_PATH || '/tmp/satloc',
logFileExtensions: ['.log', '.LOG'],
maxFileAge: parseInt(env.SATLOC_MAX_FILE_AGE) || 7776000000 // 90 days in ms
}
},
AGIDRONEX: {
apiEndpoint: env.AGIDRONEX_API_ENDPOINT || 'https://api.agidronex.com/v1',
authMethod: AuthMethods.API_KEY,
// Optional: Global fallback credentials (rarely used in production)
defaultApiKey: env.AGIDRONEX_API_KEY || null,
defaultApiSecret: env.AGIDRONEX_API_SECRET || null,
defaultUsername: env.AGIDRONEX_USERNAME || null,
defaultPassword: env.AGIDRONEX_PASSWORD || null,
timeout: parseInt(env.AGIDRONEX_API_TIMEOUT) || 25000,
retryAttempts: parseInt(env.AGIDRONEX_RETRY_ATTEMPTS) || 3,
retryDelay: parseInt(env.AGIDRONEX_RETRY_DELAY) || 1500,
rateLimit: {
requestsPerMinute: parseInt(env.AGIDRONEX_RATE_LIMIT) || 100,
burstLimit: parseInt(env.AGIDRONEX_BURST_LIMIT) || 20
},
features: {
supportsRealTime: utils.stringToBoolean(env.AGIDRONEX_REALTIME_ENABLED),
supportsFileUpload: env.AGIDRONEX_FILE_UPLOAD_ENABLED !== 'false',
maxFileSize: parseInt(env.AGIDRONEX_MAX_FILE_SIZE) || 20971520 // 20MB
},
storage: {
basePath: env.AGIDRONEX_STORAGE_PATH || '/data/partners/agidronex',
tempPath: env.AGIDRONEX_TEMP_PATH || '/tmp/agidronex',
logFileExtensions: ['.log', '.LOG', '.txt', '.dat'],
maxFileAge: parseInt(env.AGIDRONEX_MAX_FILE_AGE) || 7776000000 // 90 days in ms
}
}
};
// Global partner system settings
this.globalConfig = {
syncInterval: parseInt(env.PARTNER_SYNC_INTERVAL) || 300000, // 5 minutes
healthCheckInterval: parseInt(env.PARTNER_HEALTH_CHECK_INTERVAL) || 60000, // 1 minute
maxConcurrentJobs: parseInt(env.PARTNER_MAX_CONCURRENT_JOBS) || 10,
jobTimeout: parseInt(env.PARTNER_JOB_TIMEOUT) || 1800000, // 30 minutes
enableMetrics: env.PARTNER_METRICS_ENABLED !== 'false',
enableDetailedLogging: utils.stringToBoolean(env.PARTNER_DETAILED_LOGGING),
encryptCredentials: env.PARTNER_ENCRYPT_CREDENTIALS !== 'false'
};
}
/**
* Get configuration for a specific partner
* @param {string} partnerCode - Partner code (e.g., 'SATLOC', 'AGIDRONEX')
* @returns {object} Partner configuration
*/
getPartnerConfig(partnerCode) {
const config = this.configs[partnerCode.toUpperCase()];
if (!config) {
throw new Error(`Partner configuration not found for: ${partnerCode}`);
}
return { ...config };
}
/**
* Get global partner system configuration
* @returns {object} Global configuration
*/
getGlobalConfig() {
return { ...this.globalConfig };
}
/**
* Get API credentials for a partner system user
* @param {object} partnerSystemUser - Partner system user document
* @param {string} partnerCode - Partner code
* @returns {object} API credentials and endpoint
*/
getApiCredentials(partnerSystemUser, partnerCode) {
const partnerConfig = this.getPartnerConfig(partnerCode);
const authMethod = partnerConfig.authMethod || AuthMethods.API_KEY;
const credentials = {
endpoint: partnerConfig.apiEndpoint,
authMethod,
// Additional parameters for API calls
companyId: partnerSystemUser.companyId,
partnerUserId: partnerSystemUser.partnerUserId,
partnerUsername: partnerSystemUser.partnerUsername
};
// Handle different authentication methods
switch (authMethod) {
case AuthMethods.USERNAME_PASSWORD:
const username = partnerSystemUser.partnerUsername || partnerSystemUser.username;
const password = partnerSystemUser.password;
if (!username || !password) {
throw new Error(`Missing username/password credentials for ${partnerCode} user: ${partnerSystemUser.partnerUserId || partnerSystemUser._id}`);
}
credentials.username = username;
credentials.password = password;
// For SatLoc specifically, sometimes userId is used instead of username
credentials.userId = partnerSystemUser.partnerUserId || username;
break;
case AuthMethods.API_KEY:
const apiKey = partnerSystemUser.apiKey || partnerConfig.defaultApiKey;
const apiSecret = partnerSystemUser.apiSecret || partnerConfig.defaultApiSecret;
if (!apiKey || !apiSecret) {
throw new Error(`Missing API key/secret credentials for ${partnerCode} user: ${partnerSystemUser.partnerUserId || partnerSystemUser._id}`);
}
credentials.apiKey = apiKey;
credentials.apiSecret = apiSecret;
break;
case AuthMethods.OAUTH:
const accessToken = partnerSystemUser.accessToken;
const refreshToken = partnerSystemUser.refreshToken;
if (!accessToken) {
throw new Error(`Missing OAuth access token for ${partnerCode} user: ${partnerSystemUser.partnerUserId || partnerSystemUser._id}`);
}
credentials.accessToken = accessToken;
credentials.refreshToken = refreshToken;
break;
case AuthMethods.BEARER_TOKEN:
const bearerToken = partnerSystemUser.bearerToken || partnerSystemUser.accessToken;
if (!bearerToken) {
throw new Error(`Missing bearer token for ${partnerCode} user: ${partnerSystemUser.partnerUserId || partnerSystemUser._id}`);
}
credentials.bearerToken = bearerToken;
break;
default:
throw new Error(`Unsupported authentication method: ${authMethod} for ${partnerCode}`);
}
return credentials;
}
/**
* Get request configuration for API calls
* @param {string} partnerCode - Partner code
* @returns {object} Request configuration
*/
getRequestConfig(partnerCode) {
const config = this.getPartnerConfig(partnerCode);
return {
timeout: config.timeout,
retryAttempts: config.retryAttempts,
retryDelay: config.retryDelay,
headers: {
'Content-Type': 'application/json',
'User-Agent': `AgMission-Integration/1.0 (${partnerCode})`
}
};
}
/**
* Check if a feature is enabled for a partner
* @param {string} partnerCode - Partner code
* @param {string} feature - Feature name
* @returns {boolean} Whether feature is enabled
*/
isFeatureEnabled(partnerCode, feature) {
const config = this.getPartnerConfig(partnerCode);
return config.features[feature] || false;
}
/**
* Get rate limiting configuration for a partner
* @param {string} partnerCode - Partner code
* @returns {object} Rate limit configuration
*/
getRateLimitConfig(partnerCode) {
const config = this.getPartnerConfig(partnerCode);
return { ...config.rateLimit };
}
/**
* Validate partner configuration
* @param {string} partnerCode - Partner code
* @returns {object} Validation result
*/
validateConfig(partnerCode) {
try {
const config = this.getPartnerConfig(partnerCode);
const issues = [];
const authMethod = config.authMethod || AuthMethods.API_KEY;
if (!config.apiEndpoint) {
issues.push(`Missing API endpoint for ${partnerCode}`);
}
// Validate auth method
if (!Object.values(AuthMethods).includes(authMethod)) {
issues.push(`Unknown authentication method: ${authMethod} for ${partnerCode}`);
}
// Check if default credentials are available (optional warning)
switch (authMethod) {
case AuthMethods.USERNAME_PASSWORD:
if (!config.defaultUsername && !config.defaultPassword) {
issues.push(`No default username/password configured for ${partnerCode} (optional - credentials typically come from partner system users)`);
}
break;
case AuthMethods.API_KEY:
if (!config.defaultApiKey && !config.defaultApiSecret) {
issues.push(`No default API key/secret configured for ${partnerCode} (optional - credentials typically come from partner system users)`);
}
break;
case AuthMethods.OAUTH:
case AuthMethods.BEARER_TOKEN:
// These typically don't have default credentials
break;
}
if (config.timeout < 5000) {
issues.push(`Timeout too low for ${partnerCode}: ${config.timeout}ms`);
}
return {
valid: issues.length === 0,
issues,
config,
authMethod
};
} catch (error) {
return {
valid: false,
issues: [error.message],
config: null,
authMethod: null
};
}
}
/**
* Get environment variable names for a partner
* @param {string} partnerCode - Partner code
* @returns {array} Environment variable names
*/
getEnvVarNames(partnerCode) {
const prefix = partnerCode.toUpperCase();
return [
`${prefix}_API_ENDPOINT`,
`${prefix}_API_KEY`,
`${prefix}_API_SECRET`,
`${prefix}_USERNAME`,
`${prefix}_PASSWORD`,
`${prefix}_API_TIMEOUT`,
`${prefix}_RETRY_ATTEMPTS`,
`${prefix}_RETRY_DELAY`,
`${prefix}_RATE_LIMIT`,
`${prefix}_BURST_LIMIT`,
`${prefix}_REALTIME_ENABLED`,
`${prefix}_FILE_UPLOAD_ENABLED`,
`${prefix}_MAX_FILE_SIZE`
];
}
/**
* Generate sample environment file content
* @returns {string} Sample .env content
*/
generateSampleEnv() {
return `
# Partner System Configuration
# Global Settings
PARTNER_SYNC_INTERVAL=300000
PARTNER_HEALTH_CHECK_INTERVAL=60000
PARTNER_MAX_CONCURRENT_JOBS=10
PARTNER_JOB_TIMEOUT=1800000
PARTNER_METRICS_ENABLED=true
PARTNER_DETAILED_LOGGING=false
PARTNER_ENCRYPT_CREDENTIALS=true
# SatLoc Configuration (Uses USERNAME_PASSWORD auth)
SATLOC_API_ENDPOINT=https://www.satloccloud.com/api/Satloc
# Optional: Global fallback credentials (each customer should have their own partner system user)
# SATLOC_USERNAME=your_global_satloc_username
# SATLOC_PASSWORD=your_global_satloc_password
SATLOC_API_TIMEOUT=30000
SATLOC_RETRY_ATTEMPTS=3
SATLOC_RETRY_DELAY=1000
SATLOC_RATE_LIMIT=60
SATLOC_BURST_LIMIT=10
SATLOC_REALTIME_ENABLED=false
SATLOC_FILE_UPLOAD_ENABLED=true
SATLOC_MAX_FILE_SIZE=10485760
# AgIDronex Configuration (Uses API_KEY auth)
AGIDRONEX_API_ENDPOINT=https://api.agidronex.com/v1
# Optional: Global fallback credentials (each customer should have their own partner system user)
# AGIDRONEX_API_KEY=your_global_agidronex_api_key
# AGIDRONEX_API_SECRET=your_global_agidronex_api_secret
AGIDRONEX_API_TIMEOUT=25000
AGIDRONEX_RETRY_ATTEMPTS=3
AGIDRONEX_RETRY_DELAY=1500
AGIDRONEX_RATE_LIMIT=100
AGIDRONEX_BURST_LIMIT=20
AGIDRONEX_REALTIME_ENABLED=true
AGIDRONEX_FILE_UPLOAD_ENABLED=true
AGIDRONEX_MAX_FILE_SIZE=20971520
`.trim();
}
}
module.exports = new PartnerConfig();