-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathserver.js
130 lines (125 loc) · 5.15 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Gun Multi-WS Monster */
/* Spawn multiple Gun WebSockets from the same HTTP/HTTPS server
* Each Gun is scoped to its ws.path and intended for ephemeral usage
* MIT Licensed (C) QXIP 2020
*/
const fs = require("fs");
const url = require("url");
const Gun = require("gun"); // load defaults
const no = require('gun/lib/nomem')(); // no-memory storage adapter for RAD
require("gun/sea");
require("gun/lib/then");
const SEA = Gun.SEA;
const http = require("http");
const https = require("https");
const WebSocket = require("ws");
let debug = process.env.DEBUG || false;
let relaypeers = process.env.RELAY || 'https://mirror.rig.airfaas.com/'; // FOR FUTURE DAISY-CHAINING (see hyperswarm to connect guns)
let config = {};
if(debug) console.log(SEA, Gun.SEA);
config.options = {
}
if (!process.env.hasOwnProperty('SSL')||process.env.SSL == false) {
var server = http.createServer();
server.listen(process.env.PORT || 3000);
} else {
config.options.key= process.env.SSLKEY ? fs.readFileSync(process.env.SSLKEY) : false,
config.options.cert= process.env.SSLCERT ? fs.readFileSync(process.env.SSLCERT) : false
var server = https.createServer(config.options);
server.listen(process.env.PORT || 443);
}
let sigs ={};
// LRU with last used sockets
const QuickLRU = require("quick-lru");
const lru = new QuickLRU({ maxSize: 100, onEviction: false });
server.on("upgrade", async function(request, socket, head) {
let parsed = url.parse(request.url,true);
if(debug) console.log("parsed",parsed);
let sig = parsed.query && parsed.query.sig ? parsed.query.sig : false;
let creator = parsed.query && parsed.query.creator ? parsed.query.creator : "server";
let pathname = parsed.pathname || "/gun";
pathname = pathname.replace(/^\/\//g,'/');
if (debug) console.log("Got WS request", pathname);
var gun = { gun: false, server: false };
if (pathname) {
let roomname = pathname.split("").slice(1).join("");
if(debug) console.log("roomname",roomname);
if (lru.has(pathname)) {
// Existing Node
if (debug) console.log("Recycle id", pathname);
gun = await lru.get(pathname);
} else {
// Create Node
if (debug) console.log("Create id", pathname);
// NOTE: Only works with lib/ws.js shim allowing a predefined WS as ws.web parameter in Gun constructor
//gun.server = new WebSocket.Server({ noServer: true, path: pathname });
if (debug) console.log("set peer", request.headers.host + pathname);
if(sig) {
sigs[roomname]=sig;
if(debug) console.log("stored sig ",sig,"to pathname",roomname);
}
let qs = ["sig="+encodeURIComponent((sig ? sig :'')),"creator="+encodeURIComponent((creator ? creator : ''))].join("&");
let relaypath = roomname+'?'+qs;
let peers = []; //relaypeers.split(',').map(function(p){ return p+relaypath; });
if(debug) console.log("peers",peers);
const g = gun.gun = Gun({
peers: peers, // should we use self as peer?
localStorage: false,
store: no,
file: "tmp" + pathname, // make sure not to reuse same storage context
radisk: true, // important for nomem!
multicast: false,
ws: { noServer: true, path: pathname }
});
gun.server = gun.gun.back('opt.ws.web'); // this is the websocket server
lru.set(pathname, gun);
let obj = {
label:roomname.replace(/(_.*)/,''),
timestamp:Gun.state(),
roomname:roomname,
creator:creator
};
var meething = g.get('meething').put({label:'Meething'});
if(debug) console.log('object is',obj);
if(sig) {
let user = g.user();
user.create(roomname,sig, function(dack){
if(debug) console.log("We've got user create ack",dack,roomname,sig);
if(dack.err){ console.log("error in user.create",dack.err); }
user.auth(roomname,sig, function(auth){
if(debug) console.log("We've got user auth ack",auth);
if(auth.err){ console.log('error in auth',auth.err); }
//console.log("auth",auth,roomname,sig);
Object.assign(obj,{
pub:dack.pub,
passwordProtected:'true'
});
if(debug) console.log("putting",roomname,"with object",obj, `to user ${dack.pub}`);
user.get(roomname).put(obj,function(roomack){ //TODO: @marknadal fix me
if(debug) console.log("roomnode?",roomack);
var roomnode = user.get(roomname);
g.get('meething').get(roomname).put(roomnode,function(puback){
if(debug) console.log("put object",puback);
});
});
});
});
} else {
Object.assign(obj,{passwordProtected:false});
g.get("meething").get(roomname).put(obj,function(grack){
if(debug) console.log("room created",grack);
});
}
}
}
if (gun.server) {
// Handle Request
gun.server.handleUpgrade(request, socket, head, function(ws) {
if (debug) console.log("connecting to gun instance", gun.gun.opt()._.opt.ws.path);
gun.server.emit("connection", ws, request);
});
} else {
if (debug) console.log("destroying socket", pathname);
socket.destroy();
}
});