websocket-server 1.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +185 -0
- data/Rakefile +56 -0
- data/exe/websocket +41 -0
- data/lib/log.rb +244 -0
- data/lib/server/mime_types.rb +38 -0
- data/lib/websocket/arguments_parser.rb +142 -0
- data/lib/websocket/channel_initializer.rb +73 -0
- data/lib/websocket/config.rb +59 -0
- data/lib/websocket/encoding.rb +21 -0
- data/lib/websocket/file_server_channel_progressive_future_listener.rb +32 -0
- data/lib/websocket/frame_handler.rb +71 -0
- data/lib/websocket/header_helpers.rb +70 -0
- data/lib/websocket/http_static_file_server_handler.rb +50 -0
- data/lib/websocket/http_static_file_server_handler_instance_methods.rb +160 -0
- data/lib/websocket/idle_handler.rb +41 -0
- data/lib/websocket/idle_state_user_event_handler.rb +47 -0
- data/lib/websocket/instance_methods.rb +127 -0
- data/lib/websocket/listenable.rb +41 -0
- data/lib/websocket/message_handler.rb +47 -0
- data/lib/websocket/response_helpers.rb +83 -0
- data/lib/websocket/server.rb +26 -0
- data/lib/websocket/shutdown_hook.rb +36 -0
- data/lib/websocket/ssl_cipher_inspector.rb +44 -0
- data/lib/websocket/ssl_context_initialization.rb +106 -0
- data/lib/websocket/telnet_proxy.rb +22 -0
- data/lib/websocket/validation_helpers.rb +51 -0
- data/lib/websocket/version.rb +16 -0
- data/lib/websocket-server.rb +13 -0
- data/lib/websocket_client.rb +478 -0
- data/lib/websocket_server.rb +50 -0
- data/web/client.html +43 -0
- data/web/css/client/console.css +167 -0
- data/web/css/client/parchment.css +112 -0
- data/web/favicon.ico +0 -0
- data/web/fonts/droidsansmono.v4.woff +0 -0
- data/web/js/client/ansispan.js +103 -0
- data/web/js/client/client.js +144 -0
- data/web/js/client/console.js +393 -0
- data/web/js/client/websocket.js +76 -0
- data/web/js/jquery.min.js +2 -0
- metadata +145 -0
@@ -0,0 +1,393 @@
|
|
1
|
+
|
2
|
+
var mobile = navigator.userAgent.match(/(iPhone|iPad|Android)/i);
|
3
|
+
var iphone = navigator.userAgent.match(/iPhone/i);
|
4
|
+
var old_doc = 0;
|
5
|
+
|
6
|
+
function input(el) {
|
7
|
+
_scroll();
|
8
|
+
if (client != null && !client.isConnected()) {
|
9
|
+
resetConnection();
|
10
|
+
el.value = '';
|
11
|
+
return false;
|
12
|
+
}
|
13
|
+
|
14
|
+
var record = true;
|
15
|
+
var message = '';
|
16
|
+
var label = $('label.' + el.id);
|
17
|
+
if (el.id == 'password') {
|
18
|
+
_write(label.html().toString() + el.value.replace(/./g, '•'));
|
19
|
+
record = false
|
20
|
+
message = el.value;
|
21
|
+
$(el).hide();
|
22
|
+
$(label).hide();
|
23
|
+
focus($('input#input'));
|
24
|
+
} else {
|
25
|
+
_write(label.html().toString() + el.value);
|
26
|
+
message = el.value.replace(/[\x00-\x1F\x7F-\x9F]/g, '');
|
27
|
+
}
|
28
|
+
|
29
|
+
el.value = '';
|
30
|
+
label.html('');
|
31
|
+
client.send(message, record);
|
32
|
+
return false;
|
33
|
+
}
|
34
|
+
|
35
|
+
function send_message(message, record) {
|
36
|
+
client.send(message, record);
|
37
|
+
}
|
38
|
+
|
39
|
+
function receive_message(message) {
|
40
|
+
message = message ? message : '';
|
41
|
+
var text = $.trim(message);
|
42
|
+
if (text.length == 0) return;
|
43
|
+
if (text.match(/The current time is now /)) game_started();
|
44
|
+
|
45
|
+
var lines = message.split(/\r?\n/);
|
46
|
+
var previous_prompt = ($('form.input label:visible').html() || '').toString();
|
47
|
+
if (previous_prompt.length > 0) lines.unshift(previous_prompt);
|
48
|
+
var prompt = previous_prompt.replace(/ /, ' ');
|
49
|
+
var new_prompt = (lines.pop() || '').toString();
|
50
|
+
if (prompt.length == 0) prompt = new_prompt;
|
51
|
+
message = lines.join("\n");
|
52
|
+
|
53
|
+
if (prompt.match(/password\:\s?$/)) {
|
54
|
+
hide_input_field();
|
55
|
+
show_password_field();
|
56
|
+
} else if (!$('input#input').is(':visible')) {
|
57
|
+
hide_password_field();
|
58
|
+
show_input_field();
|
59
|
+
} else {
|
60
|
+
show_input_field();
|
61
|
+
}
|
62
|
+
|
63
|
+
if (!(typeof showdown === 'undefined') && message.match(/---\npath: .*\.md/m)) {
|
64
|
+
message = handle_markdown(message);
|
65
|
+
} else {
|
66
|
+
message = message.replace(/\>/g, '___:').replace(/\</g, ':___');
|
67
|
+
message = ansispan(message);
|
68
|
+
message = message.replace(/^[\x00-\x0B][\x0C][\x0E-\x1F]/g, '');
|
69
|
+
message = message.replace(/ /g, " ");
|
70
|
+
message = message.replace(/ $/g, " ");
|
71
|
+
message = message.replace(/^[\n\x0D]+/, "\n");
|
72
|
+
log(message.replace(/^[\x00-\x1F]+/, ''));
|
73
|
+
message = message.replace(/[\x00-\x0B][\x0C][\x0E-\x1F]/g, '');
|
74
|
+
message = message.replace(/\>/g, '>').replace(/\</g, '<');
|
75
|
+
message = buffer.html(message).text();
|
76
|
+
message = message.replace(/___:/g, '>').replace(/:___/g, '<');
|
77
|
+
message = hyperlinkdirections(message);
|
78
|
+
message = hyperlinkurls(message);
|
79
|
+
}
|
80
|
+
if (message.length > 0) println(message);
|
81
|
+
print(prompt);
|
82
|
+
}
|
83
|
+
|
84
|
+
function show_input_field() {
|
85
|
+
var input = $('input#input');
|
86
|
+
var input_label = $('label.input');
|
87
|
+
input.css('visibility', 'visible');
|
88
|
+
input.show();
|
89
|
+
input.removeClass('hidden');
|
90
|
+
input_label.css('visibility', 'visible');
|
91
|
+
input_label.show();
|
92
|
+
input_label.removeClass('hidden');
|
93
|
+
focus(input);
|
94
|
+
}
|
95
|
+
|
96
|
+
function hide_input_field() {
|
97
|
+
var input = $('input#input');
|
98
|
+
var input_label = $('label.input');
|
99
|
+
input.css('visibility', 'hidden');
|
100
|
+
input.hide();
|
101
|
+
input.addClass('hidden');
|
102
|
+
input_label.css('visibility', 'hidden');
|
103
|
+
input_label.hide();
|
104
|
+
input_label.addClass('hidden');
|
105
|
+
}
|
106
|
+
|
107
|
+
function show_password_field() {
|
108
|
+
var password = $('input#password');
|
109
|
+
var password_label = $('label.password');
|
110
|
+
password.css('visibility', 'visible');
|
111
|
+
password.show();
|
112
|
+
password.removeClass('hidden');
|
113
|
+
password_label.css('visibility', 'visible');
|
114
|
+
password_label.show();
|
115
|
+
password_label.removeClass('hidden');
|
116
|
+
focus(password);
|
117
|
+
}
|
118
|
+
|
119
|
+
function hide_password_field() {
|
120
|
+
var password = $('input#password');
|
121
|
+
var password_label = $('label.password');
|
122
|
+
password.css('visibility', 'hidden');
|
123
|
+
password.hide();
|
124
|
+
password.addClass('hidden');
|
125
|
+
password_label.css('visibility', 'hidden');
|
126
|
+
password_label.addClass('hidden');
|
127
|
+
password_label.hide();
|
128
|
+
}
|
129
|
+
|
130
|
+
function handle_markdown(s) {
|
131
|
+
s = s.replace(/---\n.*\n---\n/m, '');
|
132
|
+
var prompt = s.split(/\r?\n/).pop();
|
133
|
+
s = s.substring(0, s.lastIndexOf(prompt));
|
134
|
+
s = new showdown.Converter().makeHtml(s);
|
135
|
+
return "<div class=\"markdown\">\n" + s + "</div>\n" + prompt;
|
136
|
+
}
|
137
|
+
|
138
|
+
function previous_command(el) {
|
139
|
+
if (client.index > 0) {
|
140
|
+
if (client.index == client.history.length - 1) {
|
141
|
+
client.history.push(el.value);
|
142
|
+
client.index++;
|
143
|
+
}
|
144
|
+
client.index--;
|
145
|
+
el.value = client.history[client.index];
|
146
|
+
}
|
147
|
+
select_input(el);
|
148
|
+
}
|
149
|
+
|
150
|
+
function next_command(el) {
|
151
|
+
if (client.index < (client.history.length - 1)) {
|
152
|
+
client.index++;
|
153
|
+
el.value = client.history[client.index];
|
154
|
+
if (client.index == client.history.length - 1) {
|
155
|
+
client.history.pop();
|
156
|
+
client.index--;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
select_input(el);
|
160
|
+
}
|
161
|
+
|
162
|
+
var buffer = $("<div/>");
|
163
|
+
|
164
|
+
function _write(message, display) {
|
165
|
+
message = message.replace(/\>/g, '>').replace(/\</g, '<');
|
166
|
+
println(message, display);
|
167
|
+
}
|
168
|
+
|
169
|
+
function print(message, display) {
|
170
|
+
message = message ? message : '';
|
171
|
+
display = display ? display : $('div.display');
|
172
|
+
var input = display.find('div.input');
|
173
|
+
var form = display.find('form.input');
|
174
|
+
var type = message.match(/^.*password:\s?/) ? 'password' : 'input';
|
175
|
+
var label = form.find('label.' + type);
|
176
|
+
label.html(message.replace(/\s$/, " "));
|
177
|
+
// Impose a limit of elements displayed as output history in
|
178
|
+
// order to restrain lag
|
179
|
+
while (display.children().length > 200) {
|
180
|
+
var div = document.getElementsByClassName('display')[0]
|
181
|
+
div.removeChild(div.firstChild);
|
182
|
+
}
|
183
|
+
_scroll();
|
184
|
+
}
|
185
|
+
|
186
|
+
function println(message) {
|
187
|
+
message = message ? message : '';
|
188
|
+
var display = $('div.display');
|
189
|
+
var fragment = document.createDocumentFragment();
|
190
|
+
var span = document.createElement('span');
|
191
|
+
var br = document.createElement('br');
|
192
|
+
span.setAttribute('class', 'user');
|
193
|
+
span.innerHTML = message;
|
194
|
+
fragment.appendChild(span);
|
195
|
+
fragment.appendChild(br);
|
196
|
+
var input = display.find('div.input');
|
197
|
+
input.before(fragment.cloneNode(true));
|
198
|
+
// Impose a limit of elements displayed as output history in
|
199
|
+
// order to restrain lag
|
200
|
+
while (display.children().length > 200) {
|
201
|
+
var div = document.getElementsByClassName('display')[0]
|
202
|
+
div.removeChild(div.firstChild);
|
203
|
+
}
|
204
|
+
_scroll();
|
205
|
+
}
|
206
|
+
|
207
|
+
function _scroll() {
|
208
|
+
$('html').scrollTop(1E10);
|
209
|
+
var display = $('div.display');
|
210
|
+
display.scrollTop = display.scrollHeight;
|
211
|
+
}
|
212
|
+
|
213
|
+
function log(message) {
|
214
|
+
if (window.location.hostname == 'localhost') {
|
215
|
+
console.log(message);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
function reset(display) {
|
220
|
+
display = display ? display : $('div.display');
|
221
|
+
var input = display.find('div.input');
|
222
|
+
$('div.line').html(input);
|
223
|
+
display.find('input#input, input#password').val('');
|
224
|
+
}
|
225
|
+
|
226
|
+
function clear(display) {
|
227
|
+
display = display ? display : $('div.display');
|
228
|
+
var input = display.find('input#input');
|
229
|
+
var password = display.find('input#password');
|
230
|
+
var line = display.find('div.line');
|
231
|
+
display.html(display.find('div.input'));
|
232
|
+
display.find('input#input').val(input.val());
|
233
|
+
display.find('input#password').val(password.val());
|
234
|
+
display.find('input#input, input#password').keydown(input_keydown);
|
235
|
+
}
|
236
|
+
|
237
|
+
function focus(field) {
|
238
|
+
field = field ? field : $('input#input');
|
239
|
+
field.focus();
|
240
|
+
field.select();
|
241
|
+
select_input(field);
|
242
|
+
// if (iphone) $('div.display').click();
|
243
|
+
}
|
244
|
+
|
245
|
+
/*
|
246
|
+
function getSelectionText() {
|
247
|
+
var text = '';
|
248
|
+
if (window.getSelection) {
|
249
|
+
text = window.getSelection().toString();
|
250
|
+
} else if (document.selection && document.selection.type != "Control") {
|
251
|
+
text = document.selection.createRange().text;
|
252
|
+
}
|
253
|
+
return text;
|
254
|
+
}
|
255
|
+
*/
|
256
|
+
|
257
|
+
function text_selection() {
|
258
|
+
var text = '';
|
259
|
+
if (typeof window.getSelection != 'undefined') {
|
260
|
+
text = window.getSelection().toString();
|
261
|
+
} else if (typeof document.selection != 'undefined' && document.selection.type == 'Text') {
|
262
|
+
text = document.selection.createRange().text;
|
263
|
+
}
|
264
|
+
return text;
|
265
|
+
}
|
266
|
+
|
267
|
+
function text_selected() {
|
268
|
+
var selected = false;
|
269
|
+
if (typeof window.getSelection != 'undefined') {
|
270
|
+
selected = !(window.getSelection().isCollapsed);
|
271
|
+
} else if (typeof document.getSelection != 'undefined') {
|
272
|
+
selected = !(window.getSelection().isCollapsed);
|
273
|
+
} else if (typeof document.selection != 'undefined' && document.selection.type == 'Text') {
|
274
|
+
// selected = (document.selection.createRange().text.length > 0);
|
275
|
+
selected = (document.selection.createRange().boundingWidth > 0);
|
276
|
+
}
|
277
|
+
return selected;
|
278
|
+
}
|
279
|
+
|
280
|
+
function select_input(e) {
|
281
|
+
var el = e && e.target ? e.target : e;
|
282
|
+
if (text_selected()) {
|
283
|
+
return;
|
284
|
+
}
|
285
|
+
var input = $('input#input');
|
286
|
+
var password = $('input#password');
|
287
|
+
var field = null;
|
288
|
+
if (input.is(':visible')) {
|
289
|
+
field = input;
|
290
|
+
} else if (password.is(':visible')) {
|
291
|
+
field = password;
|
292
|
+
}
|
293
|
+
if (!field) {
|
294
|
+
return;
|
295
|
+
}
|
296
|
+
field.focus();
|
297
|
+
var l = field.value ? field.value.length : 0;
|
298
|
+
if (field.createTextRange) {
|
299
|
+
var textRange = field.createTextRange();
|
300
|
+
textRange.collapse(true);
|
301
|
+
textRange.moveEnd(l);
|
302
|
+
textRange.moveStart(l);
|
303
|
+
textRange.select();
|
304
|
+
} else if (field.setSelectionRange) {
|
305
|
+
field.setSelectionRange(l, l);
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
var directions = [
|
310
|
+
'north', 'south', 'east', 'west',
|
311
|
+
'northeast', 'southeast', 'northwest', 'southwest',
|
312
|
+
'up', 'down'
|
313
|
+
].join('|');
|
314
|
+
var compass_direction = new RegExp("\>(" + directions + ")\<\/span\>", 'g');
|
315
|
+
var direction_link = "><a class=\"direction\">$1</a></span>";
|
316
|
+
var hyperlinkdirections = function(str) {
|
317
|
+
return str.replace(compass_direction, direction_link);
|
318
|
+
};
|
319
|
+
var go = function(e) {
|
320
|
+
var prompt_label = $('form.input label:visible');
|
321
|
+
if (prompt_label.hasClass('password')) return;
|
322
|
+
var current_prompt = prompt_label.html().toString();
|
323
|
+
if (current_prompt.match(/[:\?]( |\s)?$/)) return;
|
324
|
+
var el = e ? $(e.target) : $(this);
|
325
|
+
var dir = el.text();
|
326
|
+
var field = $('form.input input:visible');
|
327
|
+
field.val(dir);
|
328
|
+
input(field.get(0));
|
329
|
+
};
|
330
|
+
var hyperlinkurls = function(str) {
|
331
|
+
return str.linkify();
|
332
|
+
};
|
333
|
+
if(!String.linkify) {
|
334
|
+
String.prototype.linkify = function() {
|
335
|
+
|
336
|
+
// http://, https://, ftp://
|
337
|
+
var urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;
|
338
|
+
|
339
|
+
// www. sans http:// or https://
|
340
|
+
var pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
341
|
+
|
342
|
+
// Email addresses
|
343
|
+
var emailAddressPattern = /[\w.]+@[a-zA-Z_-]+?(?:\.[a-zA-Z]{2,6})+/gim;
|
344
|
+
|
345
|
+
return this
|
346
|
+
.replace(urlPattern, '<a class="display" href="$&">$&</a>')
|
347
|
+
.replace(pseudoUrlPattern, '$1<a class="display" href="http://$2">$2</a>')
|
348
|
+
.replace(emailAddressPattern, '<a class="display" href="mailto:$&">$&</a>');
|
349
|
+
};
|
350
|
+
}
|
351
|
+
|
352
|
+
function createCookie(name,value,days) {
|
353
|
+
if (days) {
|
354
|
+
var date = new Date();
|
355
|
+
date.setTime(date.getTime() + (days*24*60*60*1000));
|
356
|
+
var expires = "; expires=" + date.toGMTString();
|
357
|
+
}
|
358
|
+
else var expires = "";
|
359
|
+
document.cookie = name+"="+value+expires+"; path=/";
|
360
|
+
}
|
361
|
+
|
362
|
+
function readCookie(name, default_value) {
|
363
|
+
var ca = document.cookie.split(';');
|
364
|
+
for (var i=0; i < ca.length; i++) {
|
365
|
+
var c = ca[i];
|
366
|
+
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
367
|
+
if (c.indexOf(name + '=') == 0) return c.substring(name.length + 1, c.length);
|
368
|
+
}
|
369
|
+
if (default_value == undefined) return null;
|
370
|
+
return default_value;
|
371
|
+
}
|
372
|
+
|
373
|
+
function eraseCookie(name) {
|
374
|
+
createCookie(name,"",-1);
|
375
|
+
}
|
376
|
+
|
377
|
+
Array.prototype.shuffle = function() {
|
378
|
+
var i = this.length, j, tempi, tempj;
|
379
|
+
if ( i == 0 ) return false;
|
380
|
+
while ( --i ) {
|
381
|
+
j = Math.floor( Math.random() * ( i + 1 ) );
|
382
|
+
tempi = this[i];
|
383
|
+
tempj = this[j];
|
384
|
+
this[i] = tempj;
|
385
|
+
this[j] = tempi;
|
386
|
+
}
|
387
|
+
return this;
|
388
|
+
}
|
389
|
+
|
390
|
+
function game_started() {
|
391
|
+
console.log("Event: Game started");
|
392
|
+
return;
|
393
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
Client = function(host, port) {
|
3
|
+
protocol = (window.location.protocol == 'https:') ? 'wss:' : 'ws:';
|
4
|
+
host = host ? host : window.location.hostname;
|
5
|
+
port = port ? port : (protocol == 'wss:' ? 443 : 4000);
|
6
|
+
this.ws_uri = protocol + '//' + host + ':' + port + '/websocket';
|
7
|
+
this.client = this;
|
8
|
+
if (window.WebSocket) {
|
9
|
+
this.WebSocket = window.WebSocket;
|
10
|
+
} else if ('WebSocket' in window) {
|
11
|
+
this.WebSocket = window.WebSocket;
|
12
|
+
} else if (window.MozWebSocket) {
|
13
|
+
this.WebSocket = window.MozWebSocket;
|
14
|
+
} else if ('MozWebSocket' in window) {
|
15
|
+
this.WebSocket = window.MozWebSocket;
|
16
|
+
} else {
|
17
|
+
this.WebSocket = window.MozWebSocket;
|
18
|
+
}
|
19
|
+
};
|
20
|
+
|
21
|
+
Client.prototype.ws_uri = 'ws://localhost:4000/websocket';
|
22
|
+
Client.prototype.socket = null;
|
23
|
+
Client.prototype.WebSocket = null;
|
24
|
+
Client.prototype.history = new Array();
|
25
|
+
Client.prototype.index = 0;
|
26
|
+
|
27
|
+
Client.prototype.open = function(ws_uri) {
|
28
|
+
this.ws_uri = ws_uri ? ws_uri : this.ws_uri;
|
29
|
+
this.socket = new this.WebSocket(this.ws_uri);
|
30
|
+
this.socket.onopen = function(event) { console.log('WebSocket open!'); };
|
31
|
+
this.socket.onclose = function(event) { console.log('WebSocket closed.'); };
|
32
|
+
this.socket.onmessage = function(event) { console.log(event.data); };
|
33
|
+
this
|
34
|
+
};
|
35
|
+
|
36
|
+
Client.prototype.check = function() {
|
37
|
+
console.log('Checking for WebSockets...');
|
38
|
+
if (this.WebSocket) {
|
39
|
+
console.log('Your browser supports WebSockets.');
|
40
|
+
} else {
|
41
|
+
console.log('Your browser does not support WebSockets yet.');
|
42
|
+
}
|
43
|
+
|
44
|
+
if (this.socket && this.socket.readyState == this.WebSocket.OPEN) {
|
45
|
+
console.log('The WebSocket handshake with the server was successful.')
|
46
|
+
} else {
|
47
|
+
console.log('The WebSocket is not ready.')
|
48
|
+
}
|
49
|
+
|
50
|
+
return (this.socket != null && this.socket.readyState == this.WebSocket.OPEN);
|
51
|
+
};
|
52
|
+
|
53
|
+
Client.prototype.isConnected = function() {
|
54
|
+
return (this.WebSocket && this.socket && this.socket.readyState == this.WebSocket.OPEN)
|
55
|
+
};
|
56
|
+
|
57
|
+
Client.prototype.close = function() {
|
58
|
+
this.socket.close();
|
59
|
+
};
|
60
|
+
|
61
|
+
Client.prototype.send = function(message, record) {
|
62
|
+
if (record != false) {
|
63
|
+
if (this.index < this.history.length - 1) {
|
64
|
+
this.history.splice(this.history.length - 1, 1);
|
65
|
+
this.index = this.history.length - 1;
|
66
|
+
}
|
67
|
+
this.history.push(message);
|
68
|
+
this.index = this.history.length - 1;
|
69
|
+
}
|
70
|
+
if (!this.WebSocket || !this.socket) { this.open(); }
|
71
|
+
if (this.socket.readyState == this.WebSocket.OPEN) {
|
72
|
+
this.socket.send(message);
|
73
|
+
} else {
|
74
|
+
console.log('The WebSocket is not ready yet!');
|
75
|
+
}
|
76
|
+
};
|