refactor(core): Port path, host, port, listen_address and protocol config (no-changelog) (#10223)

This commit is contained in:
Iván Ovejero 2024-07-29 14:32:20 +02:00 committed by GitHub
parent 4d37b9669f
commit 7a30d845e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 53 deletions

View file

@ -1,4 +1,4 @@
import { Config, Nested } from './decorators';
import { Config, Env, Nested } from './decorators';
import { CredentialsConfig } from './configs/credentials';
import { DatabaseConfig } from './configs/database';
import { EmailConfig } from './configs/email';
@ -51,4 +51,24 @@ export class GlobalConfig {
@Nested
readonly workflows: WorkflowsConfig;
/** Path n8n is deployed to */
@Env('N8N_PATH')
readonly path: string = '/';
/** Host name n8n can be reached */
@Env('N8N_HOST')
readonly host: string = 'localhost';
/** HTTP port n8n can be reached */
@Env('N8N_PORT')
readonly port: number = 5678;
/** IP address n8n should listen on */
@Env('N8N_LISTEN_ADDRESS')
readonly listen_address: string = '0.0.0.0';
/** HTTP Protocol via which n8n can be reached */
@Env('N8N_PROTOCOL')
readonly protocol: 'http' | 'https' = 'http';
}

View file

@ -18,6 +18,11 @@ describe('GlobalConfig', () => {
});
const defaultConfig: GlobalConfig = {
path: '/',
host: 'localhost',
port: 5678,
listen_address: '0.0.0.0',
protocol: 'http',
database: {
logging: {
enabled: false,

View file

@ -22,6 +22,7 @@ import { Logger } from '@/Logger';
import { ServiceUnavailableError } from './errors/response-errors/service-unavailable.error';
import { OnShutdown } from '@/decorators/OnShutdown';
import { ActiveWebhooks } from '@/ActiveWebhooks';
import { GlobalConfig } from '@n8n/config';
@Service()
export abstract class AbstractServer {
@ -33,7 +34,7 @@ export abstract class AbstractServer {
protected externalHooks: ExternalHooks;
protected protocol = config.getEnv('protocol');
protected protocol = Container.get(GlobalConfig).protocol;
protected sslKey: string;
@ -149,25 +150,24 @@ export abstract class AbstractServer {
this.server = http.createServer(app);
}
const PORT = config.getEnv('port');
const ADDRESS = config.getEnv('listen_address');
const { port, listen_address: address } = Container.get(GlobalConfig);
this.server.on('error', (error: Error & { code: string }) => {
if (error.code === 'EADDRINUSE') {
this.logger.info(
`n8n's port ${PORT} is already in use. Do you have another instance of n8n running already?`,
`n8n's port ${port} is already in use. Do you have another instance of n8n running already?`,
);
process.exit(1);
}
});
await new Promise<void>((resolve) => this.server.listen(PORT, ADDRESS, () => resolve()));
await new Promise<void>((resolve) => this.server.listen(port, address, () => resolve()));
this.externalHooks = Container.get(ExternalHooks);
await this.setupHealthCheck();
this.logger.info(`n8n ready on ${ADDRESS}, port ${PORT}`);
this.logger.info(`n8n ready on ${address}, port ${port}`);
}
async start(): Promise<void> {

View file

@ -10,8 +10,6 @@ import type { HttpError } from 'express-openapi-validator/dist/framework/types';
import type { OpenAPIV3 } from 'openapi-types';
import type { JsonObject } from 'swagger-ui-express';
import config from '@/config';
import { License } from '@/License';
import { UserRepository } from '@db/repositories/user.repository';
import { UrlService } from '@/services/url.service';
@ -25,7 +23,7 @@ async function createApiRouter(
handlersDirectory: string,
publicApiEndpoint: string,
): Promise<Router> {
const n8nPath = config.getEnv('path');
const n8nPath = Container.get(GlobalConfig).path;
const swaggerDocument = YAML.load(openApiSpecPath) as JsonObject;
// add the server depending on the config so the user can interact with the API
// from the Swagger UI

View file

@ -124,7 +124,7 @@ export class Start extends BaseCommand {
private async generateStaticAssets() {
// Read the index file and replace the path placeholder
const n8nPath = config.getEnv('path');
const n8nPath = Container.get(GlobalConfig).path;
const restEndpoint = config.getEnv('endpoints.rest');
const hooksUrls = config.getEnv('externalFrontendHooksUrls');
@ -283,7 +283,7 @@ export class Start extends BaseCommand {
}
const { default: localtunnel } = await import('@n8n/localtunnel');
const port = config.getEnv('port');
const { port } = Container.get(GlobalConfig);
const webhookTunnel = await localtunnel(port, {
host: 'https://hooks.n8n.cloud',

View file

@ -307,40 +307,6 @@ export const schema = {
},
},
// How n8n can be reached (Editor & REST-API)
path: {
format: String,
default: '/',
arg: 'path',
env: 'N8N_PATH',
doc: 'Path n8n is deployed to',
},
host: {
format: String,
default: 'localhost',
arg: 'host',
env: 'N8N_HOST',
doc: 'Host name n8n can be reached',
},
port: {
format: Number,
default: 5678,
arg: 'port',
env: 'N8N_PORT',
doc: 'HTTP port n8n can be reached',
},
listen_address: {
format: String,
default: '0.0.0.0',
env: 'N8N_LISTEN_ADDRESS',
doc: 'IP address n8n should listen on',
},
protocol: {
format: ['http', 'https'] as const,
default: 'http',
env: 'N8N_PROTOCOL',
doc: 'HTTP Protocol via which n8n can be reached',
},
secure_cookie: {
doc: 'This sets the `Secure` flag on n8n auth cookie',
format: Boolean,

View file

@ -1,12 +1,13 @@
import { Service } from 'typedi';
import config from '@/config';
import { GlobalConfig } from '@n8n/config';
@Service()
export class UrlService {
/** Returns the base URL n8n is reachable from */
readonly baseUrl: string;
constructor() {
constructor(private readonly globalConfig: GlobalConfig) {
this.baseUrl = this.generateBaseUrl();
}
@ -27,10 +28,7 @@ export class UrlService {
}
private generateBaseUrl(): string {
const protocol = config.getEnv('protocol');
const host = config.getEnv('host');
const port = config.getEnv('port');
const path = config.getEnv('path');
const { path, port, host, protocol } = this.globalConfig;
if ((protocol === 'http' && port === 80) || (protocol === 'https' && port === 443)) {
return `${protocol}://${host}${path}`;

View file

@ -6,11 +6,19 @@ import { UserService } from '@/services/user.service';
import { UrlService } from '@/services/url.service';
import { mockInstance } from '../../shared/mocking';
import { UserRepository } from '@/databases/repositories/user.repository';
import { GlobalConfig } from '@n8n/config';
describe('UserService', () => {
const urlService = new UrlService();
const globalConfig = mockInstance(GlobalConfig, {
host: 'localhost',
path: '/',
port: 5678,
listen_address: '0.0.0.0',
protocol: 'http',
});
const urlService = new UrlService(globalConfig);
const userRepository = mockInstance(UserRepository);
const userService = new UserService(mock(), userRepository, mock(), urlService);
const userService = new UserService(mock(), userRepository, mock(), urlService, mock());
const commonMockUser = Object.assign(new User(), {
id: uuid(),