您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

sockets.js 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. var iolib = require('socket.io')
  2. , log = require("./log.js").log
  3. , BoardData = require("./boardData.js").BoardData;
  4. var MAX_EMIT_COUNT = 64; // Maximum number of draw operations before getting banned
  5. var MAX_EMIT_COUNT_PERIOD = 5000; // Duration (in ms) after which the emit count is reset
  6. /** Map from name to *promises* of BoardData
  7. @type {Object<string, Promise<BoardData>>}
  8. */
  9. var boards = {};
  10. function noFail(fn) {
  11. return function noFailWrapped(arg) {
  12. try {
  13. return fn(arg);
  14. } catch (e) {
  15. console.trace(e);
  16. }
  17. }
  18. }
  19. function startIO(app) {
  20. io = iolib(app);
  21. io.on('connection', noFail(socketConnection));
  22. return io;
  23. }
  24. /** Returns a promise to a BoardData with the given name
  25. * @returns {Promise<BoardData>}
  26. */
  27. function getBoard(name) {
  28. if (boards.hasOwnProperty(name)) {
  29. return boards[name];
  30. } else {
  31. var board = BoardData.load(name);
  32. boards[name] = board;
  33. return board;
  34. }
  35. }
  36. function socketConnection(socket) {
  37. async function joinBoard(name) {
  38. // Default to the public board
  39. if (!name) name = "anonymous";
  40. // Join the board
  41. socket.join(name);
  42. var board = await getBoard(name);
  43. board.users.add(socket.id);
  44. log('board joined', { 'board': board.name, 'users': board.users.size });
  45. return board;
  46. }
  47. socket.on("error", noFail(function onError(error) {
  48. log("ERROR", error);
  49. }));
  50. socket.on("getboard", async function onGetBoard(name) {
  51. var board = await joinBoard(name);
  52. //Send all the board's data as soon as it's loaded
  53. socket.emit("broadcast", { _children: board.getAll() });
  54. });
  55. socket.on("joinboard", noFail(joinBoard));
  56. var lastEmitSecond = Date.now() / MAX_EMIT_COUNT_PERIOD | 0;
  57. var emitCount = 0;
  58. socket.on('broadcast', noFail(function onBroadcast(message) {
  59. var currentSecond = Date.now() / MAX_EMIT_COUNT_PERIOD | 0;
  60. if (currentSecond === lastEmitSecond) {
  61. emitCount++;
  62. if (emitCount > MAX_EMIT_COUNT) {
  63. var request = socket.client.request;
  64. log('BANNED', {
  65. user_agent: request.headers['user-agent'],
  66. original_ip: request.headers['x-forwarded-for'] || request.headers['forwarded'],
  67. emit_count: emitCount
  68. });
  69. return;
  70. }
  71. } else {
  72. emitCount = 0;
  73. lastEmitSecond = currentSecond;
  74. }
  75. var boardName = message.board || "anonymous";
  76. var data = message.data;
  77. if (!socket.rooms.hasOwnProperty(boardName)) socket.join(boardName);
  78. if (!data) {
  79. console.warn("Received invalid message: %s.", JSON.stringify(message));
  80. return;
  81. }
  82. //Send data to all other users connected on the same board
  83. socket.broadcast.to(boardName).emit('broadcast', data);
  84. // Save the message in the board
  85. saveHistory(boardName, data);
  86. }));
  87. socket.on('disconnecting', function onDisconnecting(reason) {
  88. Object.keys(socket.rooms).forEach(async function disconnectFrom(room) {
  89. if (boards.hasOwnProperty(room)) {
  90. var board = await boards[room];
  91. board.users.delete(socket.id);
  92. var userCount = board.users.size;
  93. log('disconnection', { 'board': board.name, 'users': board.users.size });
  94. if (userCount === 0) {
  95. board.save();
  96. delete boards[room];
  97. }
  98. }
  99. });
  100. });
  101. }
  102. async function saveHistory(boardName, message) {
  103. var id = message.id;
  104. var board = await getBoard(boardName);
  105. switch (message.type) {
  106. case "delete":
  107. if (id) board.delete(id);
  108. break;
  109. case "update":
  110. delete message.type;
  111. if (id) board.update(id, message);
  112. break;
  113. case "child":
  114. board.addChild(message.parent, message);
  115. break;
  116. default: //Add data
  117. if (!id) throw new Error("Invalid message: ", message);
  118. board.set(id, message);
  119. }
  120. }
  121. function generateUID(prefix, suffix) {
  122. var uid = Date.now().toString(36); //Create the uids in chronological order
  123. uid += (Math.round(Math.random() * 36)).toString(36); //Add a random character at the end
  124. if (prefix) uid = prefix + uid;
  125. if (suffix) uid = uid + suffix;
  126. return uid;
  127. }
  128. if (exports) {
  129. exports.start = startIO;
  130. }