A "multiplayer" HTML5 <canvas> to which people can connect and make changes over time.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

141 lines
3.5 KiB

// webapp.js
// Copyright (C) 2022 Rob Colbert @[email protected]
// License: Apache-2.0
'use strict';
import 'dotenv/config'; // reads .env into process.env
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url)); // jshint ignore:line
import { createRequire } from 'module';
const require = createRequire(import.meta.url); // jshint ignore:line
import express from 'express';
import { v4 as uuidv4 } from 'uuid';
import Redis from 'ioredis';
import CanvasIoServer from './canvas-io-server.js';
import winston from 'winston';
import expressWinston from 'express-winston';
import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import WEBPACK_CONFIG from './webpack.config.js';
const APP_CONFIG = {
pkg: require('./package.json'),
niceGameSdk: require('./node_modules/dtp-nice-game/package.json'),
};
class MultiplayerCanvasApp {
constructor ( ) {
this.app = express();
this.app.locals.config = APP_CONFIG;
this.app.locals.pkg = APP_CONFIG.pkg;
this.app.locals.niceGameSdk = APP_CONFIG.niceGameSdk;
this.app.set('view engine', 'pug');
this.app.set('views', path.join(__dirname, 'app', 'views'));
this.app.use(expressWinston.logger({
transports: [
new winston.transports.Console(),
],
format: winston.format.combine(
winston.format.colorize(),
// winston.format.json(),
),
meta: false,
msg: "HTTP ",
expressFormat: true,
colorize: false,
ignoreRoute: (/*req, res*/) => { return false; },
}));
this.app.use('/dist/assets', express.static(path.join(__dirname, 'app', 'assets')));
/*
* Webpack integration
*/
this.compiler = webpack(WEBPACK_CONFIG);
/*
* Webpack dev server middleware
*/
this.webpackDevMiddleware = webpackDevMiddleware(this.compiler, {
publicPath: WEBPACK_CONFIG.output.publicPath,
});
this.app.use(this.webpackDevMiddleware);
/*
* Application routes
*/
this.app.get('/', this.getCanvasView.bind(this));
}
async start ( ) {
this.redis = new Redis({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
key: process.env.REDIS_KEY_PREFIX || 'dtp',
});
this.redis.on('error', this.onRedisError.bind(this));
console.log('start', 'creating HTTP server');
this.httpServer = require('http').createServer(this.app);
this.io = new CanvasIoServer(this);
await this.io.start();
return new Promise((resolve, reject) => {
this.httpServer.listen(3000, (err) => {
if (err) {
return reject(err);
}
console.log('start', `${APP_CONFIG.pkg.name} online`);
resolve();
});
});
}
async onRedisError (error) {
console.log('Redis error', error);
}
async getCanvasView (req, res) {
/*
* Create a socket connect token and assign it to res.locals for use in the
* view. Store it in Redis for 30 seconds.
*/
res.locals.connectToken = uuidv4();
await this.redis.setex(`connect-token:${res.locals.connectToken}`, 30, JSON.stringify({
imageId: 'test-image',
ip: req.ip,
}));
/*
* Render the Multiplayer Canvas view
*/
res.locals.appModuleUrl = '/dist/canvas-app.bundle.js';
res.render('multiplayer-canvas');
}
}
(async ( ) => {
const app = new MultiplayerCanvasApp();
await app.start();
})();