Server starts up.

feature/typescript
SamTV12345 2023-06-25 15:26:34 +02:00
parent aa6323e488
commit 798543fb45
No known key found for this signature in database
GPG Key ID: E63EEC7466038043
14 changed files with 121 additions and 4260 deletions

View File

@ -79,32 +79,32 @@ const closeServer = async () => {
};
export const createServer = async () => {
console.log('Report bugs at https://github.com/ether/etherpad-lite/issues');
logger.info('Report bugs at https://github.com/ether/etherpad-lite/issues');
serverName = `Etherpad ${getGitCommit()} (https://etherpad.org)`;
console.log(`Your Etherpad version is ${getEpVersion()} (${getGitCommit()})`);
logger.info(`Your Etherpad version is ${getEpVersion()} (${getGitCommit()})`);
await restartServer();
if (ip.length===0) {
// using Unix socket for connectivity
console.log(`You can access your Etherpad instance using the Unix socket at ${port}`);
logger.info(`You can access your Etherpad instance using the Unix socket at ${port}`);
} else {
console.log(`You can access your Etherpad instance at http://${ip}:${port}/`);
logger.info(`You can access your Etherpad instance at http://${ip}:${port}/`);
}
if (!_.isEmpty(users)) {
console.log(`The plugin admin page is at http://${ip}:${port}/admin/plugins`);
logger.info(`The plugin admin page is at http://${ip}:${port}/admin/plugins`);
} else {
console.warn('Admin username and password not set in settings.json. ' +
logger.info('Admin username and password not set in settings.json. ' +
'To access admin please uncomment and edit "users" in settings.json');
}
const env = process.env.NODE_ENV || 'development';
if (env !== 'production') {
console.warn('Etherpad is running in Development mode. This mode is slower for users and ' +
logger.warn('Etherpad is running in Development mode. This mode is slower for users and ' +
'less secure than production mode. You should set the NODE_ENV environment ' +
'variable to production by using: export NODE_ENV=production');
}

View File

@ -12,12 +12,14 @@ import {getPadId, isReadOnlyId} from "../../db/ReadOnlyManager";
import {UserIndexedModel} from "../../models/UserIndexedModel";
const httpLogger = log4js.getLogger('http');
import {aCallFirst as hookCall} from "../../../static/js/pluginfw/hooks";
deprecationNotices.authFailure = 'use the authnFailure and authzFailure hooks instead';
// Promisified wrapper around hooks.aCallFirst.
const aCallFirst = (hookName, context, pred = null) => new Promise((resolve, reject) => {
// FIXME Why are there 4 arguments but only 3 parameters?
aCallFirst(hookName, context, (err, r) => err != null ? reject(err) : resolve(r));
hookCall(hookName, context, (err, r) => err != null ? reject(err) : resolve(r));
});
const aCallFirst0 =

View File

@ -47,7 +47,7 @@ checkDeprecationStatus('12.17.0', '1.9.0');
import db = require('./db/DB');
import {} from './db/DB'
import express = require('./hooks/express');
import {createServer, server} from './hooks/express';
import hooks = require('../static/js/pluginfw/hooks');
import pluginDefs = require('../static/js/pluginfw/plugin_defs');
import plugins = require('../static/js/pluginfw/plugins');
@ -87,7 +87,7 @@ export const start = async () => {
// Retry. Don't fall through because it might have transitioned to STATE_TRANSITION_FAILED.
return await start();
case State.RUNNING:
return express.server;
return server;
case State.STOPPING:
case State.STOPPED:
case State.EXITING:
@ -152,7 +152,7 @@ export const start = async () => {
logger.debug(`Installed parts:\n${plugins.formatParts()}`);
logger.debug(`Installed server-side hooks:\n${plugins.formatHooks('hooks', false)}`);
await hooks.aCallAll('loadSettings', {settings});
await hooks.aCallAll('createServer');
await hooks.aCallAll(createServer())
} catch (err) {
logger.error('Error occurred while starting Etherpad');
state = State.STATE_TRANSITION_FAILED;
@ -163,9 +163,8 @@ export const start = async () => {
logger.info('Etherpad is running');
state = State.RUNNING;
startDoneGate.resolve();
// Return the HTTP server to make it easier to write tests.
return express.server;
return server;
};
const stopDoneGate = new Gate();
@ -277,7 +276,7 @@ export const exit = async (err = null) => {
logger.info('Waiting for Node.js to exit...');
state = State.WAITING_FOR_EXIT;
/* eslint-enable no-process-exit */
};
if (require.main === module) start();
start()
.then(c=>logger.info("Server started"));

View File

@ -24,7 +24,7 @@ import {promises as fs} from "fs";
import os from 'os';
import path from "path";
import {exportCMD} from "./run_cmd";
import exportCMD from "./run_cmd";
import {soffice} from "./Settings";

View File

@ -28,6 +28,8 @@
*/
import exp from "constants";
// FIXME Is there a better way to enter dynamic package.json path
// @ts-ignore
import packageJSON from '../../../package.json'
import {findEtherpadRoot, makeAbsolute, isSubdir} from './AbsolutePaths';
import deepEqual from 'fast-deep-equal/es6';

View File

@ -1,12 +1,22 @@
'use strict';
import spawn from 'cross-spawn';
import log4js from 'log4js';
import path from 'path';
import {root} from "./Settings";
import {CMDOptions, CMDPromise} from '../models/CMDOptions'
import {root} from './Settings';
import {CustomError} from "./customError";
const logger = log4js.getLogger('runCmd');
import {CustomError} from './customError'
type CMDPromise = {
stdout: Promise<string>,
stderr: Promise<string>,
status: Promise<number>,
signal: Promise<string>,
}
const logLines = (readable, logLineFn) => {
readable.setEncoding('utf8');
// The process won't necessarily write full lines every time -- it might write a part of a line
@ -69,14 +79,23 @@ const logLines = (readable, logLineFn) => {
* - `stderr`: Similar to `stdout` but for stderr.
* - `child`: The ChildProcess object.
*/
export const exportCMD: (args: string[], opts?:CMDOptions)=>void = async (args, opts = {
cwd: undefined,
stdio: undefined,
env: undefined
type RunOpts = {
cwd?: string;
env?: any;
stdio?: any;
detached?: boolean;
uid?: number
}
const run_cmd = (args, opts:RunOpts = {
stdio: undefined
}) => {
logger.debug(`Executing command: ${args.join(' ')}`);
logger.info(`Executing command: ${args.join(' ')}`);
opts = {cwd: root, ...opts};
logger.debug(`cwd: ${opts.cwd}`);
logger.info(`cwd: ${opts.cwd}`);
// Log stdout and stderr by default.
const stdio =
@ -85,24 +104,20 @@ export const exportCMD: (args: string[], opts?:CMDOptions)=>void = async (args,
: opts.stdio === 'string' ? [null, 'string', 'string']
: Array(3).fill(opts.stdio);
const cmdLogger = log4js.getLogger(`runCmd|${args[0]}`);
if (stdio[1] == null && stdio instanceof Array) stdio[1] = (line) => cmdLogger.info(line);
if (stdio[2] == null && stdio instanceof Array) stdio[2] = (line) => cmdLogger.error(line);
if (stdio[1] == null) stdio[1] = (line) => cmdLogger.info(line);
if (stdio[2] == null) stdio[2] = (line) => cmdLogger.error(line);
const stdioLoggers = [];
const stdioSaveString = [];
for (const fd of [1, 2]) {
if (typeof stdio[fd] === 'function') {
stdioLoggers[fd] = stdio[fd];
if (stdio instanceof Array)
stdio[fd] = 'pipe';
stdio[fd] = 'pipe';
} else if (stdio[fd] === 'string') {
stdioSaveString[fd] = true;
if (stdio instanceof Array)
stdio[fd] = 'pipe';
stdio[fd] = 'pipe';
}
}
if (opts.stdio instanceof Array) {
opts.stdio = stdio;
}
opts.stdio = stdio;
// On Windows the PATH environment var might be spelled "Path".
const pathVarName =
@ -123,15 +138,13 @@ export const exportCMD: (args: string[], opts?:CMDOptions)=>void = async (args,
// Create an error object to use in case the process fails. This is done here rather than in the
// process's `exit` handler so that we get a useful stack trace.
const procFailedErr:CustomError = new CustomError({});
const procFailedErr = new CustomError({});
const proc = spawn(args[0], args.slice(1), opts);
const streams = [undefined, proc.stdout, proc.stderr];
let px;
const p = await new Promise<CMDPromise>((resolve, reject) => {
px = {resolve, reject};
});
const p = new Promise<string>((resolve, reject) => { px = {resolve, reject}; });
[, p.stdout, p.stderr] = streams;
p.child = proc;
@ -141,7 +154,6 @@ export const exportCMD: (args: string[], opts?:CMDOptions)=>void = async (args,
if (stdioLoggers[fd] != null) {
logLines(streams[fd], stdioLoggers[fd]);
} else if (stdioSaveString[fd]) {
//FIXME How to solve this?
// @ts-ignore
p[[null, 'stdout', 'stderr'][fd]] = stdioStringPromises[fd] = (async () => {
const chunks = [];
@ -166,3 +178,4 @@ export const exportCMD: (args: string[], opts?:CMDOptions)=>void = async (args,
});
return p;
};
export default run_cmd;

4249
src/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,6 @@
"log4js": "^6.9.1",
"measured-core": "^2.0.0",
"mime-types": "^2.1.35",
"npm": "^6.14.15",
"openapi-backend": "^5.9.2",
"proxy-addr": "^2.0.7",
"rate-limiter-flexible": "^2.4.1",
@ -79,9 +78,12 @@
"etherpad-lite": "node/server.js"
},
"devDependencies": {
"@types/cross-spawn": "^6.0.2",
"@types/express": "4.17.17",
"@types/jquery": "^3.5.16",
"@types/js-cookie": "^3.0.3",
"i18next": "^23.2.3",
"i18next-fs-backend": "^2.1.5",
"@types/node": "^20.3.1",
"@types/underscore": "^1.11.5",
"concurrently": "^8.2.0",

View File

@ -1,6 +1,7 @@
// @ts-nocheck
import * as pluginUtils from "./shared.js";
import * as defs from "./plugin_defs.js";
import {getLogger} from "log4js";
'use strict';
const adoptPluginsFromAncestorsOf = (frame) => {
@ -37,9 +38,12 @@ export const update = (cb) => {
// of execution on Firefox. This schedules the response in the run-loop,
// which appears to fix the issue.
const callback = () => setTimeout(cb, 0);
jQuery.getJSON(`${exports.baseURL}pluginfw/plugin-definitions.json?v=${clientVars.randomVersionString}`).done((data) => {
jQuery.getJSON(`${exports.baseURL}pluginfw/plugin-definitions.json?v=${clientVars.randomVersionString}`)
.done((data) => {
defs.plugins = data.plugins;
defs.parts = data.parts;
const logger = getLogger("client_plugins")
logger.info(data.parts)
defs.hooks = pluginUtils.extractHooks(defs.parts, 'client_hooks');
defs.loaded = true;
callback();

View File

@ -7,7 +7,7 @@ import {aCallAll} from "./hooks";
import request from "request";
import {exportCMD} from "../../../node/utils/run_cmd";
import exportCMD from "../../../node/utils/run_cmd";
import {reloadSettings} from "../../../node/utils/Settings";
import {InstallerModel} from "../../module/InstallerModel";

View File

@ -25,7 +25,7 @@ export let parts = [];
// - version
// - path
// - realPath
export const plugins = {};
export let plugins = {};
export const setPlugins = (newPlugins) => {
Object.assign(plugins, newPlugins);

View File

@ -8,13 +8,13 @@ import log4js from "log4js";
import path from "path";
import {exportCMD} from "../../../node/utils/run_cmd";
import exportCMD from "../../../node/utils/run_cmd";
import {tsort} from "./tsort";
import tsort from "./tsort";
import {extractHooks} from "./shared";
import {loaded, parts, plugins, setHooks, setLoaded, setParts, setPlugins} from "./plugin_defs";
import {parts, plugins, setHooks, setLoaded, setParts, setPlugins} from "./plugin_defs";
import {PluginInfo} from "../../module/PluginInfo";
const logger = log4js.getLogger('plugins');
@ -95,8 +95,8 @@ export const pathNormalization = (part, hookFnName, hookName) => {
export const update = async () => {
const packages = await getPackages();
let parts:{[keys: string]:any} = {}; // Key is full name. sortParts converts this into a topologically sorted array.
let plugins = {};
let parts = []; // Key is full name. sortParts converts this into a topologically sorted array.
let plugins = {}
// Load plugin metadata ep.json
await Promise.all(Object.keys(packages).map(async (pluginName) => {
@ -105,6 +105,7 @@ export const update = async () => {
}));
logger.info(`Loaded ${Object.keys(packages).length} plugins`);
logger.info(parts)
setPlugins(plugins);
setParts(sortParts(parts))
setHooks(extractHooks(parts, 'hooks', pathNormalization));
@ -123,7 +124,10 @@ const getPackages = async () => {
// unset or set to `development`) because otherwise `npm ls` will not mention any packages
// that are not included in `package.json` (which is expected to not exist).
const cmd = ['npm', 'ls', '--long', '--json', '--depth=0', '--no-production'];
const {dependencies = {}} = JSON.parse(await exportCMD(cmd, {stdio: [null, 'string']}) as unknown as string);
logger.info("Before exportCMD")
const cmdReturn = await exportCMD(cmd, {stdio: [null, 'string']})
logger.info("After exportCMD")
const {dependencies = {}} = JSON.parse(cmdReturn as string);
await Promise.all(Object.entries(dependencies).map(async ([pkg, info]) => {
if (!pkg.startsWith(prefix)) {
delete dependencies[pkg];

View File

@ -33,7 +33,7 @@ export const loadFn = (path, hookName) => {
return fn;
};
export const extractHooks = (parts, hookSetName, normalizer) => {
export const extractHooks = (parts: any[], hookSetName, normalizer) => {
const hooks = {};
for (const part of parts) {
for (const [hookName, regHookFnName] of Object.entries(part[hookSetName] || {})) {

View File

@ -55,7 +55,7 @@ export const tsort = (edges: (string|number)[][]) => {
Object.keys(nodes).forEach(visit);
return sorted;
};
}
/**
* TEST
@ -111,3 +111,5 @@ if (typeof exports === 'object' && exports === this) {
module.exports = tsort;
if (process.argv[1] === __filename) tsortTest();
}
export default tsort;