websocket-server 1.0.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
};
|