Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sockets: Go rewrite #3536

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion config/config-example.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,22 @@ exports.workers = 1;
// TODO: allow SSL to actually be possible to use for third-party servers at
// some point.

// golang - toggle using Go instead of Node for sockets workers
// Node workers are more unstable at handling connections because of bugs in
// sockjs-node, but sending/receiving messages over connections on Go workers
// is slightly slower due to the extra work involved in performing IPC with
// them safely. This should be left set to false unless you know what you are
// doing.
exports.golang = false;

// proxyip - proxy IPs with trusted X-Forwarded-For headers
// This can be either false (meaning not to trust any proxies) or an array
// of strings. Each string should be either an IP address or a subnet given
// in CIDR notation. You should usually leave this as `false` unless you
// know what you are doing.
exports.proxyip = false;

// ofe - write heapdumps if sockets.js workers run out of memory.
// ofe - write heapdumps if Node sockets workers run out of memory
// If you wish to enable this, you will need to install ofe, as it is not a
// installed by default:
// $ npm install --no-save ofe
Expand Down
35 changes: 35 additions & 0 deletions dev-tools/sockets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const {Session, SockJSConnection} = require('sockjs/lib/transport');

const chars = 'abcdefghijklmnopqrstuvwxyz1234567890-';
let sessionidCount = 0;

/**
* @return string
*/
function generateSessionid() {
let ret = '';
let idx = sessionidCount;
for (let i = 0; i < 8; i++) {
ret = chars[idx % chars.length] + ret;
idx = idx / chars.length | 0;
}
sessionidCount++;
return ret;
}

/**
* @param {string} sessionid
* @param {{options: {{}}} config
* @return SockJSConnection
*/
exports.createSocket = function (sessionid = generateSessionid(), config = {options: {}}) {
let session = new Session(sessionid, config);
let socket = new SockJSConnection(session);
socket.remoteAddress = '127.0.0.1';
socket.protocol = 'websocket';
return socket;
};

// TODO: move worker mocks here, use require('../sockets-workers').Multiplexer to stub IPC
65 changes: 51 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@
"private": true,
"license": "MIT",
"devDependencies": {
"@types/cloud-env": "^0.2.0",
"@types/node": "^8.0.28",
"@types/node-static": "^0.7.0",
"@types/nodemailer": "^1.3.33",
"@types/ofe": "^0.5.0",
"@types/sockjs": "^0.3.31",
"eslint": "^4.0.0",
"mocha": "^3.0.0",
"@types/node": "^8.0.1",
"@types/nodemailer": "^1.3.33",
"typescript": "^2.5.0-dev.20170622"
}
}
82 changes: 82 additions & 0 deletions pokemon-showdown
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,88 @@ try {
}

if (!process.argv[2] || /^[0-9]+$/.test(process.argv[2])) {
// Check if the server is configured to use Go, and ensure the required
// environment variables and dependencies are available if that is the case

let config;
try {
config = require('./config/config');
} catch (e) {}

if (config && config.golang) {
// GOPATH and GOROOT are optional to a degree, but we need them in order
// to be able to handle Go dependencies. Since Go only cares about the
// first path in the list, so will we.
const GOPATH = child_process.execSync('go env GOPATH', {stdio: null, encoding: 'utf8'})
.trim()
.split(path.delimiter)[0]
.replace(/^"(.*)"$/, '$1');
if (!GOPATH) {
// Should never happen, but it does on Bash on Ubuntu on Windows.
console.error('There is no $GOPATH environment variable set.');
process.exit(1);
}

const dependencies = ['github.com/gorilla/mux', 'github.com/igm/sockjs-go/sockjs'];
let packages = child_process.execSync('go list all', {stdio: null, encoding: 'utf8'});
for (let dep of dependencies) {
if (!packages.includes(dep)) {
console.log(`Installing ${dep}...`);
child_process.execSync(`go install ${dep}`, {stdio: 'inherit'});
}
}

let stat;
let needsSrcDir = false;
try {
stat = fs.lstatSync(path.resolve(GOPATH, 'src/github.com/Zarel'));
} catch (e) {
needsSrcDir = true;
} finally {
if (stat && !stat.isDirectory()) {
needsSrcDir = true;
}
}

let srcPath = path.resolve(process.cwd(), 'sockets');
let tarPath = path.resolve(GOPATH, 'src/github.com/Zarel/Pokemon-Showdown/sockets');
if (needsSrcDir) {
try {
fs.mkdirSync(path.resolve(GOPATH, 'src/github.com/Zarel'));
fs.mkdirSync(path.resolve(GOPATH, 'src/github.com/Zarel/Pokemon-Showdown'));
} catch (e) {
console.error(`Cannot make go source directory for the sockets library files! Symlink them manually from ${srcPath} to ${tarPath}`);
process.exit(1);
}
}

try {
stat = fs.lstatSync(tarPath);
} catch (e) {}

if (!stat || !stat.isSymbolicLink()) {
// Windows requires administrator privileges to make symlinks, so we
// make junctions instead. For our purposes they're compatible enough
// with symlinks on UNIX-like OSes.
let symlinkType = (process.platform === 'win32') ? 'junction' : 'dir';
try {
fs.symlinkSync(srcPath, tarPath, symlinkType);
} catch (e) {
console.error(`Cannot make go source directory for the sockets library files! Symlink them manually from ${srcPath} to ${tarPath}`);
process.exit(1);
}
}

console.log('Building Go source libs...');
try {
child_process.execSync('go install github.com/Zarel/Pokemon-Showdown/sockets', {stdio: 'inherit'});
} catch (e) {
// Go will show the errors that caused compiling Go's files to fail, so
// there's no reason to bother logging anything of our own.
process.exit(1);
}
}

// Start the server. We manually load app.js so it can be configured to run as
// the main module, rather than this file being considered the main module.
// This ensures any dependencies that were just installed can be found when
Expand Down
Loading