-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.js
272 lines (232 loc) · 8.42 KB
/
index.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
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// chrome-speech-synthesis
// this is web application service written for node.js/express
// which acts as gateway API server for google chrome
//
// http GET request from remote
// --> chrome-speech synthesis server
// --> google chrome voice API (thru socket.io)
//
// author: jaejunh @embian.com
// license: MIT
// date: 2016.2.19
//
////////////////////////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////////////////////////
var servicePort = 3000;
var BROADCAST_KEY = "embian";
var defaultVoice = "ko-KR";
// you can change the keyLength to much bigger size if you want
var keyLength = 4;
// client can start the chrome command line with GET parameter
// id=my_wishful_id_in_alphanumeric&proxyid=someid
// if that's the case, one also need to specify PROXYID
//
// so change PROXYID for yoursite for security
var PROXYID = "embian";
////////////////////////////////////////////////////////////////////////
// NOTE: for multi user service, you need to make separate
// speaker ID registration process where speaker ID is always
// assigned and bounded by user's preference.
//
// In my case, it was over-kill to implement that because
// I will be just using one speaker ID to bridge on speaker.
// where I can get away with broadcast key.
////////////////////////////////////////////////////////////////////////
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
//var LanguageDetect = require('languagedetect');
//var ld = new LanguageDetect();
// view engine setup
app.set('views', __dirname + '/views');
// set the view engine to ejs
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
var util = require('util');
////////////////////////////////////////////////////////////////////////
// Global Variable
////////////////////////////////////////////////////////////////////////
var socket_ids = [];
var errCode = { 530: "General Error:",
531: "Unicast with No Specified:",
532: "Unicast with No Client under that name:",
533: "Unicast with No Message:",
550: "Unknown Error:" };
////////////////////////////////////////////////////////////////////////
// Http Request Handlers
////////////////////////////////////////////////////////////////////////
// main html file for google chrome service.
app.get('/', function(req, res){
var id=req.query.id;
var proxyid=req.query.proxyid
var speakerID = "";
var speakerIDLabel = "..Generating ID...";
if (id == undefined || id == "" || proxyid== undefined || proxyid == "") {
// wrong syntax. nothing to set
} else if (proxyid == PROXYID) {
// need to set variables
// speakerID has to alphanumeric
speakerID = id.replace(/([^a-zA-Z0-9])/,"");
speakerIDLabel = speakerID;
} else {
// wrong PROXYID
}
res.render(__dirname +'/views/index.ejs', {
speakerID: speakerID,
speakerIDLabel: speakerIDLabel
});
});
// GET handler .
app.get('/client', function(req,res) {
// process parameters
var debug=req.query.debug;
var msg=req.query.msg;
var voice=req.query.voice ? req.query.voice : defaultVoice;
var pitch=parseFloat(req.query.pitch);
var rate=parseFloat(req.query.rate);
var volume=parseFloat(req.query.volume);
var to=req.query.to;
var from="web";
// to must be there
if (to == undefined || to === "") {
d = new Date();
return res.status(531).send(errCode[531]+po(req.query,false));
}
var msgObj = buildMsg(msg,pitch,rate,volume,voice,to,from);
d = new Date();
console.log('<==]message: ' + po(req.query,true));
if (msg == "") {
// do nothing
console.error(errCode[533]);
return res.status(533).send(errCode[533]+po(req.query,false));
}
// broadcast handler
if (msgObj.to == BROADCAST_KEY) {
console.log('==><== broadcast');
io.emit('chat message', msgObj);
return res.send(d.toString() + ':' + po(req.query,false));
}
// unicast handler
var r = unicastHandler(msgObj);
if (r > 500) {
res.status(r).send(errCode[r] + po(req.query,false));
} else {
res.send(d.toString() + ':' + po(req.query,false));
}
});
// Example (demo) client, sending multiple lines of speech to CSSS
app.get('/rap', function(req,res) {
res.sendFile(__dirname + '/public/htmls/rap.html');
});
// client can send http://localhost:3000/client?msg=안녕하세요
// from any http client, and it will send that msg to
// google chrome via socket.io
////////////////////////////////////////////////////////////////////////
// Helper Functions
////////////////////////////////////////////////////////////////////////
// print json to string to be printed
function po(obj,color) { return util.inspect(obj, { colors: color, depth: 2 } ); };
// msg obj builder
function buildMsg(msg,pitch,rate,volume,voice,to,from) {
return { msg: msg, pitch: pitch, rate: rate, volume: volume, voice: voice, to: to, from: from };
}
// generate random string with give length
function randomString(length) {
var result = '';
//var chars = '0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
var chars = '0123456789thankyouverymuch';
for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
return result;
}
////////////////////////////////////////////////////////////////////////
// Socket unicast handler
////////////////////////////////////////////////////////////////////////
function unicastHandler (msgObj) {
msgObj.to=msgObj.to.trim();
if (msgObj.to == undefined || msgObj.to == "") {
console.error(errCode[531]);
return 531;
}
if (socket_ids[msgObj.to] == undefined || socket_ids[msgObj.to] == "") {
console.error(errCode[532]);
return 532;
}
io.to(socket_ids[msgObj.to]).emit('chat message', msgObj);
return 200;
}
////////////////////////////////////////////////////////////////////////
// Socket.io Websocket Handler
//
// Note: Just for me to remember
// receive: *.on
// send: *.emit
// assume: A: sender, B: someone
// ~A: everyone except sender A
// ~B: everyone except B
// ALL: everyone including sender
//
// (associate with sender)
// 1. send(A): socket.emit();
// 2. send(~A): socket.broadcast.emit(); <--- I don't like this notation
// <-- io.NOT(A).emit. should be better notation
// (since following doesn't associate with sender)
// 3. send(B): io.to("B's socket.id").emit();
// 4. send(ALL): io.emit('msg type', msgObj);
//
// http://www.html5gamedevs.com/topic/9816-sending-a-specific-socketid-data-with-nodejssocketio/
////////////////////////////////////////////////////////////////////////
// standard socket.io chat messaging
io.on('connection', function(socket){
// when connect reqeust sent,
// first create humanly readable userid at server side first
var from = randomString(keyLength);
console.log('User '+socket.id+' connected, ' + from);
socket.emit('greetings',{id: from });
// bookkeeping socket.id with from
// to be used later at "send to anybody, B"
socket_ids[from] = socket.id;
socket.on('set id', function(msgObj) {
// ok. my client send request to keep the id,
// then, i need to bookkeep that
console.log("==>|set id to " + msgObj.localid
+ " from " + msgObj.serverid);
socket_ids[msgObj.localid]=socket.id
if (socket_ids[msgObj.serverid] == undefined) {
//nothing to delete
} else {
// delete my index
delete socket_ids[msgObj.serverid];
}
});
// main message handling
socket.on('chat message', function(msgObj){
console.log('==>]message: ' + po(msgObj));
// if requesting broadcast, make sure he knows secret key
if (msgObj.to == BROADCAST_KEY) {
console.log('==><== broadcast');
socket.broadcast.emit('chat message', msgObj);
} else {
// it's not broadcast. then better be unicast
unicastHandler(msgObj);
}
});
// disconnect
socket.on('disconnect', function() {
console.log("disconnect request!");
// delete entry at from my book
delete socket_ids[from];
});
});
////////////////////////////////////////////////////////////////////////
// web server main loop
////////////////////////////////////////////////////////////////////////
// Socket.io Websocket Handler
// listen to serverPort
// or if you want to use only locally by yourself,
// use following line instead,
// http.listen(3000, 'localhost', function(){
http.listen(servicePort, function(){
console.log('listening on *:' + servicePort);
});