Skip to content

Commit 51dc9bf

Browse files
committed
initial commit
0 parents  commit 51dc9bf

19 files changed

+1468
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__*
2+
node_modules/
3+
config.json

.vscode/extensions.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
// See http://go.microsoft.com/fwlink/?LinkId=827846
3+
// for the documentation about the extensions.json format
4+
"recommendations": [
5+
"dbaeumer.vscode-eslint"
6+
]
7+
}

.vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"eslint.autoFixOnSave": true,
3+
"files.eol": "\n",
4+
"javascript.updateImportsOnFileMove.enabled": "always"
5+
}

development.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
process.stdin.setEncoding('utf8');
3+
process.stdin.on('data', async input => {
4+
try {
5+
let t = eval(input.toString().trim());
6+
if (t instanceof Promise) console.log(await t);
7+
else console.log(t);
8+
} catch (e) {
9+
console.warn(e);
10+
}
11+
});
12+
process.on('restart', async () => {
13+
console.log('Signal detected, restarting...');
14+
await global.Hydro.stop();
15+
await global.Hydro.destory();
16+
delete global.Hydro;
17+
delete require.cache;
18+
run();
19+
});
20+
21+
async function run() {
22+
const hydro = require('./index.js');
23+
let config;
24+
try {
25+
config = require('./config.json');
26+
} catch (e) {
27+
config = {};
28+
}
29+
global.Hydro = new hydro(config);
30+
await Hydro.load();
31+
await Hydro.listen();
32+
}
33+
34+
run();

handlers/user.js

Whitespace-only changes.

index.js

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
const
2+
log = require('./lib/log.js').get('Worker'),
3+
bson = require('bson'),
4+
Koa = require('koa'),
5+
Router = require('koa-router'),
6+
MongoStore = require('koa-session2-mongostore'),
7+
path = require('path'),
8+
mongo = require('mongodb'),
9+
EventEmitter = require('events');
10+
11+
module.exports = class Hydro extends EventEmitter {
12+
constructor(Hydro_config) {
13+
super();
14+
this.cfg = Hydro_config;
15+
this.config = {};
16+
this.locales = {};
17+
this.lib = {};
18+
this.status = {};
19+
this.sockets = [];
20+
this.routes = [];
21+
this.routers = [];
22+
this.serviceID = new bson.ObjectID();
23+
this.sessionOpt = {
24+
store: new MongoStore({
25+
collection: 'session',
26+
url: this.cfg.db_url,
27+
dbName: this.cfg.db_name,
28+
collName: 'session'
29+
})
30+
};
31+
this.app = new Koa();
32+
this.app.keys = this.cfg.keys || ['Hydro'];
33+
this.router = new Router();
34+
this.server = require('http').createServer(this.app.callback());
35+
this.io = require('socket.io')(this.server, { cookie: true });
36+
}
37+
async load() {
38+
await this.connectDatabase();
39+
await this.mountLib();
40+
await require('./lib/deploy.js')(this.db, this.lib);
41+
this.app.use((require('./modules/trace/index.js'))({
42+
sourceMap: false
43+
}));
44+
this.app.use(require('./modules/static')(path.join(__dirname, 'public'), false));
45+
this.app.use(require('koa-morgan')(':method :url :status :res[content-length] - :response-time ms'));
46+
this.app.use(require('koa-body')({
47+
patchNode: true,
48+
multipart: true,
49+
formidable: {
50+
uploadDir: path.join(__dirname, 'uploads'),
51+
keepExtensions: true
52+
}
53+
}));
54+
this.app.use(require('koa-session2')(this.sessionOpt));
55+
this.app.use(async (ctx, next) => {
56+
let that = this;
57+
ctx.state.url = function (name, params) {
58+
let route = that.router.route(name);
59+
if (route) {
60+
let args = Array.prototype.slice.call(arguments, 1);
61+
return route.url.apply(route, args);
62+
}
63+
return '#';
64+
};
65+
ctx.state._ = msg => this.locales[ctx.state.user.language][msg] || msg;
66+
await next();
67+
});
68+
//TODO(masnn) Load main routes.
69+
this.app.use(this.router.routes()).use(this.router.allowedMethods());
70+
this.status.loaded = true;
71+
}
72+
async listen() {
73+
await this.server.listen(this.cfg.port);
74+
this.status.listening = true;
75+
}
76+
async stop() {
77+
await this.server.close();
78+
this.status.listening = false;
79+
}
80+
async destory() {
81+
82+
}
83+
async restart() {
84+
process.emit('restart');
85+
}
86+
async connectDatabase() {
87+
try {
88+
let Database = await require('mongodb').MongoClient.connect(
89+
this.cfg.db_url, { useNewUrlParser: true, useUnifiedTopology: true }
90+
);
91+
this.db = Database.db(this.cfg.db_name);
92+
this.gfs = require('gridfs')(this.db, mongo);
93+
} catch (e) {
94+
log.error('Unable to connect to database.');
95+
log.error(e);
96+
process.exit(1);
97+
}
98+
}
99+
async mountLib() {
100+
let conf = require('./lib/config.js');
101+
this.lib.conf = new conf({ db: this.db });
102+
let user = require('./lib/user.js');
103+
this.lib.user = new user({ db: this.db });
104+
}
105+
};

lib/config.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = class CONFIG {
2+
constructor(item) {
3+
this.coll = item.db.collection('config');
4+
}
5+
async get(key = null) {
6+
if (key) {
7+
let data = await this.coll.findOne({ key });
8+
if (data) return data.value;
9+
else return null;
10+
} else return await this.coll.find().toArray();
11+
}
12+
async set(key, value) {
13+
let doc = await this.coll.findOne({ key });
14+
if (doc) await this.coll.deleteOne({ key });
15+
await this.coll.insertOne({ key, value });
16+
}
17+
unset(key) { return this.coll.deleteMany({ key }); }
18+
};

lib/deploy.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const
2+
log = require('./log.js').get('Deploy'),
3+
expects = {
4+
udoc: {
5+
uid: 0,
6+
uname: 'Guest',
7+
uname_lower: 'guest',
8+
password: '',
9+
10+
email_lower: '[email protected]',
11+
perm: [],
12+
field: 'local'
13+
}
14+
};
15+
16+
async function db_install(db, lib) {
17+
log.info('\nIt seem that it\'s your first time to run Hydro.\nWe are now preparing database.');
18+
let udoc = await db.collection('user').findOne({ uid: 0 });
19+
if (udoc) expects.udoc.perm = udoc.perm;
20+
await db.collection('user').deleteMany({ uid: 0 });
21+
await db.collection('user').insertOne(expects.udoc);
22+
await Promise.all([
23+
db.collection('user').createIndex({ 'uid': 1 }, { unique: true }),
24+
db.collection('user').createIndex({ 'uname': 1 }, { unique: true }),
25+
db.collection('user').createIndex({ 'uname_lower': 1 }, { unique: true }),
26+
db.collection('user').createIndex({ 'email': 1 }, { unique: true }),
27+
db.collection('user').createIndex({ 'email_lower': 1 }, { unique: true }),
28+
db.collection('config').createIndex({ 'key': 1 }, { unique: true })
29+
]);
30+
await lib.conf.set('dbver', 1);
31+
log.info('Database installed.');
32+
process.emit('restart');
33+
}
34+
module.exports = async (db, lib) => {
35+
if (await lib.conf.get('dbver') != 1) await db_install(db, lib).catch(e => {
36+
log.error(e);
37+
log.error('Database installation failed.');
38+
process.exit(1);
39+
});
40+
};

lib/log.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
get: function () {
3+
return console;
4+
}
5+
}

lib/user.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = class USER {
2+
constructor(item) {
3+
this.coll = item.db.collection('user');
4+
}
5+
getByUID(uid) {
6+
return this.coll.findOne({ uid });
7+
}
8+
};

modules/static/index.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const { resolve } = require('path');
4+
const assert = require('assert');
5+
const send = require('koa-send');
6+
const { drop } = require('lodash');
7+
8+
module.exports = function serve(root, rewrite) {
9+
let opts = {};
10+
assert(root, 'root directory is required to serve files');
11+
opts.root = resolve(root);
12+
if (opts.index !== false) opts.index = opts.index || 'index.html';
13+
return async function serve(ctx, next) {
14+
await next();
15+
if (ctx.method !== 'HEAD' && ctx.method !== 'GET') return;
16+
if (ctx.body != null || ctx.status !== 404) return;
17+
if (rewrite) {
18+
let temp = ctx.path.split('/');
19+
if (temp.length < 3) return;
20+
let plugin = temp[1];
21+
let path = drop(temp, 2);
22+
try {
23+
await send(ctx, plugin + '/public/' + path.join('/'), opts);
24+
} catch (err) {
25+
if (err.status !== 404) throw err;
26+
}
27+
} else try {
28+
await send(ctx, ctx.path, opts);
29+
} catch (err) {
30+
if (err.status !== 404) throw err;
31+
}
32+
};
33+
};

modules/trace/index.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const statuses = require('statuses');
2+
const { isFunction } = require('core-util-is');
3+
const Tracer = require('./tracer');
4+
5+
module.exports = function (opts) {
6+
const tracer = new Tracer(opts);
7+
// source map support for compiled file
8+
let errorCallback;
9+
if (opts && isFunction(opts.error)) errorCallback = opts.error;
10+
else errorCallback = () => { };
11+
return (ctx, next) => {
12+
return Promise.resolve().then(next).then(() => {
13+
if (ctx.res.statusCode !== 404) return true;
14+
return ctx.throw(404, `url \`${ctx.path}\` not found.`);
15+
}).catch(err => {
16+
if (errorCallback(err, ctx) === false) return Promise.resolve();
17+
if (typeof err.status !== 'number' || !statuses[err.status])
18+
err.status = 500;
19+
ctx.status = err.status;
20+
return tracer.run(ctx, err);
21+
});
22+
};
23+
};

modules/trace/template/404.html

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Not Found</title>
7+
</head>
8+
9+
<body>
10+
<h1>Not Found</h1>
11+
<pre>{{errMsg}}</pre>
12+
</body>
13+
14+
</html>

modules/trace/template/500.html

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<title>Internal Server Error</title>
7+
</head>
8+
9+
<body>
10+
<h1>Internal Server Error</h1>
11+
<pre>{{errMsg}}</pre><br />
12+
<pre>{{error}}</pre>
13+
</body>
14+
15+
</html>

0 commit comments

Comments
 (0)