fluent-plugin-websocket 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bed9989f3203afca2a0ecac1ecd6d0155aa6b061
4
+ data.tar.gz: 9fe57af129239dd41520445f6f3d5b0e5f90b71b
5
+ SHA512:
6
+ metadata.gz: 49300703aa75c86e1a571a5e1bc527bacf735916e8d3c85718e0f400756b920071657528263152248a2b678b546e9c1cd260f062ef2bda49afbbd09cbf49f687
7
+ data.tar.gz: 1446c1902d16db79f4c499c0d68afb5c9e86b0ad418d87073c0acc302652a51c16287cbe29bfe506547c28bbe3fd1c275f629c012c196c8a93701dfbdcfb16a8
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 IZAWA Tetsu (@moccos)
1
+ Copyright (c) 2013 Tetsu Izawa (@moccos)
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
data/README.rdoc CHANGED
@@ -1,4 +1,5 @@
1
- = Fluent::Plugin::Websocket
1
+ = fluent-plugin-websocket
2
+ {https://badge.fury.io/rb/fluent-plugin-websocket.svg}[https://badge.fury.io/rb/fluent-plugin-websocket]
2
3
 
3
4
  Fluentd websocket output plugin.
4
5
 
@@ -10,16 +11,16 @@ In the current version, emitted data will be broadcasted to the all connected cl
10
11
 
11
12
  gem install fluent-plugin-websocket
12
13
 
13
- This plugin depends on {*em-websocket*}[https://github.com/igrigorik/em-websocket].
14
-
15
14
  == Configuration
16
15
  <match foo.**>
17
16
  type websocket
18
- host 192.168.1.1 # default: 0.0.0.0 (ANY)
19
- port 8080 # default: 8080
20
- use_msgpack false # default: false
21
- add_time false # default: false
22
- add_tag true # default: true
17
+ host 192.168.1.1 # default: 0.0.0.0 (ANY)
18
+ port 8080 # default: 8080
19
+ use_msgpack false # default: false
20
+ add_time false # default: false
21
+ add_tag true # default: true
22
+ buffered_messages 100 # default: 0
23
+ token SomeToken # default: nil
23
24
  </match>
24
25
 
25
26
  * *host*: WebSocket server IP address.
@@ -27,6 +28,8 @@ This plugin depends on {*em-websocket*}[https://github.com/igrigorik/em-websocke
27
28
  * <b>use_msgpack</b>: Send {MessagePack}[http://msgpack.org/] format binary. Otherwise, you send JSON format text.
28
29
  * <b>add_time</b>: Add timestamp to the data.
29
30
  * <b>add_tag</b>: Add fluentd tag to the data.
31
+ * <b>buffered_messages</b>: The number of messages to be buffered. The new connection receives them.
32
+ * <b>token</b>: Authentication token. Passed as get param. If set to nil, authentication is disabled.
30
33
 
31
34
  If there are no websocket connections, this plugin silently discards data. You may use <em>out_copy</em> plugin like this:
32
35
 
@@ -42,8 +45,10 @@ If there are no websocket connections, this plugin silently discards data. You m
42
45
  </store>
43
46
  </match>
44
47
 
48
+ If <em>buffered_messages</em> is greater than <em>0</em>, the last stored data is sent to the client upon new connection.
49
+
45
50
  == Data format
46
- [tag, timestamp, data\_object]
51
+ [tag, timestamp, data_object]
47
52
 
48
53
  * tag is appended when <em>add_tag</em> option is true.
49
54
  * timestamp is appended when <em>add_time</em> option is true.
@@ -70,22 +75,33 @@ Extract data by {msgpack.js}[https://github.com/msgpack/msgpack-javascript].
70
75
  ...
71
76
  }
72
77
 
73
- == Contributing
74
-
75
- 1. Fork it
76
- 2. Create your feature branch (`git checkout -b my-new-feature`)
77
- 3. Commit your changes (`git commit -am 'Add some feature'`)
78
- 4. Push to the branch (`git push origin my-new-feature`)
79
- 5. Create new Pull Request
80
-
81
- == Recent changes
82
- * 0.1.6 Added lisence to gemspec.
83
- * 0.1.5 Fixed dependencies. (Thanks to {ca-gacky}[https://github.com/ca-gacky])
84
- * 0.1.4 Changed json parser to yajl. (Thanks to {Kogarasi}[https://github.com/Kogarasi])
78
+ === Authentication and filtering
79
+
80
+ curl --include \
81
+ --no-buffer \
82
+ --header "Connection: Upgrade" \
83
+ --header "Upgrade: websocket" \
84
+ --header "Host: 127.0.0.1:8080" \
85
+ --header "Origin: http://127.0.0.1:8080" \
86
+ --header "Sec-WebSocket-Key: SGVabG8sIHOvcmxDIQ==" \
87
+ --header "Sec-WebSocket-Version: 13" \
88
+ "http://127.0.0.1:8888/?foo=bar&token=MyT0ken"
89
+
90
+ * If token setting in config file is not nil, websocket server checks _token_ parameter
91
+ * Client will receive data which include \{"foo": "bar"\}
92
+
93
+ == Changelogs
94
+ * 0.1.8 Add authentication and filtering
95
+ * 0.1.7 Add message buffering.
96
+ * 0.1.6 Added license to gemspec.
97
+ * 0.1.5 Fixed dependencies.
98
+ * 0.1.4 Changed json parser to yajl.
85
99
  * 0.1.3 Bug fix.
86
100
  * 0.1.2 Released gem.
87
101
 
102
+ See commit logs about contributors.
103
+
88
104
  == Copyright
89
105
 
90
- Copyright:: Copyright (c) 2013 IZAWA Tetsu (@moccos)
106
+ Copyright:: Copyright (c) 2013 Tetsu Izawa (@moccos)
91
107
  License:: Apache License, Version 2.0
@@ -0,0 +1,646 @@
1
+ /* jshint browser: true */
2
+ /* global define, module */
3
+ ( // Module boilerplate to support browser globals and browserify and AMD.
4
+ typeof define === "function" ? function (m) { define("msgpack-js", m); } :
5
+ typeof exports === "object" ? function (m) { module.exports = m(); } :
6
+ function(m){ this.msgpack = m(); }
7
+ )(function () {
8
+ "use strict";
9
+
10
+ var exports = {};
11
+
12
+ exports.inspect = inspect;
13
+ function inspect(buffer) {
14
+ if (buffer === undefined) return "undefined";
15
+ var view;
16
+ var type;
17
+ if (buffer instanceof ArrayBuffer) {
18
+ type = "ArrayBuffer";
19
+ view = new DataView(buffer);
20
+ }
21
+ else if (buffer instanceof DataView) {
22
+ type = "DataView";
23
+ view = buffer;
24
+ }
25
+ if (!view) return JSON.stringify(buffer);
26
+ var bytes = [];
27
+ for (var i = 0; i < buffer.byteLength; i++) {
28
+ if (i > 20) {
29
+ bytes.push("...");
30
+ break;
31
+ }
32
+ var byte = view.getUint8(i).toString(16);
33
+ if (byte.length === 1) byte = "0" + byte;
34
+ bytes.push(byte);
35
+ }
36
+ return "<" + type + " " + bytes.join(" ") + ">";
37
+ }
38
+
39
+ // Encode string as utf8 into dataview at offset
40
+ exports.utf8Write = utf8Write;
41
+ function utf8Write(view, offset, string) {
42
+ var byteLength = view.byteLength;
43
+ for(var i = 0, l = string.length; i < l; i++) {
44
+ var codePoint = string.charCodeAt(i);
45
+
46
+ // One byte of UTF-8
47
+ if (codePoint < 0x80) {
48
+ view.setUint8(offset++, codePoint >>> 0 & 0x7f | 0x00);
49
+ continue;
50
+ }
51
+
52
+ // Two bytes of UTF-8
53
+ if (codePoint < 0x800) {
54
+ view.setUint8(offset++, codePoint >>> 6 & 0x1f | 0xc0);
55
+ view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
56
+ continue;
57
+ }
58
+
59
+ // Three bytes of UTF-8.
60
+ if (codePoint < 0x10000) {
61
+ view.setUint8(offset++, codePoint >>> 12 & 0x0f | 0xe0);
62
+ view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80);
63
+ view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
64
+ continue;
65
+ }
66
+
67
+ // Four bytes of UTF-8
68
+ if (codePoint < 0x110000) {
69
+ view.setUint8(offset++, codePoint >>> 18 & 0x07 | 0xf0);
70
+ view.setUint8(offset++, codePoint >>> 12 & 0x3f | 0x80);
71
+ view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80);
72
+ view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80);
73
+ continue;
74
+ }
75
+ throw new Error("bad codepoint " + codePoint);
76
+ }
77
+ }
78
+
79
+ exports.utf8Read = utf8Read;
80
+ function utf8Read(view, offset, length) {
81
+ var string = "";
82
+ for (var i = offset, end = offset + length; i < end; i++) {
83
+ var byte = view.getUint8(i);
84
+ // One byte character
85
+ if ((byte & 0x80) === 0x00) {
86
+ string += String.fromCharCode(byte);
87
+ continue;
88
+ }
89
+ // Two byte character
90
+ if ((byte & 0xe0) === 0xc0) {
91
+ string += String.fromCharCode(
92
+ ((byte & 0x1f) << 6) |
93
+ (view.getUint8(++i) & 0x3f)
94
+ );
95
+ continue;
96
+ }
97
+ // Three byte character
98
+ if ((byte & 0xf0) === 0xe0) {
99
+ string += String.fromCharCode(
100
+ ((byte & 0x0f) << 12) |
101
+ ((view.getUint8(++i) & 0x3f) << 6) |
102
+ ((view.getUint8(++i) & 0x3f) << 0)
103
+ );
104
+ continue;
105
+ }
106
+ // Four byte character
107
+ if ((byte & 0xf8) === 0xf0) {
108
+ string += String.fromCharCode(
109
+ ((byte & 0x07) << 18) |
110
+ ((view.getUint8(++i) & 0x3f) << 12) |
111
+ ((view.getUint8(++i) & 0x3f) << 6) |
112
+ ((view.getUint8(++i) & 0x3f) << 0)
113
+ );
114
+ continue;
115
+ }
116
+ throw new Error("Invalid byte " + byte.toString(16));
117
+ }
118
+ return string;
119
+ }
120
+
121
+ exports.utf8ByteCount = utf8ByteCount;
122
+ function utf8ByteCount(string) {
123
+ var count = 0;
124
+ for(var i = 0, l = string.length; i < l; i++) {
125
+ var codePoint = string.charCodeAt(i);
126
+ if (codePoint < 0x80) {
127
+ count += 1;
128
+ continue;
129
+ }
130
+ if (codePoint < 0x800) {
131
+ count += 2;
132
+ continue;
133
+ }
134
+ if (codePoint < 0x10000) {
135
+ count += 3;
136
+ continue;
137
+ }
138
+ if (codePoint < 0x110000) {
139
+ count += 4;
140
+ continue;
141
+ }
142
+ throw new Error("bad codepoint " + codePoint);
143
+ }
144
+ return count;
145
+ }
146
+
147
+ exports.encode = function (value) {
148
+ var buffer = new ArrayBuffer(encodedSize(value));
149
+ var view = new DataView(buffer);
150
+ encode(value, view, 0);
151
+ return buffer;
152
+ };
153
+
154
+ exports.decode = decode;
155
+
156
+ // https://github.com/msgpack/msgpack/blob/master/spec.md
157
+ // we reserve extension type 0x00 to encode javascript 'undefined'
158
+
159
+ function Decoder(view, offset) {
160
+ this.offset = offset || 0;
161
+ this.view = view;
162
+ }
163
+ Decoder.prototype.map = function (length) {
164
+ var value = {};
165
+ for (var i = 0; i < length; i++) {
166
+ var key = this.parse();
167
+ value[key] = this.parse();
168
+ }
169
+ return value;
170
+ };
171
+ Decoder.prototype.bin = function (length) {
172
+ var value = new ArrayBuffer(length);
173
+ (new Uint8Array(value)).set(new Uint8Array(this.view.buffer, this.offset, length), 0);
174
+ this.offset += length;
175
+ return value;
176
+ };
177
+ Decoder.prototype.str = function (length) {
178
+ var value = utf8Read(this.view, this.offset, length);
179
+ this.offset += length;
180
+ return value;
181
+ };
182
+ Decoder.prototype.array = function (length) {
183
+ var value = new Array(length);
184
+ for (var i = 0; i < length; i++) {
185
+ value[i] = this.parse();
186
+ }
187
+ return value;
188
+ };
189
+ Decoder.prototype.parse = function () {
190
+ var type = this.view.getUint8(this.offset);
191
+ var value, length;
192
+ // FixStr
193
+ if ((type & 0xe0) === 0xa0) {
194
+ length = type & 0x1f;
195
+ this.offset++;
196
+ return this.str(length);
197
+ }
198
+ // FixMap
199
+ if ((type & 0xf0) === 0x80) {
200
+ length = type & 0x0f;
201
+ this.offset++;
202
+ return this.map(length);
203
+ }
204
+ // FixArray
205
+ if ((type & 0xf0) === 0x90) {
206
+ length = type & 0x0f;
207
+ this.offset++;
208
+ return this.array(length);
209
+ }
210
+ // Positive FixNum
211
+ if ((type & 0x80) === 0x00) {
212
+ this.offset++;
213
+ return type;
214
+ }
215
+ // Negative Fixnum
216
+ if ((type & 0xe0) === 0xe0) {
217
+ value = this.view.getInt8(this.offset);
218
+ this.offset++;
219
+ return value;
220
+ }
221
+ // Undefined as FixExt1
222
+ if (type === 0xd4 && this.view.getUint8(this.offset + 1) === 0x00) {
223
+ this.offset += 3;
224
+ return undefined;
225
+ }
226
+ switch (type) {
227
+ // str 8
228
+ case 0xd9:
229
+ length = this.view.getUint8(this.offset + 1);
230
+ this.offset += 2;
231
+ return this.str(length);
232
+ // str 16
233
+ case 0xda:
234
+ length = this.view.getUint16(this.offset + 1);
235
+ this.offset += 3;
236
+ return this.str(length);
237
+ // str 32
238
+ case 0xdb:
239
+ length = this.view.getUint32(this.offset + 1);
240
+ this.offset += 5;
241
+ return this.str(length);
242
+ // bin 8
243
+ case 0xc4:
244
+ length = this.view.getUint8(this.offset + 1);
245
+ this.offset += 2;
246
+ return this.bin(length);
247
+ // bin 16
248
+ case 0xc5:
249
+ length = this.view.getUint16(this.offset + 1);
250
+ this.offset += 3;
251
+ return this.bin(length);
252
+ // bin 32
253
+ case 0xc6:
254
+ length = this.view.getUint32(this.offset + 1);
255
+ this.offset += 5;
256
+ return this.bin(length);
257
+ // nil
258
+ case 0xc0:
259
+ this.offset++;
260
+ return null;
261
+ // false
262
+ case 0xc2:
263
+ this.offset++;
264
+ return false;
265
+ // true
266
+ case 0xc3:
267
+ this.offset++;
268
+ return true;
269
+ // uint8
270
+ case 0xcc:
271
+ value = this.view.getUint8(this.offset + 1);
272
+ this.offset += 2;
273
+ return value;
274
+ // uint 16
275
+ case 0xcd:
276
+ value = this.view.getUint16(this.offset + 1);
277
+ this.offset += 3;
278
+ return value;
279
+ // uint 32
280
+ case 0xce:
281
+ value = this.view.getUint32(this.offset + 1);
282
+ this.offset += 5;
283
+ return value;
284
+ // uint 64
285
+ case 0xcf:
286
+ var high = this.view.getUint32(this.offset + 1);
287
+ var low = this.view.getUint32(this.offset + 5);
288
+ value = high*0x100000000 + low;
289
+ this.offset += 9;
290
+ return value;
291
+ // int 8
292
+ case 0xd0:
293
+ value = this.view.getInt8(this.offset + 1);
294
+ this.offset += 2;
295
+ return value;
296
+ // int 16
297
+ case 0xd1:
298
+ value = this.view.getInt16(this.offset + 1);
299
+ this.offset += 3;
300
+ return value;
301
+ // int 32
302
+ case 0xd2:
303
+ value = this.view.getInt32(this.offset + 1);
304
+ this.offset += 5;
305
+ return value;
306
+ // int 64
307
+ case 0xd3:
308
+ var high = this.view.getInt32(this.offset + 1);
309
+ var low = this.view.getUint32(this.offset + 5);
310
+ value = high*0x100000000 + low;
311
+ this.offset += 9;
312
+ return value;
313
+ // map 16
314
+ case 0xde:
315
+ length = this.view.getUint16(this.offset + 1);
316
+ this.offset += 3;
317
+ return this.map(length);
318
+ // map 32
319
+ case 0xdf:
320
+ length = this.view.getUint32(this.offset + 1);
321
+ this.offset += 5;
322
+ return this.map(length);
323
+ // array 16
324
+ case 0xdc:
325
+ length = this.view.getUint16(this.offset + 1);
326
+ this.offset += 3;
327
+ return this.array(length);
328
+ // array 32
329
+ case 0xdd:
330
+ length = this.view.getUint32(this.offset + 1);
331
+ this.offset += 5;
332
+ return this.array(length);
333
+ // float
334
+ case 0xca:
335
+ value = this.view.getFloat32(this.offset + 1);
336
+ this.offset += 5;
337
+ return value;
338
+ // double
339
+ case 0xcb:
340
+ value = this.view.getFloat64(this.offset + 1);
341
+ this.offset += 9;
342
+ return value;
343
+ }
344
+ throw new Error("Unknown type 0x" + type.toString(16));
345
+ };
346
+ function decode(buffer) {
347
+ var view = new DataView(buffer);
348
+ var decoder = new Decoder(view);
349
+ var value = decoder.parse();
350
+ if (decoder.offset !== buffer.byteLength) throw new Error((buffer.byteLength - decoder.offset) + " trailing bytes");
351
+ return value;
352
+ }
353
+
354
+ function encode(value, view, offset) {
355
+ var type = typeof value;
356
+
357
+ // Strings Bytes
358
+ if (type === "string") {
359
+ var length = utf8ByteCount(value);
360
+ // fix str
361
+ if (length < 0x20) {
362
+ view.setUint8(offset, length | 0xa0);
363
+ utf8Write(view, offset + 1, value);
364
+ return 1 + length;
365
+ }
366
+ // str 8
367
+ if (length < 0x100) {
368
+ view.setUint8(offset, 0xd9);
369
+ view.setUint8(offset + 1, length);
370
+ utf8Write(view, offset + 2, value);
371
+ return 2 + length;
372
+ }
373
+ // str 16
374
+ if (length < 0x10000) {
375
+ view.setUint8(offset, 0xda);
376
+ view.setUint16(offset + 1, length);
377
+ utf8Write(view, offset + 3, value);
378
+ return 3 + length;
379
+ }
380
+ // str 32
381
+ if (length < 0x100000000) {
382
+ view.setUint8(offset, 0xdb);
383
+ view.setUint32(offset + 1, length);
384
+ utf8Write(view, offset + 5, value);
385
+ return 5 + length;
386
+ }
387
+ }
388
+
389
+ if (value instanceof ArrayBuffer) {
390
+ var length = value.byteLength;
391
+ // bin 8
392
+ if (length < 0x100) {
393
+ view.setUint8(offset, 0xc4);
394
+ view.setUint8(offset + 1, length);
395
+ (new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 2);
396
+ return 2 + length;
397
+ }
398
+ // bin 16
399
+ if (length < 0x10000) {
400
+ view.setUint8(offset, 0xc5);
401
+ view.setUint16(offset + 1, length);
402
+ (new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 3);
403
+ return 3 + length;
404
+ }
405
+ // bin 32
406
+ if (length < 0x100000000) {
407
+ view.setUint8(offset, 0xc6);
408
+ view.setUint32(offset + 1, length);
409
+ (new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 5);
410
+ return 5 + length;
411
+ }
412
+ }
413
+
414
+ if (type === "number") {
415
+ // Floating Point
416
+ if ((value << 0) !== value) {
417
+ view.setUint8(offset, 0xcb);
418
+ view.setFloat64(offset + 1, value);
419
+ return 9;
420
+ }
421
+
422
+ // Integers
423
+ if (value >=0) {
424
+ // positive fixnum
425
+ if (value < 0x80) {
426
+ view.setUint8(offset, value);
427
+ return 1;
428
+ }
429
+ // uint 8
430
+ if (value < 0x100) {
431
+ view.setUint8(offset, 0xcc);
432
+ view.setUint8(offset + 1, value);
433
+ return 2;
434
+ }
435
+ // uint 16
436
+ if (value < 0x10000) {
437
+ view.setUint8(offset, 0xcd);
438
+ view.setUint16(offset + 1, value);
439
+ return 3;
440
+ }
441
+ // uint 32
442
+ if (value < 0x100000000) {
443
+ view.setUint8(offset, 0xce);
444
+ view.setUint32(offset + 1, value);
445
+ return 5;
446
+ }
447
+ throw new Error("Number too big 0x" + value.toString(16));
448
+ }
449
+ // negative fixnum
450
+ if (value >= -0x20) {
451
+ view.setInt8(offset, value);
452
+ return 1;
453
+ }
454
+ // int 8
455
+ if (value >= -0x80) {
456
+ view.setUint8(offset, 0xd0);
457
+ view.setInt8(offset + 1, value);
458
+ return 2;
459
+ }
460
+ // int 16
461
+ if (value >= -0x8000) {
462
+ view.setUint8(offset, 0xd1);
463
+ view.setInt16(offset + 1, value);
464
+ return 3;
465
+ }
466
+ // int 32
467
+ if (value >= -0x80000000) {
468
+ view.setUint8(offset, 0xd2);
469
+ view.setInt32(offset + 1, value);
470
+ return 5;
471
+ }
472
+ throw new Error("Number too small -0x" + (-value).toString(16).substr(1));
473
+ }
474
+
475
+ // undefined
476
+ if (type === "undefined") {
477
+ view.setUint8(offset, 0xd4); // fixext 1
478
+ view.setUint8(offset + 1, 0); // type (undefined)
479
+ view.setUint8(offset + 2, 0); // data (ignored)
480
+ return 3;
481
+ }
482
+
483
+ // null
484
+ if (value === null) {
485
+ view.setUint8(offset, 0xc0);
486
+ return 1;
487
+ }
488
+
489
+ // Boolean
490
+ if (type === "boolean") {
491
+ view.setUint8(offset, value ? 0xc3 : 0xc2);
492
+ return 1;
493
+ }
494
+
495
+ // Container Types
496
+ if (type === "object") {
497
+ var length, size = 0;
498
+ var isArray = Array.isArray(value);
499
+
500
+ if (isArray) {
501
+ length = value.length;
502
+ }
503
+ else {
504
+ var keys = Object.keys(value);
505
+ length = keys.length;
506
+ }
507
+
508
+ var size;
509
+ if (length < 0x10) {
510
+ view.setUint8(offset, length | (isArray ? 0x90 : 0x80));
511
+ size = 1;
512
+ }
513
+ else if (length < 0x10000) {
514
+ view.setUint8(offset, isArray ? 0xdc : 0xde);
515
+ view.setUint16(offset + 1, length);
516
+ size = 3;
517
+ }
518
+ else if (length < 0x100000000) {
519
+ view.setUint8(offset, isArray ? 0xdd : 0xdf);
520
+ view.setUint32(offset + 1, length);
521
+ size = 5;
522
+ }
523
+
524
+ if (isArray) {
525
+ for (var i = 0; i < length; i++) {
526
+ size += encode(value[i], view, offset + size);
527
+ }
528
+ }
529
+ else {
530
+ for (var i = 0; i < length; i++) {
531
+ var key = keys[i];
532
+ size += encode(key, view, offset + size);
533
+ size += encode(value[key], view, offset + size);
534
+ }
535
+ }
536
+
537
+ return size;
538
+ }
539
+ throw new Error("Unknown type " + type);
540
+ }
541
+
542
+ function encodedSize(value) {
543
+ var type = typeof value;
544
+
545
+ // Raw Bytes
546
+ if (type === "string") {
547
+ var length = utf8ByteCount(value);
548
+ if (length < 0x20) {
549
+ return 1 + length;
550
+ }
551
+ if (length < 0x100) {
552
+ return 2 + length;
553
+ }
554
+ if (length < 0x10000) {
555
+ return 3 + length;
556
+ }
557
+ if (length < 0x100000000) {
558
+ return 5 + length;
559
+ }
560
+ }
561
+
562
+ if (value instanceof ArrayBuffer) {
563
+ var length = value.byteLength;
564
+ if (length < 0x100) {
565
+ return 2 + length;
566
+ }
567
+ if (length < 0x10000) {
568
+ return 3 + length;
569
+ }
570
+ if (length < 0x100000000) {
571
+ return 5 + length;
572
+ }
573
+ }
574
+
575
+ if (type === "number") {
576
+ // Floating Point
577
+ // double
578
+ if (value << 0 !== value) return 9;
579
+
580
+ // Integers
581
+ if (value >=0) {
582
+ // positive fixnum
583
+ if (value < 0x80) return 1;
584
+ // uint 8
585
+ if (value < 0x100) return 2;
586
+ // uint 16
587
+ if (value < 0x10000) return 3;
588
+ // uint 32
589
+ if (value < 0x100000000) return 5;
590
+ // uint 64
591
+ if (value < 0x10000000000000000) return 9;
592
+ throw new Error("Number too big 0x" + value.toString(16));
593
+ }
594
+ // negative fixnum
595
+ if (value >= -0x20) return 1;
596
+ // int 8
597
+ if (value >= -0x80) return 2;
598
+ // int 16
599
+ if (value >= -0x8000) return 3;
600
+ // int 32
601
+ if (value >= -0x80000000) return 5;
602
+ // int 64
603
+ if (value >= -0x8000000000000000) return 9;
604
+ throw new Error("Number too small -0x" + value.toString(16).substr(1));
605
+ }
606
+
607
+ // undefined
608
+ if (type === "undefined") return 3;
609
+
610
+ // Boolean, null
611
+ if (type === "boolean" || value === null) return 1;
612
+
613
+ // Container Types
614
+ if (type === "object") {
615
+ var length, size = 0;
616
+ if (Array.isArray(value)) {
617
+ length = value.length;
618
+ for (var i = 0; i < length; i++) {
619
+ size += encodedSize(value[i]);
620
+ }
621
+ }
622
+ else {
623
+ var keys = Object.keys(value);
624
+ length = keys.length;
625
+ for (var i = 0; i < length; i++) {
626
+ var key = keys[i];
627
+ size += encodedSize(key) + encodedSize(value[key]);
628
+ }
629
+ }
630
+ if (length < 0x10) {
631
+ return 1 + size;
632
+ }
633
+ if (length < 0x10000) {
634
+ return 3 + size;
635
+ }
636
+ if (length < 0x100000000) {
637
+ return 5 + size;
638
+ }
639
+ throw new Error("Array or object too long 0x" + length.toString(16));
640
+ }
641
+ throw new Error("Unknown type " + type);
642
+ }
643
+
644
+ return exports;
645
+
646
+ });
@@ -0,0 +1,81 @@
1
+ <!DOCTYPE html>
2
+ </head>
3
+ <meta charset="utf-8" />
4
+ <title>WebSocket Test</title>
5
+ </head>
6
+ <!-- based on http://www.websocket.org/echo.html -->
7
+ <body>
8
+ <!-- https://github.com/creationix/msgpack-js-browser --><script src="./msgpack.js"></script>
9
+ <script language="javascript" type="text/javascript">
10
+
11
+ var wsUri = "ws://localhost:38080/";
12
+ var output;
13
+ var latestData; // for debugging
14
+
15
+ function init()
16
+ {
17
+ output = document.getElementById("output");
18
+ testWebSocket();
19
+ }
20
+
21
+ function testWebSocket()
22
+ {
23
+ websocket = new WebSocket(wsUri);
24
+ websocket.binaryType = "arraybuffer";
25
+ websocket.onopen = function(evt) { onOpen(evt) };
26
+ websocket.onclose = function(evt) { onClose(evt) };
27
+ websocket.onmessage = function(evt) { onMessage(evt) };
28
+ websocket.onerror = function(evt) { onError(evt) };
29
+ }
30
+
31
+ function onOpen(evt)
32
+ {
33
+ writeToScreen("CONNECTED");
34
+ doSend("onOpen");
35
+ }
36
+
37
+ function onClose(evt)
38
+ {
39
+ writeToScreen("DISCONNECTED");
40
+ }
41
+
42
+ function onMessage(evt)
43
+ {
44
+ latestData = evt.data
45
+ if (typeof(evt.data) == 'string') {
46
+ text = evt.data;
47
+ } else {
48
+ decoded = msgpack.decode(evt.data);
49
+ text = JSON.stringify(decoded.slice(1));
50
+ }
51
+ writeToScreen('<span style="color: blue;">RESPONSE: ' + text +'</span>');
52
+ }
53
+
54
+ function onError(evt)
55
+ {
56
+ writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
57
+ }
58
+
59
+ function doSend(message)
60
+ {
61
+ writeToScreen("SENT: " + message);
62
+ websocket.send(message);
63
+ }
64
+
65
+ function writeToScreen(message)
66
+ {
67
+ var pre = document.createElement("p");
68
+ pre.style.wordWrap = "break-word";
69
+ pre.innerHTML = message;
70
+ output.appendChild(pre);
71
+ }
72
+
73
+ window.addEventListener("load", init, false);
74
+
75
+ </script>
76
+
77
+ <h2>WebSocket Test</h2>
78
+
79
+ <div id="output"></div>
80
+ </body>
81
+
@@ -1,10 +1,10 @@
1
1
  # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
2
+ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = "fluent-plugin-websocket"
6
- gem.version = "0.1.6"
7
- gem.authors = ["IZAWA Tetsu (@moccos)"]
6
+ gem.version = "0.1.8"
7
+ gem.authors = ["Tetsu Izawa (@moccos)"]
8
8
  gem.email = ["tt.izawa@gmail.com"]
9
9
  gem.homepage = "https://github.com/moccos/fluent-plugin-websocket"
10
10
  gem.summary = %q{Fluentd websocket output plugin}
@@ -18,9 +18,8 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_development_dependency "rake"
21
- gem.add_development_dependency "fluentd"
22
21
  gem.add_development_dependency "websocket-eventmachine-client"
23
- gem.add_development_dependency "msgpack"
22
+ gem.add_runtime_dependency "msgpack"
24
23
  gem.add_runtime_dependency "yajl-ruby"
25
24
  gem.add_runtime_dependency "fluentd"
26
25
  gem.add_runtime_dependency "em-websocket"
@@ -27,43 +27,83 @@ module Fluent
27
27
  config_param :port, :integer, :default => 8080
28
28
  config_param :add_time, :bool, :default => false
29
29
  config_param :add_tag, :bool, :default => true
30
+ config_param :buffered_messages, :integer, :default => 0
31
+ config_param :token, :string, :default => nil
30
32
 
31
33
  def configure(conf)
32
34
  super
33
- $thread = Thread.new do
34
- $log.trace "Started em-websocket thread."
35
- $log.info "WebSocket server #{@host}:#{@port} [msgpack: #{@use_msgpack}]"
36
- EM.run {
37
- EM::WebSocket.run(:host => @host, :port => @port) do |ws|
38
- ws.onopen { |handshake|
39
- callback = @use_msgpack ? proc{|msg| ws.send_binary(msg)} : proc{|msg| ws.send(msg)}
40
- $lock.synchronize do
41
- sid = $channel.subscribe callback
42
- $log.trace "WebSocket connection: ID " + sid.to_s
43
- ws.onclose {
44
- $log.trace "Connection closed: ID " + sid.to_s
35
+ @thread = Thread.new do
36
+ $log.trace "Started em-websocket thread."
37
+ $log.info "WebSocket server #{@host}:#{@port} [msgpack: #{@use_msgpack}]"
38
+ EM.run {
39
+ EM::WebSocket.run(:host => @host, :port => @port) do |ws|
40
+ ws.onopen { |handshake|
41
+ $log.info "WebSocket opened #{{
42
+ :path => handshake.path,
43
+ :query => handshake.query,
44
+ :origin => handshake.origin,
45
+ }}"
46
+ if doAuth(handshake.query)
47
+ callback = @use_msgpack ? proc{|msg| ws.send_binary(msg)} : proc{|msg| sendMsg(handshake.query, ws, msg)}
45
48
  $lock.synchronize do
46
- $channel.unsubscribe(sid)
49
+ sid = $channel.subscribe callback
50
+ $log.trace "WebSocket connection: ID " + sid.to_s
51
+ ws.onclose {
52
+ $log.trace "Connection closed: ID " + sid.to_s
53
+ $lock.synchronize do
54
+ $channel.unsubscribe(sid)
55
+ end
56
+ }
57
+ @buffer.each do |msg|
58
+ sendMsg(handshake.query, ws, msg)
59
+ end
47
60
  end
48
- }
49
- end
61
+ else
62
+ ws.send("Unauthorized")
63
+ end
50
64
 
51
- #ws.onmessage { |msg|
52
- #}
53
- }
54
- end
55
- }
65
+ #ws.onmessage { |msg|
66
+ #}
67
+ }
68
+ end
69
+ }
70
+ end
71
+ end
72
+
73
+ def doAuth(query)
74
+ if @token.nil? || ( query.key?("token") && @token == query["token"] )
75
+ $log.trace "Auth OK"
76
+ return true
77
+ end
78
+
79
+ $log.trace "Auth failed"
80
+ return false
81
+ end
82
+
83
+ def sendMsg(filters, ws, msg)
84
+ parser = Yajl::Parser.new
85
+ msgStruct = parser.parse(msg)
86
+ return if msgStruct.length != 2
87
+ msgContent = msgStruct[1]
88
+
89
+ pass = 0
90
+
91
+ filters.each do |key, value|
92
+ pass += 1 if key == 'token' || ( msgContent.key?(key) && msgContent[key] == value )
56
93
  end
94
+
95
+ ws.send(msg) if filters.length == pass
57
96
  end
58
97
 
59
98
  def start
99
+ @buffer = []
60
100
  super
61
101
  end
62
102
 
63
103
  def shutdown
64
104
  super
65
105
  EM.stop
66
- Thread::kill($thread)
106
+ Thread::kill(@thread)
67
107
  $log.trace "Killed em-websocket thread."
68
108
  end
69
109
 
@@ -74,10 +114,18 @@ module Fluent
74
114
  if (@add_time) then data.unshift(time) end
75
115
  if (@add_tag) then data.unshift(tag) end
76
116
  output = @use_msgpack ? data.to_msgpack : Yajl::Encoder.encode( data )
117
+ buffer(output)
77
118
  $lock.synchronize do
78
119
  $channel.push output
79
120
  end
80
121
  }
81
122
  end
123
+
124
+ def buffer(data)
125
+ return unless @buffered_messages > 0
126
+ @buffer << data
127
+ # Buffer only new @buffered_messages messages
128
+ @buffer = @buffer[-@buffered_messages, @buffered_messages] if @buffer.length > @buffered_messages
129
+ end
82
130
  end
83
131
  end
metadata CHANGED
@@ -1,126 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-websocket
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
5
- prerelease:
4
+ version: 0.1.8
6
5
  platform: ruby
7
6
  authors:
8
- - IZAWA Tetsu (@moccos)
7
+ - Tetsu Izawa (@moccos)
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-11-18 00:00:00.000000000 Z
11
+ date: 2018-01-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: fluentd
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
39
- prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
24
+ - - ">="
44
25
  - !ruby/object:Gem::Version
45
26
  version: '0'
46
27
  - !ruby/object:Gem::Dependency
47
28
  name: websocket-eventmachine-client
48
29
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
30
  requirements:
51
- - - ! '>='
31
+ - - ">="
52
32
  - !ruby/object:Gem::Version
53
33
  version: '0'
54
34
  type: :development
55
35
  prerelease: false
56
36
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
37
  requirements:
59
- - - ! '>='
38
+ - - ">="
60
39
  - !ruby/object:Gem::Version
61
40
  version: '0'
62
41
  - !ruby/object:Gem::Dependency
63
42
  name: msgpack
64
43
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
44
  requirements:
67
- - - ! '>='
45
+ - - ">="
68
46
  - !ruby/object:Gem::Version
69
47
  version: '0'
70
- type: :development
48
+ type: :runtime
71
49
  prerelease: false
72
50
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
51
  requirements:
75
- - - ! '>='
52
+ - - ">="
76
53
  - !ruby/object:Gem::Version
77
54
  version: '0'
78
55
  - !ruby/object:Gem::Dependency
79
56
  name: yajl-ruby
80
57
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
58
  requirements:
83
- - - ! '>='
59
+ - - ">="
84
60
  - !ruby/object:Gem::Version
85
61
  version: '0'
86
62
  type: :runtime
87
63
  prerelease: false
88
64
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
65
  requirements:
91
- - - ! '>='
66
+ - - ">="
92
67
  - !ruby/object:Gem::Version
93
68
  version: '0'
94
69
  - !ruby/object:Gem::Dependency
95
70
  name: fluentd
96
71
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
72
  requirements:
99
- - - ! '>='
73
+ - - ">="
100
74
  - !ruby/object:Gem::Version
101
75
  version: '0'
102
76
  type: :runtime
103
77
  prerelease: false
104
78
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
79
  requirements:
107
- - - ! '>='
80
+ - - ">="
108
81
  - !ruby/object:Gem::Version
109
82
  version: '0'
110
83
  - !ruby/object:Gem::Dependency
111
84
  name: em-websocket
112
85
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
86
  requirements:
115
- - - ! '>='
87
+ - - ">="
116
88
  - !ruby/object:Gem::Version
117
89
  version: '0'
118
90
  type: :runtime
119
91
  prerelease: false
120
92
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
93
  requirements:
123
- - - ! '>='
94
+ - - ">="
124
95
  - !ruby/object:Gem::Version
125
96
  version: '0'
126
97
  description: Fluentd websocket output plugin which can output JSON string or MessagePack
@@ -131,38 +102,39 @@ executables: []
131
102
  extensions: []
132
103
  extra_rdoc_files: []
133
104
  files:
134
- - .gitignore
105
+ - ".gitignore"
135
106
  - Gemfile
136
107
  - LICENSE.txt
137
108
  - README.rdoc
138
109
  - Rakefile
110
+ - examples/msgpack.js
111
+ - examples/websocket.html
139
112
  - fluent-plugin-websocket.gemspec
140
113
  - lib/fluent/plugin/out_websocket.rb
141
114
  - test/plugin/test_out_websocket.rb
142
115
  homepage: https://github.com/moccos/fluent-plugin-websocket
143
116
  licenses:
144
117
  - Apache License, Version 2.0
118
+ metadata: {}
145
119
  post_install_message:
146
120
  rdoc_options: []
147
121
  require_paths:
148
122
  - lib
149
123
  required_ruby_version: !ruby/object:Gem::Requirement
150
- none: false
151
124
  requirements:
152
- - - ! '>='
125
+ - - ">="
153
126
  - !ruby/object:Gem::Version
154
127
  version: 1.9.2
155
128
  required_rubygems_version: !ruby/object:Gem::Requirement
156
- none: false
157
129
  requirements:
158
- - - ! '>='
130
+ - - ">="
159
131
  - !ruby/object:Gem::Version
160
132
  version: '0'
161
133
  requirements: []
162
134
  rubyforge_project:
163
- rubygems_version: 1.8.25
135
+ rubygems_version: 2.6.11
164
136
  signing_key:
165
- specification_version: 3
137
+ specification_version: 4
166
138
  summary: Fluentd websocket output plugin
167
139
  test_files:
168
140
  - test/plugin/test_out_websocket.rb