Compare commits
34 Commits
bugfix/ssh
...
master
Author | SHA1 | Date |
---|---|---|
Bryan Ashby | 6aa0c8679f | |
Nathan Byrd | 6b169de3ac | |
Nathan Byrd | 362f443290 | |
Nathan Byrd | 8a97f79d8c | |
Nathan Byrd | f17bbe7c5a | |
Bryan Ashby | 8c7df1fe75 | |
Bryan Ashby | b00d5d07dd | |
Bryan Ashby | bbfef536e0 | |
Bryan Ashby | 83636cb894 | |
Bryan Ashby | ca985dd2cb | |
Bryan Ashby | b87ff51160 | |
Bryan Ashby | 746233fa56 | |
Bryan Ashby | c84b3ee1c1 | |
Bryan Ashby | 1a99153431 | |
Nathan Byrd | 88a1b0ea69 | |
Nathan Byrd | 498c4a6082 | |
Nathan Byrd | 577992bbe5 | |
Nathan Byrd | 402c5d0156 | |
Nathan Byrd | 0ca22de6e9 | |
Nathan Byrd | 394ac465c8 | |
Nathan Byrd | 450ba65565 | |
Nathan Byrd | 72a8546d74 | |
Nathan Byrd | 79a3f4e1ce | |
Nathan Byrd | c0c262c971 | |
Nathan Byrd | 826db2d718 | |
Nathan Byrd | f3c9afc684 | |
Nathan Byrd | 372d84f572 | |
Nathan Byrd | 8029521399 | |
Nathan Byrd | 855fabe34d | |
Nathan Byrd | 5712645299 | |
Nathan Byrd | a99b55abb5 | |
Nathan Byrd | d8f45f9147 | |
Nathan Byrd | 08841528e2 | |
Nathan Byrd | 4d70f07fde |
|
@ -7,7 +7,7 @@
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/python:1": {
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
"installTools": true,
|
"installTools": true,
|
||||||
"version": "latest"
|
"version": "3.11"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers-contrib/features/curl-apt-get:1": {},
|
"ghcr.io/devcontainers-contrib/features/curl-apt-get:1": {},
|
||||||
"ghcr.io/jungaretti/features/ripgrep:1": {},
|
"ghcr.io/jungaretti/features/ripgrep:1": {},
|
||||||
|
|
|
@ -11,14 +11,14 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
|
@ -31,5 +31,5 @@ jobs:
|
||||||
with:
|
with:
|
||||||
tags: enigmabbs/enigma-bbs:latest
|
tags: enigmabbs/enigma-bbs:latest
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||||
push: true
|
push: true
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Program",
|
|
||||||
"skipFiles": [
|
|
||||||
"<node_internals>/**"
|
|
||||||
],
|
|
||||||
"program": "${workspaceFolder}/main.js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -24,7 +24,7 @@ function ANSIEscapeParser(options) {
|
||||||
this.graphicRendition = {};
|
this.graphicRendition = {};
|
||||||
|
|
||||||
this.parseState = {
|
this.parseState = {
|
||||||
re: /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsutEFGST])/g, // eslint-disable-line no-control-regex
|
re: /(?:\x1b)(?:(?:\x5b([?=;0-9]*?)([ABCDEFGfHJKLmMsSTuUYZt@PXhlnpt]))|([78DEHM]))/g, // eslint-disable-line no-control-regex
|
||||||
};
|
};
|
||||||
|
|
||||||
options = miscUtil.valueWithDefault(options, {
|
options = miscUtil.valueWithDefault(options, {
|
||||||
|
@ -77,10 +77,25 @@ function ANSIEscapeParser(options) {
|
||||||
self.clearScreen = function () {
|
self.clearScreen = function () {
|
||||||
self.column = 1;
|
self.column = 1;
|
||||||
self.row = 1;
|
self.row = 1;
|
||||||
|
self.positionUpdated();
|
||||||
self.emit('clear screen');
|
self.emit('clear screen');
|
||||||
};
|
};
|
||||||
|
|
||||||
self.positionUpdated = function () {
|
self.positionUpdated = function () {
|
||||||
|
if(self.row > self.termHeight) {
|
||||||
|
if(this.savedPosition) {
|
||||||
|
this.savedPosition.row -= self.row - self.termHeight;
|
||||||
|
}
|
||||||
|
self.emit('scroll', self.row - self.termHeight);
|
||||||
|
self.row = self.termHeight;
|
||||||
|
}
|
||||||
|
else if(self.row < 1) {
|
||||||
|
if(this.savedPosition) {
|
||||||
|
this.savedPosition.row -= self.row - 1;
|
||||||
|
}
|
||||||
|
self.emit('scroll', -(self.row - 1));
|
||||||
|
self.row = 1;
|
||||||
|
}
|
||||||
self.emit('position update', self.row, self.column);
|
self.emit('position update', self.row, self.column);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -231,7 +246,7 @@ function ANSIEscapeParser(options) {
|
||||||
self.parseState = {
|
self.parseState = {
|
||||||
// ignore anything past EOF marker, if any
|
// ignore anything past EOF marker, if any
|
||||||
buffer: input.split(String.fromCharCode(0x1a), 1)[0],
|
buffer: input.split(String.fromCharCode(0x1a), 1)[0],
|
||||||
re: /(?:\x1b\x5b)([?=;0-9]*?)([ABCDHJKfhlmnpsutEFGST])/g, // eslint-disable-line no-control-regex
|
re: /(?:\x1b)(?:(?:\x5b([?=;0-9]*?)([ABCDEFGfHJKLmMsSTuUYZt@PXhlnpt]))|([78DEHM]))/g, // eslint-disable-line no-control-regex
|
||||||
stop: false,
|
stop: false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -271,9 +286,47 @@ function ANSIEscapeParser(options) {
|
||||||
opCode = match[2];
|
opCode = match[2];
|
||||||
args = match[1].split(';').map(v => parseInt(v, 10)); // convert to array of ints
|
args = match[1].split(';').map(v => parseInt(v, 10)); // convert to array of ints
|
||||||
|
|
||||||
escape(opCode, args);
|
// Handle the case where there is no bracket
|
||||||
|
if(!(_.isNil(match[3]))) {
|
||||||
|
opCode = match[3];
|
||||||
|
args = [];
|
||||||
|
// no bracket
|
||||||
|
switch(opCode) {
|
||||||
|
// save cursor position
|
||||||
|
case '7':
|
||||||
|
escape('s', args);
|
||||||
|
break;
|
||||||
|
// restore cursor position
|
||||||
|
case '8':
|
||||||
|
escape('u', args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// scroll up
|
||||||
|
case 'D':
|
||||||
|
escape('S', args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// move to next line
|
||||||
|
case 'E':
|
||||||
|
// functonality is the same as ESC [ E
|
||||||
|
escape(opCode, args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// create a tab at current cursor position
|
||||||
|
case 'H':
|
||||||
|
literal('\t');
|
||||||
|
break;
|
||||||
|
|
||||||
|
// scroll down
|
||||||
|
case 'M':
|
||||||
|
escape('T', args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
escape(opCode, args);
|
||||||
|
}
|
||||||
|
|
||||||
//self.emit('chunk', match[0]);
|
|
||||||
self.emit('control', match[0], opCode, args);
|
self.emit('control', match[0], opCode, args);
|
||||||
}
|
}
|
||||||
} while (0 !== re.lastIndex);
|
} while (0 !== re.lastIndex);
|
||||||
|
@ -281,8 +334,8 @@ function ANSIEscapeParser(options) {
|
||||||
if (pos < buffer.length) {
|
if (pos < buffer.length) {
|
||||||
var lastBit = buffer.slice(pos);
|
var lastBit = buffer.slice(pos);
|
||||||
|
|
||||||
// :TODO: check for various ending LF's, not just DOS \r\n
|
// handles either \r\n or \n
|
||||||
if ('\r\n' === lastBit.slice(-2).toString()) {
|
if ('\n' === lastBit.slice(-1).toString()) {
|
||||||
switch (self.trailingLF) {
|
switch (self.trailingLF) {
|
||||||
case 'default':
|
case 'default':
|
||||||
//
|
//
|
||||||
|
@ -290,14 +343,14 @@ function ANSIEscapeParser(options) {
|
||||||
// if we're going to end on termHeight
|
// if we're going to end on termHeight
|
||||||
//
|
//
|
||||||
if (this.termHeight === self.row) {
|
if (this.termHeight === self.row) {
|
||||||
lastBit = lastBit.slice(0, -2);
|
lastBit = lastBit.slice(0, -1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'omit':
|
case 'omit':
|
||||||
case 'no':
|
case 'no':
|
||||||
case false:
|
case false:
|
||||||
lastBit = lastBit.slice(0, -2);
|
lastBit = lastBit.slice(0, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,48 +361,6 @@ function ANSIEscapeParser(options) {
|
||||||
self.emit('complete');
|
self.emit('complete');
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
self.parse = function(buffer, savedRe) {
|
|
||||||
// :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc.
|
|
||||||
// :TODO: move this to "constants" section @ top
|
|
||||||
var re = /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g;
|
|
||||||
var pos = 0;
|
|
||||||
var match;
|
|
||||||
var opCode;
|
|
||||||
var args;
|
|
||||||
|
|
||||||
// ignore anything past EOF marker, if any
|
|
||||||
buffer = buffer.split(String.fromCharCode(0x1a), 1)[0];
|
|
||||||
|
|
||||||
do {
|
|
||||||
pos = re.lastIndex;
|
|
||||||
match = re.exec(buffer);
|
|
||||||
|
|
||||||
if(null !== match) {
|
|
||||||
if(match.index > pos) {
|
|
||||||
parseMCI(buffer.slice(pos, match.index));
|
|
||||||
}
|
|
||||||
|
|
||||||
opCode = match[2];
|
|
||||||
args = getArgArray(match[1].split(';'));
|
|
||||||
|
|
||||||
escape(opCode, args);
|
|
||||||
|
|
||||||
self.emit('chunk', match[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} while(0 !== re.lastIndex);
|
|
||||||
|
|
||||||
if(pos < buffer.length) {
|
|
||||||
parseMCI(buffer.slice(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit('complete');
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
function escape(opCode, args) {
|
function escape(opCode, args) {
|
||||||
let arg;
|
let arg;
|
||||||
|
|
||||||
|
@ -382,6 +393,37 @@ function ANSIEscapeParser(options) {
|
||||||
self.moveCursor(-arg, 0);
|
self.moveCursor(-arg, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// line feed
|
||||||
|
case 'E':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
if(this.row + arg > this.termHeight) {
|
||||||
|
this.emit('scroll', arg - (this.termHeight - this.row));
|
||||||
|
self.moveCursor(0, this.termHeight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.moveCursor(0, arg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// reverse line feed
|
||||||
|
case 'F':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
if(this.row - arg < 1) {
|
||||||
|
this.emit('scroll', -(arg - this.row));
|
||||||
|
self.moveCursor(0, 1 - this.row);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.moveCursor(0, -arg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// absolute horizontal cursor position
|
||||||
|
case 'G':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.column = Math.max(1, arg);
|
||||||
|
self.positionUpdated();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'f': // horiz & vertical
|
case 'f': // horiz & vertical
|
||||||
case 'H': // cursor position
|
case 'H': // cursor position
|
||||||
//self.row = args[0] || 1;
|
//self.row = args[0] || 1;
|
||||||
|
@ -392,14 +434,37 @@ function ANSIEscapeParser(options) {
|
||||||
self.positionUpdated();
|
self.positionUpdated();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// save position
|
|
||||||
case 's':
|
// erase display/screen
|
||||||
self.saveCursorPosition();
|
case 'J':
|
||||||
|
if(isNaN(args[0]) || 0 === args[0]) {
|
||||||
|
self.emit('erase rows', self.row, self.termHeight);
|
||||||
|
}
|
||||||
|
else if (1 === args[0]) {
|
||||||
|
self.emit('erase rows', 1, self.row);
|
||||||
|
}
|
||||||
|
else if (2 === args[0]) {
|
||||||
|
self.clearScreen();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// restore position
|
// erase text in line
|
||||||
case 'u':
|
case 'K':
|
||||||
self.restoreCursorPosition();
|
if(isNaN(args[0]) || 0 === args[0]) {
|
||||||
|
self.emit('erase columns', self.row, self.column, self.termWidth);
|
||||||
|
}
|
||||||
|
else if (1 === args[0]) {
|
||||||
|
self.emit('erase columns', self.row, 1, self.column);
|
||||||
|
}
|
||||||
|
else if (2 === args[0]) {
|
||||||
|
self.emit('erase columns', self.row, 1, self.termWidth);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// insert line
|
||||||
|
case 'L':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.emit('insert line', self.row, arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// set graphic rendition
|
// set graphic rendition
|
||||||
|
@ -471,15 +536,52 @@ function ANSIEscapeParser(options) {
|
||||||
self.emit('sgr update', self.graphicRendition);
|
self.emit('sgr update', self.graphicRendition);
|
||||||
break; // m
|
break; // m
|
||||||
|
|
||||||
// :TODO: s, u, K
|
// save position
|
||||||
|
case 's':
|
||||||
// erase display/screen
|
self.saveCursorPosition();
|
||||||
case 'J':
|
|
||||||
// :TODO: Handle other 'J' types!
|
|
||||||
if (2 === args[0]) {
|
|
||||||
self.clearScreen();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Scroll up
|
||||||
|
case 'S':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.emit('scroll', arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Scroll down
|
||||||
|
case 'T':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.emit('scroll', -arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// restore position
|
||||||
|
case 'u':
|
||||||
|
self.restoreCursorPosition();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// clear
|
||||||
|
case 'U':
|
||||||
|
self.clearScreen();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// delete line
|
||||||
|
// TODO: how should we handle 'M'?
|
||||||
|
case 'Y':
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.emit('delete line', self.row, arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// back tab
|
||||||
|
case 'Z':
|
||||||
|
// calculate previous tabstop
|
||||||
|
self.column = Math.max( 1, self.column - (self.column % 8 || 8) );
|
||||||
|
self.positionUpdated();
|
||||||
|
break;
|
||||||
|
case '@':
|
||||||
|
// insert column(s)
|
||||||
|
arg = isNaN(args[0]) ? 1 : args[0];
|
||||||
|
self.emit('insert columns', self.row, self.column, arg);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,17 +208,17 @@ module.exports = class ArchiveUtil {
|
||||||
// pty.js doesn't currently give us a error when things fail,
|
// pty.js doesn't currently give us a error when things fail,
|
||||||
// so we have this horrible, horrible hack:
|
// so we have this horrible, horrible hack:
|
||||||
let err;
|
let err;
|
||||||
proc.once('data', d => {
|
proc.onData(d => {
|
||||||
if (_.isString(d) && d.startsWith('execvp(3) failed.')) {
|
if (_.isString(d) && d.startsWith('execvp(3) failed.')) {
|
||||||
err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
|
err = Errors.ExternalProcess(`${action} failed: ${d.trim()}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
proc.once('exit', exitCode => {
|
proc.onExit(exitEvent => {
|
||||||
return cb(
|
return cb(
|
||||||
exitCode
|
exitEvent.exitCode
|
||||||
? Errors.ExternalProcess(
|
? Errors.ExternalProcess(
|
||||||
`${action} failed with exit code: ${exitCode}`
|
`${action} failed with exit code: ${exitEvent.exitCode}`
|
||||||
)
|
)
|
||||||
: err
|
: err
|
||||||
);
|
);
|
||||||
|
@ -358,10 +358,10 @@ module.exports = class ArchiveUtil {
|
||||||
output += data;
|
output += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
proc.once('exit', exitCode => {
|
proc.onExit(exitEvent => {
|
||||||
if (exitCode) {
|
if (exitEvent.exitCode) {
|
||||||
return cb(
|
return cb(
|
||||||
Errors.ExternalProcess(`List failed with exit code: ${exitCode}`)
|
Errors.ExternalProcess(`List failed with exit code: ${exitEvent.exitCode}`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
core/art.js
69
core/art.js
|
@ -316,6 +316,75 @@ function display(client, art, options, cb) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove any MCI's that are in erased rows
|
||||||
|
ansiParser.on('erase row', (startRow, endRow) => {
|
||||||
|
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||||
|
if (mciInfo.position[0] >= startRow && mciInfo.position[0] <= endRow) {
|
||||||
|
delete mciMap[mapKey];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove any MCI's that are in erased columns
|
||||||
|
ansiParser.on('erase columns', (row, startCol, endCol) => {
|
||||||
|
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||||
|
if (
|
||||||
|
mciInfo.position[0] === row &&
|
||||||
|
mciInfo.position[1] >= startCol &&
|
||||||
|
mciInfo.position[1] <= endCol
|
||||||
|
) {
|
||||||
|
delete mciMap[mapKey];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ansiParser.on('insert columns', (row, startCol, numCols) => {
|
||||||
|
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||||
|
if (mciInfo.position[0] === row && mciInfo.position[1] >= startCol) {
|
||||||
|
mciInfo.position[1] += numCols;
|
||||||
|
if(mciInfo.position[1] > client.term.termWidth) {
|
||||||
|
delete mciMap[mapKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear the screen, removing any MCI's
|
||||||
|
ansiParser.on('clear screen', () => {
|
||||||
|
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||||
|
delete mciMap[mapKey];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ansiParser.on('scroll', (scrollY) => {
|
||||||
|
_.forEach(mciMap, (mciInfo) => {
|
||||||
|
mciInfo.position[0] -= scrollY;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ansiParser.on('insert line', (row, numLines) => {
|
||||||
|
_.forEach(mciMap, (mciInfo) => {
|
||||||
|
if (mciInfo.position[0] >= row) {
|
||||||
|
mciInfo.position[0] += numLines;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ansiParser.on('delete line', (row, numLines) => {
|
||||||
|
_.forEach(mciMap, (mciInfo, mapKey) => {
|
||||||
|
if (mciInfo.position[0] >= row) {
|
||||||
|
if(mciInfo.position[0] < row + numLines) {
|
||||||
|
// unlike scrolling, the rows are actually gone,
|
||||||
|
// so we need to delete any MCI's that are in them
|
||||||
|
delete mciMap[mapKey];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mciInfo.position[0] -= numLines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
ansiParser.on('literal', literal => client.term.write(literal, false));
|
ansiParser.on('literal', literal => client.term.write(literal, false));
|
||||||
ansiParser.on('control', control => client.term.rawWrite(control));
|
ansiParser.on('control', control => client.term.rawWrite(control));
|
||||||
|
|
||||||
|
|
12
core/door.js
12
core/door.js
|
@ -115,9 +115,10 @@ module.exports = class Door {
|
||||||
spawnOptions
|
spawnOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
prePty.once('exit', exitCode => {
|
prePty.onExit(exitEvent => {
|
||||||
|
const {exitCode, signal} = exitEvent;
|
||||||
this.client.log.info(
|
this.client.log.info(
|
||||||
{ exitCode: exitCode },
|
{ exitCode, signal },
|
||||||
'Door pre-command exited'
|
'Door pre-command exited'
|
||||||
);
|
);
|
||||||
return callback(null);
|
return callback(null);
|
||||||
|
@ -167,7 +168,7 @@ module.exports = class Door {
|
||||||
|
|
||||||
this.doorPty.onData(this.doorDataHandler.bind(this));
|
this.doorPty.onData(this.doorDataHandler.bind(this));
|
||||||
|
|
||||||
this.doorPty.once('close', () => {
|
this.doorPty.onExit( (/*exitEvent*/) => {
|
||||||
return this.restoreIo(this.doorPty);
|
return this.restoreIo(this.doorPty);
|
||||||
});
|
});
|
||||||
} else if ('socket' === this.io) {
|
} else if ('socket' === this.io) {
|
||||||
|
@ -180,8 +181,9 @@ module.exports = class Door {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.doorPty.once('exit', exitCode => {
|
this.doorPty.onExit(exitEvent => {
|
||||||
this.client.log.info({ exitCode: exitCode }, 'Door exited');
|
const {exitCode, signal} = exitEvent;
|
||||||
|
this.client.log.info({ exitCode, signal }, 'Door exited');
|
||||||
|
|
||||||
if (this.sockServer) {
|
if (this.sockServer) {
|
||||||
this.sockServer.close();
|
this.sockServer.close();
|
||||||
|
|
|
@ -167,17 +167,17 @@ class ScheduledEvent {
|
||||||
return cb(e);
|
return cb(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc.once('exit', exitCode => {
|
proc.onExit(exitEvent => {
|
||||||
if (exitCode) {
|
if (exitEvent.exitCode) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
{ eventName: this.name, action: this.action, exitCode: exitCode },
|
{ eventName: this.name, action: this.action, exitCode: exitEvent.exitCode },
|
||||||
'Bad exit code while performing scheduled event action'
|
'Bad exit code while performing scheduled event action'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return cb(
|
return cb(
|
||||||
exitCode
|
exitEvent.exitCode
|
||||||
? Errors.ExternalProcess(
|
? Errors.ExternalProcess(
|
||||||
`Bad exit code while performing scheduled event action: ${exitCode}`
|
`Bad exit code while performing scheduled event action: ${exitEvent.exitCode}`
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
|
@ -485,13 +485,10 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
externalProc.once('close', () => {
|
externalProc.onExit(exitEvent => {
|
||||||
return this.restorePipeAfterExternalProc();
|
const {exitCode, signal} = exitEvent;
|
||||||
});
|
|
||||||
|
|
||||||
externalProc.once('exit', exitCode => {
|
|
||||||
this.client.log.debug(
|
this.client.log.debug(
|
||||||
{ cmd: cmd, args: args, exitCode: exitCode },
|
{ cmd: cmd, args: args, exitCode, signal },
|
||||||
'Process exited'
|
'Process exited'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
FROM node:18-buster-slim
|
FROM --platform=${BUILDPLATFORM:-linux/amd64} node:20-bookworm-slim
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
ARG BUILDPLATFORM
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETBRANCH
|
||||||
|
|
||||||
LABEL maintainer="dave@force9.org"
|
LABEL maintainer="dave@force9.org"
|
||||||
|
|
||||||
ENV NVM_DIR /root/.nvm
|
ENV NVM_DIR /root/.nvm
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
COPY . /enigma-bbs
|
|
||||||
|
|
||||||
# Do some installing! (and alot of cleaning up) keeping it in one step for less docker layers
|
|
||||||
# - if you need to debug i recommend to break the steps with individual RUNs)
|
# Just copy the package.json so it only needs to build once
|
||||||
|
COPY package.json /enigma-bbs/
|
||||||
|
|
||||||
|
# Install APT and NPM packages
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y \
|
&& apt-get install -y \
|
||||||
git \
|
git \
|
||||||
curl \
|
curl \
|
||||||
build-essential \
|
build-essential \
|
||||||
python \
|
|
||||||
python3 \
|
python3 \
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
lrzsz \
|
lrzsz \
|
||||||
|
@ -22,9 +28,21 @@ RUN apt-get update \
|
||||||
unrar-free \
|
unrar-free \
|
||||||
p7zip-full \
|
p7zip-full \
|
||||||
dos2unix \
|
dos2unix \
|
||||||
|
&& npm set progress=false && npm config set depth 0 \
|
||||||
&& npm install -g npm@latest \
|
&& npm install -g npm@latest \
|
||||||
&& npm install -g pm2 \
|
&& npm install -g pm2 \
|
||||||
&& cd /enigma-bbs && npm install \
|
&& cd /enigma-bbs && npm install
|
||||||
|
|
||||||
|
|
||||||
|
# Do this after npm install to avoid cache-miss on every code change
|
||||||
|
COPY . /enigma-bbs
|
||||||
|
|
||||||
|
# Then run post source copy steps that have to happen every time
|
||||||
|
RUN dos2unix /enigma-bbs/docker/bin/docker-entrypoint.sh \
|
||||||
|
&& apt-get remove dos2unix -y \
|
||||||
|
&& chmod +x /enigma-bbs/docker/bin/docker-entrypoint.sh \
|
||||||
|
&& cp -f /enigma-bbs/docker/bin/sexyz /usr/local/bin \
|
||||||
|
&& cd /enigma-bbs \
|
||||||
&& pm2 start main.js \
|
&& pm2 start main.js \
|
||||||
&& mkdir -p /enigma-bbs-pre/art \
|
&& mkdir -p /enigma-bbs-pre/art \
|
||||||
&& mkdir /enigma-bbs-pre/mods \
|
&& mkdir /enigma-bbs-pre/mods \
|
||||||
|
@ -32,16 +50,11 @@ RUN apt-get update \
|
||||||
&& cp -rp art/* ../enigma-bbs-pre/art/ \
|
&& cp -rp art/* ../enigma-bbs-pre/art/ \
|
||||||
&& cp -rp mods/* ../enigma-bbs-pre/mods/ \
|
&& cp -rp mods/* ../enigma-bbs-pre/mods/ \
|
||||||
&& cp -rp config/* ../enigma-bbs-pre/config/ \
|
&& cp -rp config/* ../enigma-bbs-pre/config/ \
|
||||||
&& apt-get remove build-essential python python3 libssl-dev git curl -y \
|
&& apt-get remove build-essential python3 libssl-dev git curl -y \
|
||||||
&& apt-get autoremove -y \
|
&& apt-get autoremove -y \
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
|
||||||
&& apt-get clean
|
&& apt-get clean
|
||||||
|
|
||||||
# sexyz
|
|
||||||
COPY docker/bin/sexyz /usr/local/bin
|
|
||||||
RUN dos2unix /enigma-bbs/docker/bin/docker-entrypoint.sh && apt-get remove dos2unix -y
|
|
||||||
RUN chmod +x /enigma-bbs/docker/bin/docker-entrypoint.sh
|
|
||||||
|
|
||||||
# enigma storage mounts
|
# enigma storage mounts
|
||||||
VOLUME /enigma-bbs/art
|
VOLUME /enigma-bbs/art
|
||||||
VOLUME /enigma-bbs/config
|
VOLUME /enigma-bbs/config
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
"minimist": "^1.2.6",
|
"minimist": "^1.2.6",
|
||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
"nntp-server": "3.1.0",
|
"nntp-server": "3.1.0",
|
||||||
"node-pty": "0.10.1",
|
"node-pty": "1.0.0",
|
||||||
"nodemailer": "6.7.7",
|
"nodemailer": "6.7.7",
|
||||||
"otplib": "11.0.1",
|
"otplib": "11.0.1",
|
||||||
"qrcode-generator": "^1.4.4",
|
"qrcode-generator": "^1.4.4",
|
||||||
|
|
Loading…
Reference in New Issue