feat: add dynamic user-agent version updater
- Add user-agent-updater.js to automatically fetch latest factory-cli version - Fetch version from https://downloads.factory.ai/factory-cli/LATEST on startup - Automatically refresh version every hour - Implement retry mechanism: max 3 retries with 1-minute intervals on failure - Use user_agent from config.json as fallback value - Update config.js to use dynamic user-agent - Initialize updater in server.js startup sequence
This commit is contained in:
@@ -2,6 +2,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { logInfo } from './logger.js';
|
||||
import { getCurrentUserAgent } from './user-agent-updater.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -64,8 +65,7 @@ export function getModelReasoning(modelId) {
|
||||
}
|
||||
|
||||
export function getUserAgent() {
|
||||
const cfg = getConfig();
|
||||
return cfg.user_agent || 'factory-cli/0.19.3';
|
||||
return getCurrentUserAgent();
|
||||
}
|
||||
|
||||
export function getProxyConfigs() {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { loadConfig, isDevMode, getPort } from './config.js';
|
||||
import { logInfo, logError } from './logger.js';
|
||||
import router from './routes.js';
|
||||
import { initializeAuth } from './auth.js';
|
||||
import { initializeUserAgentUpdater } from './user-agent-updater.js';
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -112,6 +113,9 @@ app.use((err, req, res, next) => {
|
||||
logInfo('Configuration loaded successfully');
|
||||
logInfo(`Dev mode: ${isDevMode()}`);
|
||||
|
||||
// Initialize User-Agent version updater
|
||||
initializeUserAgentUpdater();
|
||||
|
||||
// Initialize auth system (load and setup API key if needed)
|
||||
// This won't throw error if no auth config is found - will use client auth
|
||||
await initializeAuth();
|
||||
|
||||
114
user-agent-updater.js
Normal file
114
user-agent-updater.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import https from 'https';
|
||||
import { logInfo, logError } from './logger.js';
|
||||
import { getConfig } from './config.js';
|
||||
|
||||
const VERSION_URL = 'https://downloads.factory.ai/factory-cli/LATEST';
|
||||
const USER_AGENT_PREFIX = 'factory-cli';
|
||||
const CHECK_INTERVAL = 60 * 60 * 1000; // 1 hour
|
||||
const RETRY_INTERVAL = 60 * 1000; // 1 minute
|
||||
const MAX_RETRIES = 3;
|
||||
|
||||
let currentVersion = null;
|
||||
let isUpdating = false;
|
||||
|
||||
function getDefaultVersion() {
|
||||
const cfg = getConfig();
|
||||
const userAgent = cfg.user_agent || 'factory-cli/0.19.3';
|
||||
const match = userAgent.match(/\/(\d+\.\d+\.\d+)/);
|
||||
return match ? match[1] : '0.19.3';
|
||||
}
|
||||
|
||||
function initializeVersion() {
|
||||
if (currentVersion === null) {
|
||||
currentVersion = getDefaultVersion();
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentUserAgent() {
|
||||
initializeVersion();
|
||||
return `${USER_AGENT_PREFIX}/${currentVersion}`;
|
||||
}
|
||||
|
||||
function fetchLatestVersion() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = https.get(VERSION_URL, (res) => {
|
||||
let data = '';
|
||||
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error(`HTTP ${res.statusCode}`));
|
||||
return;
|
||||
}
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
const version = data.trim();
|
||||
if (version && /^\d+\.\d+\.\d+/.test(version)) {
|
||||
resolve(version);
|
||||
} else {
|
||||
reject(new Error(`Invalid version format: ${version}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
request.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
request.setTimeout(10000, () => {
|
||||
request.destroy();
|
||||
reject(new Error('Request timeout'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function updateVersionWithRetry(retryCount = 0) {
|
||||
if (isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
isUpdating = true;
|
||||
|
||||
try {
|
||||
const version = await fetchLatestVersion();
|
||||
if (version !== currentVersion) {
|
||||
const oldVersion = currentVersion;
|
||||
currentVersion = version;
|
||||
logInfo(`User-Agent version updated: ${oldVersion} -> ${currentVersion}`);
|
||||
} else {
|
||||
logInfo(`User-Agent version is up to date: ${currentVersion}`);
|
||||
}
|
||||
isUpdating = false;
|
||||
} catch (error) {
|
||||
logError(`Failed to fetch latest version (attempt ${retryCount + 1}/${MAX_RETRIES})`, error);
|
||||
|
||||
if (retryCount < MAX_RETRIES - 1) {
|
||||
logInfo(`Retrying in 1 minute...`);
|
||||
setTimeout(() => {
|
||||
updateVersionWithRetry(retryCount + 1);
|
||||
}, RETRY_INTERVAL);
|
||||
} else {
|
||||
logError(`Max retries reached. Will try again in next hourly check.`);
|
||||
isUpdating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeUserAgentUpdater() {
|
||||
initializeVersion();
|
||||
logInfo('Initializing User-Agent version updater...');
|
||||
logInfo(`Default User-Agent from config: ${USER_AGENT_PREFIX}/${currentVersion}`);
|
||||
|
||||
// Fetch immediately on startup
|
||||
updateVersionWithRetry();
|
||||
|
||||
// Schedule hourly checks
|
||||
setInterval(() => {
|
||||
logInfo('Running scheduled User-Agent version check...');
|
||||
updateVersionWithRetry();
|
||||
}, CHECK_INTERVAL);
|
||||
|
||||
logInfo(`User-Agent updater initialized. Will check every hour.`);
|
||||
}
|
||||
Reference in New Issue
Block a user