Gopher server revamp!
* gophermap support * More generic and flexible server
This commit is contained in:
parent
228cd79989
commit
f7e4b57763
|
@ -9,6 +9,7 @@ This document attempts to track **major** changes and additions in ENiGMA½. For
|
||||||
* New `PV` ACS check for arbitrary user properties. See [ACS](./docs/configuration/acs.md) for details.
|
* New `PV` ACS check for arbitrary user properties. See [ACS](./docs/configuration/acs.md) for details.
|
||||||
* The `message` arg used by `msg_list` has been deprecated. Please starting using `messageIndex` for this purpose. Support for `message` will be removed in the future.
|
* The `message` arg used by `msg_list` has been deprecated. Please starting using `messageIndex` for this purpose. Support for `message` will be removed in the future.
|
||||||
* Added ability to export/download messages. This is enabled in the default menu. See `messageAreaViewPost` in [the default message base template](./misc/menu_templates/message_base.in.hjson) and look for the download options (`@method:addToDownloadQueue`, etc.) for details on adding to your system!
|
* Added ability to export/download messages. This is enabled in the default menu. See `messageAreaViewPost` in [the default message base template](./misc/menu_templates/message_base.in.hjson) and look for the download options (`@method:addToDownloadQueue`, etc.) for details on adding to your system!
|
||||||
|
* The Gopher server has had a revamp! Standard `gophermap` files are now served along with any other content you configure for your Gopher Hole! A default [gophermap](https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu) can be found [in the misc directory](./misc/gophermap) that behaves like the previous implementation. See [Gopher docs](./docs/servers/gopher.md) for more information.
|
||||||
|
|
||||||
## 0.0.11-beta
|
## 0.0.11-beta
|
||||||
* Upgraded from `alpha` to `beta` -- The software is far along and mature enough at this point!
|
* Upgraded from `alpha` to `beta` -- The software is far along and mature enough at this point!
|
||||||
|
|
|
@ -263,7 +263,7 @@ module.exports = () => {
|
||||||
port : 8070,
|
port : 8070,
|
||||||
publicHostname : 'another-fine-enigma-bbs.org',
|
publicHostname : 'another-fine-enigma-bbs.org',
|
||||||
publicPort : 8070, // adjust if behind NAT/etc.
|
publicPort : 8070, // adjust if behind NAT/etc.
|
||||||
bannerFile : 'gopher_banner.asc',
|
staticRoot : paths.join(__dirname, './../gopher'),
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set messageConferences{} to maps of confTag -> [ areaTag1, areaTag2, ... ]
|
// Set messageConferences{} to maps of confTag -> [ areaTag1, areaTag2, ... ]
|
||||||
|
|
|
@ -27,6 +27,7 @@ const _ = require('lodash');
|
||||||
const fs = require('graceful-fs');
|
const fs = require('graceful-fs');
|
||||||
const paths = require('path');
|
const paths = require('path');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const async = require('async');
|
||||||
|
|
||||||
const ModuleInfo = exports.moduleInfo = {
|
const ModuleInfo = exports.moduleInfo = {
|
||||||
name : 'Gopher',
|
name : 'Gopher',
|
||||||
|
@ -81,8 +82,8 @@ exports.getModule = class GopherModule extends ServerModule {
|
||||||
this.publicHostname = config.contentServers.gopher.publicHostname;
|
this.publicHostname = config.contentServers.gopher.publicHostname;
|
||||||
this.publicPort = config.contentServers.gopher.publicPort;
|
this.publicPort = config.contentServers.gopher.publicPort;
|
||||||
|
|
||||||
this.addRoute(/^\/?\r\n$/, this.defaultGenerator);
|
this.addRoute(/^\/?msgarea(\/[a-z0-9_-]+(\/[a-z0-9_-]+)?(\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(_raw)?)?)?\/?\r\n$/, this.messageAreaGenerator);
|
||||||
this.addRoute(/^\/msgarea(\/[a-z0-9_-]+(\/[a-z0-9_-]+)?(\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(_raw)?)?)?\/?\r\n$/, this.messageAreaGenerator);
|
this.addRoute(/^(\/?[^\t\r\n]*)\r\n$/, this.staticGenerator);
|
||||||
|
|
||||||
this.server = net.createServer( socket => {
|
this.server = net.createServer( socket => {
|
||||||
socket.setEncoding('ascii');
|
socket.setEncoding('ascii');
|
||||||
|
@ -161,22 +162,56 @@ exports.getModule = class GopherModule extends ServerModule {
|
||||||
return `${itemType}${text}\t${selector}\t${hostname}\t${port}\r\n`;
|
return `${itemType}${text}\t${selector}\t${hostname}\t${port}\r\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultGenerator(selectorMatch, cb) {
|
staticGenerator(selectorMatch, cb) {
|
||||||
this.log.debug( { selector : selectorMatch[0] }, 'Serving default content');
|
this.log.debug( { selector : selectorMatch[1] || '(gophermap)' }, 'Serving static content');
|
||||||
|
|
||||||
let bannerFile = _.get(Config(), 'contentServers.gopher.bannerFile', 'gopher_banner.asc');
|
const requestedPath = selectorMatch[1];
|
||||||
bannerFile = paths.isAbsolute(bannerFile) ? bannerFile : paths.join(__dirname, '../../../misc', bannerFile);
|
let path = this.resolveContentPath(requestedPath);
|
||||||
fs.readFile(bannerFile, 'utf8', (err, banner) => {
|
if (!path) {
|
||||||
if(err) {
|
return cb('Not found');
|
||||||
return cb('You have reached an ENiGMA½ Gopher server!');
|
}
|
||||||
|
|
||||||
|
fs.stat(path, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
return cb('Not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
banner = splitTextAtTerms(banner).map(l => this.makeItem(ItemTypes.InfoMessage, l)).join('');
|
let isGopherMap = false;
|
||||||
banner += this.makeItem(ItemTypes.SubMenu, 'Public Message Area', '/msgarea');
|
if (stats.isDirectory()) {
|
||||||
return cb(banner);
|
path = paths.join(path, 'gophermap');
|
||||||
|
isGopherMap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.readFile(path, isGopherMap ? 'utf8' : null, (err, content) => {
|
||||||
|
if (err) {
|
||||||
|
let content = 'You have reached an ENiGMA½ Gopher server!\r\n';
|
||||||
|
content += this.makeItem(ItemTypes.SubMenu, 'Public Message Area', '/msgarea');
|
||||||
|
return cb(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGopherMap) {
|
||||||
|
// Convert any UNIX style LF's to DOS CRLF's
|
||||||
|
content = content.replace(/\r?\n/g, '\r\n');
|
||||||
|
|
||||||
|
// variable support
|
||||||
|
content = content
|
||||||
|
.replace(/{publicHostname}/g, this.publicHostname)
|
||||||
|
.replace(/{publicPort}/g, this.publicPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb(content);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveContentPath(requestPath) {
|
||||||
|
const staticRoot = _.get(Config(), 'contentServers.gopher.staticRoot');
|
||||||
|
const path = paths.resolve(staticRoot, `.${requestPath}`);
|
||||||
|
if (path.startsWith(staticRoot)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notFoundGenerator(selector, cb) {
|
notFoundGenerator(selector, cb) {
|
||||||
this.log.debug( { selector }, 'Serving not found content');
|
this.log.debug( { selector }, 'Serving not found content');
|
||||||
return cb('Not found');
|
return cb('Not found');
|
||||||
|
|
|
@ -3,7 +3,7 @@ layout: page
|
||||||
title: Gopher Server
|
title: Gopher Server
|
||||||
---
|
---
|
||||||
## The Gopher Content Server
|
## The Gopher Content Server
|
||||||
The Gopher *content server* provides access to publicly exposed message conferences and areas over Gopher (gopher://).
|
The Gopher *content server* provides access to publicly exposed message conferences and areas over Gopher (gopher://) as well as any other content you wish to serve in your Gopher Hole!
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
Gopher configuration is found in `contentServers.gopher` in `config.hjson`.
|
Gopher configuration is found in `contentServers.gopher` in `config.hjson`.
|
||||||
|
@ -11,14 +11,36 @@ Gopher configuration is found in `contentServers.gopher` in `config.hjson`.
|
||||||
| Item | Required | Description |
|
| Item | Required | Description |
|
||||||
|------|----------|-------------|
|
|------|----------|-------------|
|
||||||
| `enabled` | :+1: | Set to `true` to enable Gopher |
|
| `enabled` | :+1: | Set to `true` to enable Gopher |
|
||||||
|
| `staticRoot` | :+1: | Sets the path serving as the static root path for all Gopher content. Defaults to `enigma-bbs/gopher`.<br>See also **Gophermap's** below |
|
||||||
| `port` | :-1: | Override the default port of `8070` |
|
| `port` | :-1: | Override the default port of `8070` |
|
||||||
| `publicHostName` | :+1: | Set the **public** hostname/domain that Gopher will serve to the outside world. Example: `myfancybbs.com` |
|
| `publicHostname` | :+1: | Set the **public** hostname/domain that Gopher will serve to the outside world. Example: `myfancybbs.com` |
|
||||||
| `publicPort` | :+1: | Set the **public** port that Gopher will serve to the outside world. |
|
| `publicPort` | :+1: | Set the **public** port that Gopher will serve to the outside world. |
|
||||||
| `messageConferences` | :+1: | An map of *conference tags* to *area tags* that are publicly exposed via Gopher. See example below. |
|
| `messageConferences` | :-1: | An map of *conference tags* to *area tags* that are publicly exposed via Gopher. See example below. |
|
||||||
|
|
||||||
Notes on `publicHostName` and `publicPort`:
|
Notes on `publicHostname` and `publicPort`:
|
||||||
The Gopher protocol serves content that contains host/domain and port even when referencing it's own documents. Due to this, these members must be set to your publicly addressable Gopher server!
|
The Gopher protocol serves content that contains host/domain and port even when referencing it's own documents. Due to this, these members must be set to your publicly addressable Gopher server!
|
||||||
|
|
||||||
|
## Gophermap's
|
||||||
|
[Gophermap's](https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu) are how to build menus for your Gopher Hole. Each map is a simple text file named `gophermap` (all lowercase, no extension) with DOS style CRLF endings.
|
||||||
|
|
||||||
|
Within any directory nested within your `staticRoot` may live a `gophermap`. A template may be found in the `enigma-bbsmisc` directory.
|
||||||
|
|
||||||
|
ENiGMA will pre-process `gophermap` files replacing in following variables:
|
||||||
|
* `{publicHostname}`: The public hostname from your config.
|
||||||
|
* `{publicPort}`: The public port from your config.
|
||||||
|
|
||||||
|
:information_source: See [Wikipedia](https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu) for more information on the `gophermap` format.
|
||||||
|
|
||||||
|
:bulb: Tools such as [gfu](https://rawtext.club/~sloum/gfu.html) may help you with `gophermap`'s
|
||||||
|
|
||||||
|
### Example Gophermap
|
||||||
|
An example `gophermap` living in `enigma-bbs/gopher`:
|
||||||
|
```
|
||||||
|
iWelcome to a Gopher server! {publicHostname} {publicPort}
|
||||||
|
1Public Message Area /msgarea {publicHostname} {publicPort}
|
||||||
|
.
|
||||||
|
```
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
Let's suppose you are serving Gopher for your BBS at `myfancybbs.com`. Your ENiGMA½ system is listening on the default Gopher `port` of 8070 but you're behind a firewall and want port 70 exposed to the public. Lastly, you want to expose some fsxNet areas:
|
Let's suppose you are serving Gopher for your BBS at `myfancybbs.com`. Your ENiGMA½ system is listening on the default Gopher `port` of 8070 but you're behind a firewall and want port 70 exposed to the public. Lastly, you want to expose some fsxNet areas:
|
||||||
|
|
||||||
|
@ -26,9 +48,10 @@ Let's suppose you are serving Gopher for your BBS at `myfancybbs.com`. Your ENiG
|
||||||
contentServers: {
|
contentServers: {
|
||||||
gopher: {
|
gopher: {
|
||||||
enabled: true
|
enabled: true
|
||||||
publicHostName: myfancybbs.com
|
publicHostname: myfancybbs.com
|
||||||
publicPort: 70
|
publicPort: 70
|
||||||
|
|
||||||
|
// Expose some public message conferences/areas
|
||||||
messageConferences: {
|
messageConferences: {
|
||||||
fsxnet: { // fsxNet's conf tag
|
fsxnet: { // fsxNet's conf tag
|
||||||
// Areas of fsxNet we want to expose:
|
// Areas of fsxNet we want to expose:
|
||||||
|
|
|
@ -242,8 +242,8 @@
|
||||||
port: XXXXX
|
port: XXXXX
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
// bannerFile path in misc/ by default. Full paths allowed.
|
// The root directory to serve gophermaps and other content
|
||||||
bannerFile: XXXXX
|
staticRoot: XXXXX
|
||||||
|
|
||||||
//
|
//
|
||||||
// The Gopher Content Server can export message base
|
// The Gopher Content Server can export message base
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
_____________________ _____ ____________________ __________\_ /
|
|
||||||
\__ ____/\_ ____ \ /____/ / _____ __ \ / ______/ // /___jp!
|
|
||||||
// __|___// | \// |// | \// | | \// \ /___ /_____
|
|
||||||
/____ _____| __________ ___|__| ____| \ / _____ \
|
|
||||||
---- \______\ -- |______\ ------ /______/ ---- |______\ - |______\ /__/ // ___/
|
|
||||||
/__ _\
|
|
||||||
<*> ENiGMA½ // HTTPS://GITHUB.COM/NUSKOOLER/ENIGMA-BBS <*> /__/
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
i_____________________ _____ ____________________ __________\_ /
|
||||||
|
i\__ ____/\_ ____ \ /____/ / _____ __ \ / ______/ // /___jp!
|
||||||
|
i// __|___// | \// |// | \// | | \// \ /___ /_____
|
||||||
|
i/____ _____| __________ ___|__| ____| \ / _____ \
|
||||||
|
i---- \______\ -- |______\ ------ /______/ ---- |______\ - |______\ /__/ // ___/
|
||||||
|
i /__ _\
|
||||||
|
i <*> ENiGMA½ // HTTPS://GITHUB.COM/NUSKOOLER/ENIGMA-BBS <*> /__/
|
||||||
|
i
|
||||||
|
i-------------------------------------------------------------------------------
|
||||||
|
i
|
||||||
|
1Public Message Area /msgarea {publicHostname} {publicPort}
|
||||||
|
.
|
|
@ -146,6 +146,12 @@ install_node_packages() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy_template_files() {
|
||||||
|
if [[ ! -f "./gopher/gophermap" ]]; then
|
||||||
|
cp "./misc/gophermap" "./gopher/gophermap"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
enigma_footer() {
|
enigma_footer() {
|
||||||
log "ENiGMA½ installation complete!"
|
log "ENiGMA½ installation complete!"
|
||||||
echo -e "\e[1;33m"
|
echo -e "\e[1;33m"
|
||||||
|
@ -189,6 +195,7 @@ install_nvm
|
||||||
configure_nvm
|
configure_nvm
|
||||||
download_enigma_source
|
download_enigma_source
|
||||||
install_node_packages
|
install_node_packages
|
||||||
|
copy_template_files
|
||||||
enigma_footer
|
enigma_footer
|
||||||
|
|
||||||
} # this ensures the entire script is downloaded before execution
|
} # this ensures the entire script is downloaded before execution
|
||||||
|
|
Loading…
Reference in New Issue