-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathserver.ts
172 lines (162 loc) · 5.71 KB
/
server.ts
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import { server as WebSocketServer, connection } from 'websocket';
import net from 'net';
import fs from 'fs';
import config from './config';
import { originIsAllowed } from './utils';
import { logger } from './logger';
const createIndexFile = () => {
const protocol = config.ssl.enabled ? 'wss' : 'ws';
const url = `${protocol}://${config.server.address}:${config.server.websocketPort}`;
const output =
'<!DOCTYPE html>\n' +
'<html>\n' +
' <head>\n' +
' <title>Example of a user defined function (UDF) in MySQL</title>\n' +
' <meta charset="UTF-8">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <style>\n' +
' html, body {\n' +
' margin: 0;\n' +
' padding: 0; \n' +
' }\n' +
' #wrapper {\n' +
' width: 320px;\n' +
' margin: 0 auto; \n' +
' text-align: center;\n' +
' padding: 20px 0;\n' +
' }\n' +
' img {\n' +
' // display: block;\n' +
' }\n' +
' </style>\n' +
' <script>\n' +
' document.addEventListener("DOMContentLoaded", (e) => {\n' +
' const ws = new WebSocket("' +
url +
'", "echo-protocol");\n' +
' ws.onmessage = (e) => {\n' +
' const events = ["INSERT", "UPDATE", "DELETE"];\n' +
" const source = 'https://via.placeholder.com/250x64.png/000/fff/?text=' + events[JSON.parse(e.data).type - 2];\n" +
" const toAppend = '<img src=\"' + source + '\" />';\n" +
" const wrapper = document.getElementById('wrapper');\n" +
' wrapper.innerHTML += toAppend + "<br />";\n' +
' };\n' +
' })\n' +
' </script>\n' +
' </head>\n' +
' <body>\n' +
' <div id="wrapper"></div>\n' +
' </body>\n' +
'</html>';
fs.writeFile('index.html', output, (err) => {
if (err) {
return logger.error(err);
}
logger.info('Creating index.html file.');
});
};
export const run = async () => {
// keeps track of all connected clients
const connections: connection[] = [];
let credentials = {};
if (config.ssl.enabled) {
if (!config.ssl.key || !config.ssl.cert) {
logger.error('You need to specify a ssl key and certificate.');
process.exit(-1);
}
const privateKey = fs.readFileSync(config.ssl.key, 'utf8');
const certificate = fs.readFileSync(config.ssl.cert, 'utf8');
credentials = {
key: privateKey,
cert: certificate,
};
}
// create our index.html file
createIndexFile();
// create a listening socket which listens for data sent from our UDF
net
.createServer((sock) => {
sock.on('data', (data) => {
sock.end();
sock.destroy();
// send data to all connected clients
for (let i = 0; i < connections.length; i++) {
connections[i].sendUTF(data);
}
});
sock.on('close', (data) => {});
sock.on('error', (error) => {});
})
.on('error', (error) => {
logger.error(error);
process.exit(-1);
})
.listen(config.server.port, config.server.address, () => {
logger.info(
`Socket server is listening on: ${config.server.address}:${config.server.port}`
);
});
import(`${config.ssl.enabled ? 'https' : 'http'}`).then((http) => {
// create a http server
const httpServer = http
.createServer(credentials, (req: any, res: any) => {
fs.readFile(__dirname + '/../' + req.url, function (err, data) {
if (err) {
res.writeHead(404);
res.end(JSON.stringify(err));
return;
}
res.writeHead(200);
res.end(data);
});
})
.on('error', (error: any) => {
logger.error(error);
process.exit(-1);
})
.listen(config.server.websocketPort, config.server.address, () => {
logger.info(
`Http server is listening on: ${config.server.address}:${config.server.websocketPort}`
);
});
const wsServer = new WebSocketServer({
httpServer,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: config.autoAcceptConnections,
});
wsServer.on('request', (req) => {
const url = new URL(req.origin);
if (!originIsAllowed(url.hostname)) {
// Make sure we only accept requests from an allowed origin
req.reject();
logger.warn(`Connection from origin ${req.origin} rejected.`);
return;
}
const con = req
.accept('echo-protocol', req.origin)
.on('message', function (this: connection, message) {
if (message.type === 'utf8') {
logger.debug(`Received Message: ${message.utf8Data}`);
this.sendUTF(message.utf8Data);
} else if (message.type === 'binary') {
logger.debug(
`Received Binary Message of ${message.binaryData.length} bytes`
);
this.sendBytes(message.binaryData);
}
})
.on('close', function (this: connection, reasonCode, description) {
const index = connections.indexOf(this);
// TODO: Do we need to close the connection
// connections[index].close();
connections.splice(index, 1);
logger.debug(`Peer ${this.remoteAddress} disconnected.`);
});
connections.push(con);
});
});
};