diff --git a/package.json b/package.json
index 8067637..ae63347 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"ansi-html": "0.0.7",
"bcrypt": "^5.0.0",
"classnames": "2.2.6",
+ "concat-stream-p": "0.1.2",
"connect-redis": "^5.0.0",
"contempo": "1.x",
"debug": "^4.1.1",
diff --git a/src/client/index.ejs b/src/client/index.ejs
index bf8c18d..e203835 100644
--- a/src/client/index.ejs
+++ b/src/client/index.ejs
@@ -5,6 +5,7 @@
<%= htmlWebpackPlugin.options.title %>
+
diff --git a/src/server/http.js b/src/server/http.js
index 0a7ad0d..595e53a 100644
--- a/src/server/http.js
+++ b/src/server/http.js
@@ -1,14 +1,31 @@
/* eslint-disable import/no-extraneous-dependencies */
-import express from 'express';
+import {createReadStream} from 'fs';
import http, {ServerResponse} from 'http';
-import httpProxy from 'http-proxy';
import {join} from 'path';
+import concat from 'concat-stream-p';
+import express from 'express';
+import httpProxy from 'http-proxy';
+import {invokeHookFlat} from 'scwp';
+
import userRoutes from './routes/user';
import passport from './passport';
import session from './session';
-export function createHttpServer() {
+const hydration = async (req, buffer) => {
+ const hydration = JSON.stringify(
+ (await Promise.all(invokeHookFlat('hydration', req)))
+ .reduce((hydration, result) => ({...hydration, ...result}), {}),
+ );
+ return buffer
+ .toString()
+ .replace(
+ 'window.__HYDRATION__ = {};',
+ `window.__HYDRATION__ = ${hydration};`,
+ );
+};
+
+export async function createHttpServer() {
const app = express();
app.use(express.urlencoded({extended: true}));
app.use(session());
@@ -22,19 +39,23 @@ export function createHttpServer() {
secure: false,
target: 'http://127.0.0.1:31345',
});
+ proxy.on('proxyRes', async (proxyRes, req, res) => {
+ const buffer = await proxyRes.pipe(concat());
+ res.end(await hydration(req, buffer));
+ });
proxy.on('error', (err, req, res) => {
if (res instanceof ServerResponse) {
res.status(502).end('Bad Gateway (WDS)');
}
});
- app.get('*', (req, res) => proxy.web(req, res));
+ app.get('*', (req, res) => proxy.web(req, res, {selfHandleResponse: true}));
httpServer.on('close', () => proxy.close());
}
else {
app.use(express.static(join(__dirname, '..', 'client')));
- app.get('*', (req, res) => {
- res.sendFile(join(__dirname, '..', 'client', 'index.html'));
- });
+ const stream = createReadStream(join(__dirname, '..', 'client', 'index.html'));
+ const buffer = await stream.pipe(concat());
+ app.get('*', async (req, res) => res.end(await hydration(req, buffer)));
}
return httpServer;
}
diff --git a/src/server/models/base.js b/src/server/models/base.js
index 3c9e7f2..adf5ee2 100644
--- a/src/server/models/base.js
+++ b/src/server/models/base.js
@@ -2,11 +2,10 @@ import {Model} from 'sequelize';
class BaseModel extends Model {
- // eslint-disable-next-line no-unused-vars
- static associate(map) {}
+ static associate(/* map */) {}
- static attributes() {
- throw new ReferenceError('You must define a static attributes() method in your model.');
+ static get attributes() {
+ return {};
}
}
diff --git a/src/server/models/user.model.js b/src/server/models/user.model.js
index 3552888..b70b634 100644
--- a/src/server/models/user.model.js
+++ b/src/server/models/user.model.js
@@ -3,9 +3,10 @@ import {randomBytes} from 'crypto';
import bcrypt from 'bcrypt';
import {registerHooks} from 'scwp';
-import {DataTypes as Types} from 'sequelize';
+import {DataTypes as Types, Op} from 'sequelize';
import BaseModel from './base';
+import {allModels} from './registrar';
class User extends BaseModel {
@@ -33,6 +34,19 @@ class User extends BaseModel {
});
}
+ async friends() {
+ const {Friendship} = allModels();
+ const friendships = await Friendship.findAll({
+ where: {
+ [Op.or]: [
+ {adderId: this.id},
+ {addeeId: this.id},
+ ],
+ },
+ });
+ return friendships.map(({adderId, addeeId}) => (adderId === this.id ? addeeId : adderId));
+ }
+
validatePassword(plaintext) {
return bcrypt.compare(plaintext, this.hash);
}
diff --git a/src/server/session.js b/src/server/session.js
index 7b473d4..2dab20e 100644
--- a/src/server/session.js
+++ b/src/server/session.js
@@ -1,5 +1,6 @@
-import redis from 'redis';
import session from 'express-session';
+import redis from 'redis';
+import {registerHooks} from 'scwp';
const {
REDIS_HOST,
@@ -20,3 +21,18 @@ export default (options = {}) => (
...options,
})
);
+
+registerHooks({
+ hydration: async (req) => {
+ const hydration = {};
+ const {user} = req;
+ if (user) {
+ hydration.redditUsername = user.redditUsername;
+ hydration.friends = await user.friends();
+ }
+ else {
+ hydration.user = null;
+ }
+ return hydration;
+ },
+}, module.id);
diff --git a/yarn.lock b/yarn.lock
index 66553ee..4ed5fc6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1924,6 +1924,11 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
+bluebird@^2.10.0:
+ version "2.11.0"
+ resolved "https://npm.i12e.cha0s.io/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
+ integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
+
bluebird@^3.5.5, bluebird@^3.7.2:
version "3.7.2"
resolved "https://npm.i12e.cha0s.io/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -2600,6 +2605,14 @@ concat-map@0.0.1:
resolved "https://npm.i12e.cha0s.io/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+concat-stream-p@0.1.2:
+ version "0.1.2"
+ resolved "https://npm.i12e.cha0s.io/concat-stream-p/-/concat-stream-p-0.1.2.tgz#5de0386a3d0a27e2013627f58cddb5c46d8e2d22"
+ integrity sha1-XeA4aj0KJ+IBNif1jN21xG2OLSI=
+ dependencies:
+ bluebird "^2.10.0"
+ concat-stream "^1.5.0"
+
concat-stream@^1.5.0:
version "1.6.2"
resolved "https://npm.i12e.cha0s.io/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"