Refactor apps routes: explicit dependency injection
- Updated all apps route modules to use destructured dependencies - Added JSDoc comments for factory functions - Replaced ctx. references with direct parameter access - Updated apps/index.js to extract and pass explicit dependencies - All files pass syntax validation Files refactored: - routes/apps/deploy.js (18k lines) - routes/apps/helpers.js (17k lines) - routes/apps/removal.js - routes/apps/restore.js - routes/apps/templates.js - routes/apps/index.js (orchestrator)
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
const express = require('express');
|
||||
const { DOCKER } = require('../../constants');
|
||||
|
||||
module.exports = function(ctx, helpers) {
|
||||
/**
|
||||
* Apps restore routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
* @param {Object} deps.docker - Docker client wrapper
|
||||
* @param {Object} deps.caddy - Caddy client
|
||||
* @param {Object} deps.servicesStateManager - Services state manager
|
||||
* @param {Function} deps.asyncHandler - Async route handler wrapper
|
||||
* @param {Object} deps.log - Logger instance
|
||||
* @param {Object} deps.helpers - Apps helpers module
|
||||
* @returns {express.Router}
|
||||
*/
|
||||
module.exports = function({ docker, caddy, servicesStateManager, asyncHandler, log, helpers }) {
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
@@ -9,16 +20,16 @@ module.exports = function(ctx, helpers) {
|
||||
* Pulls image, creates container, starts it, recreates Caddy config.
|
||||
* Skips if container is already running.
|
||||
*/
|
||||
router.post('/apps/:appId/restore', ctx.asyncHandler(async (req, res) => {
|
||||
router.post('/apps/:appId/restore', asyncHandler(async (req, res) => {
|
||||
const { appId } = req.params;
|
||||
const services = await ctx.servicesStateManager.read();
|
||||
const services = await servicesStateManager.read();
|
||||
const service = services.find(s => s.id === appId);
|
||||
|
||||
if (!service) {
|
||||
return ctx.errorResponse(res, 404, `Service "${appId}" not found in services.json`);
|
||||
return errorResponse(res, 404, `Service "${appId}" not found in services.json`);
|
||||
}
|
||||
if (!service.deploymentManifest) {
|
||||
return ctx.errorResponse(res, 400, `Service "${appId}" has no deployment manifest — it was deployed before the manifest feature was added. Redeploy it manually to create a manifest.`);
|
||||
return errorResponse(res, 400, `Service "${appId}" has no deployment manifest — it was deployed before the manifest feature was added. Redeploy it manually to create a manifest.`);
|
||||
}
|
||||
|
||||
const result = await restoreService(service);
|
||||
@@ -29,8 +40,8 @@ module.exports = function(ctx, helpers) {
|
||||
* Restore all services that have deployment manifests.
|
||||
* Returns per-service results.
|
||||
*/
|
||||
router.post('/apps/restore-all', ctx.asyncHandler(async (req, res) => {
|
||||
const services = await ctx.servicesStateManager.read();
|
||||
router.post('/apps/restore-all', asyncHandler(async (req, res) => {
|
||||
const services = await servicesStateManager.read();
|
||||
const restoreable = services.filter(s => s.deploymentManifest);
|
||||
|
||||
if (restoreable.length === 0) {
|
||||
@@ -70,8 +81,8 @@ module.exports = function(ctx, helpers) {
|
||||
/**
|
||||
* List all services and their restore status.
|
||||
*/
|
||||
router.get('/apps/restore-status', ctx.asyncHandler(async (req, res) => {
|
||||
const services = await ctx.servicesStateManager.read();
|
||||
router.get('/apps/restore-status', asyncHandler(async (req, res) => {
|
||||
const services = await servicesStateManager.read();
|
||||
const status = [];
|
||||
|
||||
for (const service of services) {
|
||||
@@ -87,7 +98,7 @@ module.exports = function(ctx, helpers) {
|
||||
// Check if container is currently running
|
||||
if (service.containerId) {
|
||||
try {
|
||||
const container = ctx.docker.client.getContainer(service.containerId);
|
||||
const container = docker.client.getContainer(service.containerId);
|
||||
const info = await container.inspect();
|
||||
entry.containerRunning = info.State.Running;
|
||||
} catch (e) {
|
||||
@@ -108,11 +119,11 @@ module.exports = function(ctx, helpers) {
|
||||
const manifest = service.deploymentManifest;
|
||||
const template = ctx.APP_TEMPLATES[manifest.templateId];
|
||||
|
||||
ctx.log.info('restore', `Restoring service: ${service.name}`, { id: service.id, templateId: manifest.templateId });
|
||||
log.info('restore', `Restoring service: ${service.name}`, { id: service.id, templateId: manifest.templateId });
|
||||
|
||||
// Static sites: just recreate Caddy config
|
||||
if (template?.isStaticSite) {
|
||||
ctx.log.info('restore', `Restoring static site Caddy config: ${service.name}`);
|
||||
log.info('restore', `Restoring static site Caddy config: ${service.name}`);
|
||||
const caddyOptions = {
|
||||
tailscaleOnly: manifest.caddy.tailscaleOnly,
|
||||
allowedIPs: manifest.caddy.allowedIPs,
|
||||
@@ -132,10 +143,10 @@ module.exports = function(ctx, helpers) {
|
||||
// Docker container: check if already running
|
||||
if (service.containerId) {
|
||||
try {
|
||||
const existing = ctx.docker.client.getContainer(service.containerId);
|
||||
const existing = docker.client.getContainer(service.containerId);
|
||||
const info = await existing.inspect();
|
||||
if (info.State.Running) {
|
||||
ctx.log.info('restore', `Container already running, skipping: ${service.name}`);
|
||||
log.info('restore', `Container already running, skipping: ${service.name}`);
|
||||
return {
|
||||
id: service.id,
|
||||
name: service.name,
|
||||
@@ -151,11 +162,11 @@ module.exports = function(ctx, helpers) {
|
||||
// Also check by name (container ID may have changed)
|
||||
const containerName = `${DOCKER.CONTAINER_PREFIX}${manifest.config.subdomain}`;
|
||||
try {
|
||||
const byName = ctx.docker.client.getContainer(containerName);
|
||||
const byName = docker.client.getContainer(containerName);
|
||||
const info = await byName.inspect();
|
||||
if (info.State.Running) {
|
||||
// Update the service entry with the current container ID
|
||||
await ctx.servicesStateManager.update(services => {
|
||||
await servicesStateManager.update(services => {
|
||||
const svc = services.find(s => s.id === service.id);
|
||||
if (svc) svc.containerId = info.Id;
|
||||
return services;
|
||||
@@ -183,18 +194,18 @@ module.exports = function(ctx, helpers) {
|
||||
}
|
||||
|
||||
// Pull image
|
||||
ctx.log.info('restore', `Pulling image: ${manifest.container.image}`);
|
||||
log.info('restore', `Pulling image: ${manifest.container.image}`);
|
||||
try {
|
||||
await ctx.docker.pull(manifest.container.image);
|
||||
await docker.pull(manifest.container.image);
|
||||
} catch (e) {
|
||||
// Check if image exists locally
|
||||
const images = await ctx.docker.client.listImages({
|
||||
const images = await docker.client.listImages({
|
||||
filters: { reference: [manifest.container.image] }
|
||||
});
|
||||
if (images.length === 0) {
|
||||
throw new Error(`Failed to pull image ${manifest.container.image}: ${e.message}`);
|
||||
}
|
||||
ctx.log.warn('restore', `Pull failed, using local image: ${manifest.container.image}`);
|
||||
log.warn('restore', `Pull failed, using local image: ${manifest.container.image}`);
|
||||
}
|
||||
|
||||
// Build container config from manifest
|
||||
@@ -231,10 +242,10 @@ module.exports = function(ctx, helpers) {
|
||||
}
|
||||
|
||||
// Create and start container
|
||||
ctx.log.info('restore', `Creating container: ${containerName}`);
|
||||
const container = await ctx.docker.client.createContainer(containerConfig);
|
||||
log.info('restore', `Creating container: ${containerName}`);
|
||||
const container = await docker.client.createContainer(containerConfig);
|
||||
await container.start();
|
||||
ctx.log.info('restore', `Container started: ${containerName}`);
|
||||
log.info('restore', `Container started: ${containerName}`);
|
||||
|
||||
// Recreate Caddy config
|
||||
const port = manifest.config.port;
|
||||
@@ -245,19 +256,19 @@ module.exports = function(ctx, helpers) {
|
||||
};
|
||||
|
||||
if (manifest.caddy.routingMode === 'subdirectory') {
|
||||
const caddyConfig = ctx.caddy.generateConfig(manifest.config.subdomain, manifest.config.ip, port, caddyOptions);
|
||||
const caddyConfig = caddy.generateConfig(manifest.config.subdomain, manifest.config.ip, port, caddyOptions);
|
||||
try {
|
||||
await helpers.ensureMainDomainBlock();
|
||||
await helpers.addSubpathConfig(manifest.config.subdomain, caddyConfig);
|
||||
} catch (e) {
|
||||
ctx.log.warn('restore', `Caddy config may already exist: ${e.message}`);
|
||||
log.warn('restore', `Caddy config may already exist: ${e.message}`);
|
||||
}
|
||||
} else {
|
||||
const caddyConfig = ctx.caddy.generateConfig(manifest.config.subdomain, manifest.config.ip, port, caddyOptions);
|
||||
const caddyConfig = caddy.generateConfig(manifest.config.subdomain, manifest.config.ip, port, caddyOptions);
|
||||
try {
|
||||
await helpers.addCaddyConfig(manifest.config.subdomain, caddyConfig);
|
||||
} catch (e) {
|
||||
ctx.log.warn('restore', `Caddy config may already exist: ${e.message}`);
|
||||
log.warn('restore', `Caddy config may already exist: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,14 +276,14 @@ module.exports = function(ctx, helpers) {
|
||||
if (manifest.config.createDns && manifest.caddy.routingMode !== 'subdirectory') {
|
||||
try {
|
||||
await ctx.dns.createRecord(manifest.config.subdomain, manifest.config.ip);
|
||||
ctx.log.info('restore', 'DNS record recreated', { subdomain: manifest.config.subdomain });
|
||||
log.info('restore', 'DNS record recreated', { subdomain: manifest.config.subdomain });
|
||||
} catch (e) {
|
||||
ctx.log.warn('restore', `DNS recreation failed: ${e.message}`);
|
||||
log.warn('restore', `DNS recreation failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the service entry with the new container ID
|
||||
await ctx.servicesStateManager.update(services => {
|
||||
await servicesStateManager.update(services => {
|
||||
const svc = services.find(s => s.id === service.id);
|
||||
if (svc) {
|
||||
svc.containerId = container.id;
|
||||
|
||||
Reference in New Issue
Block a user