Ein Projekt das es ermöglicht Beerpong über das Internet von zwei unabhängigen positionen aus zu spielen. Entstehung im Rahmen einer Praktikumsaufgabe im Fach Interaktion.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Sender.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*!
  2. * ws: a node.js websocket client
  3. * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
  4. * MIT Licensed
  5. */
  6. var events = require('events')
  7. , util = require('util')
  8. , EventEmitter = events.EventEmitter
  9. , ErrorCodes = require('./ErrorCodes')
  10. , bufferUtil = require('./BufferUtil').BufferUtil
  11. , PerMessageDeflate = require('./PerMessageDeflate');
  12. /**
  13. * HyBi Sender implementation
  14. */
  15. function Sender(socket, extensions) {
  16. events.EventEmitter.call(this);
  17. this._socket = socket;
  18. this.extensions = extensions || {};
  19. this.firstFragment = true;
  20. this.compress = false;
  21. this.messageHandlers = [];
  22. this.processing = false;
  23. }
  24. /**
  25. * Inherits from EventEmitter.
  26. */
  27. util.inherits(Sender, events.EventEmitter);
  28. /**
  29. * Sends a close instruction to the remote party.
  30. *
  31. * @api public
  32. */
  33. Sender.prototype.close = function(code, data, mask, cb) {
  34. if (typeof code !== 'undefined') {
  35. if (typeof code !== 'number' ||
  36. !ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number');
  37. }
  38. code = code || 1000;
  39. var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0));
  40. writeUInt16BE.call(dataBuffer, code, 0);
  41. if (dataBuffer.length > 2) dataBuffer.write(data, 2);
  42. var self = this;
  43. this.messageHandlers.push(function(callback) {
  44. self.frameAndSend(0x8, dataBuffer, true, mask);
  45. callback();
  46. if (typeof cb == 'function') cb();
  47. });
  48. this.flush();
  49. };
  50. /**
  51. * Sends a ping message to the remote party.
  52. *
  53. * @api public
  54. */
  55. Sender.prototype.ping = function(data, options) {
  56. var mask = options && options.mask;
  57. var self = this;
  58. this.messageHandlers.push(function(callback) {
  59. self.frameAndSend(0x9, data || '', true, mask);
  60. callback();
  61. });
  62. this.flush();
  63. };
  64. /**
  65. * Sends a pong message to the remote party.
  66. *
  67. * @api public
  68. */
  69. Sender.prototype.pong = function(data, options) {
  70. var mask = options && options.mask;
  71. var self = this;
  72. this.messageHandlers.push(function(callback) {
  73. self.frameAndSend(0xa, data || '', true, mask);
  74. callback();
  75. });
  76. this.flush();
  77. };
  78. /**
  79. * Sends text or binary data to the remote party.
  80. *
  81. * @api public
  82. */
  83. Sender.prototype.send = function(data, options, cb) {
  84. var finalFragment = options && options.fin === false ? false : true;
  85. var mask = options && options.mask;
  86. var compress = options && options.compress;
  87. var opcode = options && options.binary ? 2 : 1;
  88. if (this.firstFragment === false) {
  89. opcode = 0;
  90. compress = false;
  91. } else {
  92. this.firstFragment = false;
  93. this.compress = compress;
  94. }
  95. if (finalFragment) this.firstFragment = true
  96. var compressFragment = this.compress;
  97. var self = this;
  98. this.messageHandlers.push(function(callback) {
  99. self.applyExtensions(data, finalFragment, compressFragment, function(err, data) {
  100. if (err) {
  101. if (typeof cb == 'function') cb(err);
  102. else self.emit('error', err);
  103. return;
  104. }
  105. self.frameAndSend(opcode, data, finalFragment, mask, compress, cb);
  106. callback();
  107. });
  108. });
  109. this.flush();
  110. };
  111. /**
  112. * Frames and sends a piece of data according to the HyBi WebSocket protocol.
  113. *
  114. * @api private
  115. */
  116. Sender.prototype.frameAndSend = function(opcode, data, finalFragment, maskData, compressed, cb) {
  117. var canModifyData = false;
  118. if (!data) {
  119. try {
  120. this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb);
  121. }
  122. catch (e) {
  123. if (typeof cb == 'function') cb(e);
  124. else this.emit('error', e);
  125. }
  126. return;
  127. }
  128. if (!Buffer.isBuffer(data)) {
  129. canModifyData = true;
  130. if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) {
  131. data = getArrayBuffer(data);
  132. } else {
  133. data = new Buffer(data);
  134. }
  135. }
  136. var dataLength = data.length
  137. , dataOffset = maskData ? 6 : 2
  138. , secondByte = dataLength;
  139. if (dataLength >= 65536) {
  140. dataOffset += 8;
  141. secondByte = 127;
  142. }
  143. else if (dataLength > 125) {
  144. dataOffset += 2;
  145. secondByte = 126;
  146. }
  147. var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData);
  148. var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset;
  149. var outputBuffer = new Buffer(totalLength);
  150. outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode;
  151. if (compressed) outputBuffer[0] |= 0x40;
  152. switch (secondByte) {
  153. case 126:
  154. writeUInt16BE.call(outputBuffer, dataLength, 2);
  155. break;
  156. case 127:
  157. writeUInt32BE.call(outputBuffer, 0, 2);
  158. writeUInt32BE.call(outputBuffer, dataLength, 6);
  159. }
  160. if (maskData) {
  161. outputBuffer[1] = secondByte | 0x80;
  162. var mask = this._randomMask || (this._randomMask = getRandomMask());
  163. outputBuffer[dataOffset - 4] = mask[0];
  164. outputBuffer[dataOffset - 3] = mask[1];
  165. outputBuffer[dataOffset - 2] = mask[2];
  166. outputBuffer[dataOffset - 1] = mask[3];
  167. if (mergeBuffers) {
  168. bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength);
  169. try {
  170. this._socket.write(outputBuffer, 'binary', cb);
  171. }
  172. catch (e) {
  173. if (typeof cb == 'function') cb(e);
  174. else this.emit('error', e);
  175. }
  176. }
  177. else {
  178. bufferUtil.mask(data, mask, data, 0, dataLength);
  179. try {
  180. this._socket.write(outputBuffer, 'binary');
  181. this._socket.write(data, 'binary', cb);
  182. }
  183. catch (e) {
  184. if (typeof cb == 'function') cb(e);
  185. else this.emit('error', e);
  186. }
  187. }
  188. }
  189. else {
  190. outputBuffer[1] = secondByte;
  191. if (mergeBuffers) {
  192. data.copy(outputBuffer, dataOffset);
  193. try {
  194. this._socket.write(outputBuffer, 'binary', cb);
  195. }
  196. catch (e) {
  197. if (typeof cb == 'function') cb(e);
  198. else this.emit('error', e);
  199. }
  200. }
  201. else {
  202. try {
  203. this._socket.write(outputBuffer, 'binary');
  204. this._socket.write(data, 'binary', cb);
  205. }
  206. catch (e) {
  207. if (typeof cb == 'function') cb(e);
  208. else this.emit('error', e);
  209. }
  210. }
  211. }
  212. };
  213. /**
  214. * Execute message handler buffers
  215. *
  216. * @api private
  217. */
  218. Sender.prototype.flush = function() {
  219. if (this.processing) return;
  220. var handler = this.messageHandlers.shift();
  221. if (!handler) return;
  222. this.processing = true;
  223. var self = this;
  224. handler(function() {
  225. self.processing = false;
  226. self.flush();
  227. });
  228. };
  229. /**
  230. * Apply extensions to message
  231. *
  232. * @api private
  233. */
  234. Sender.prototype.applyExtensions = function(data, fin, compress, callback) {
  235. if (compress && data) {
  236. this.extensions[PerMessageDeflate.extensionName].compress(data, fin, callback);
  237. } else {
  238. callback(null, data);
  239. }
  240. };
  241. module.exports = Sender;
  242. function writeUInt16BE(value, offset) {
  243. this[offset] = (value & 0xff00)>>8;
  244. this[offset+1] = value & 0xff;
  245. }
  246. function writeUInt32BE(value, offset) {
  247. this[offset] = (value & 0xff000000)>>24;
  248. this[offset+1] = (value & 0xff0000)>>16;
  249. this[offset+2] = (value & 0xff00)>>8;
  250. this[offset+3] = value & 0xff;
  251. }
  252. function getArrayBuffer(data) {
  253. // data is either an ArrayBuffer or ArrayBufferView.
  254. var array = new Uint8Array(data.buffer || data)
  255. , l = data.byteLength || data.length
  256. , o = data.byteOffset || 0
  257. , buffer = new Buffer(l);
  258. for (var i = 0; i < l; ++i) {
  259. buffer[i] = array[o+i];
  260. }
  261. return buffer;
  262. }
  263. function getRandomMask() {
  264. return new Buffer([
  265. ~~(Math.random() * 255),
  266. ~~(Math.random() * 255),
  267. ~~(Math.random() * 255),
  268. ~~(Math.random() * 255)
  269. ]);
  270. }