Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

395 строки
9.2 KiB

  1. var app = require('express')();
  2. var server = require('http').Server(app);
  3. var io = require('socket.io')(server);
  4. var cookie = require('cookie')
  5. var fs = require('fs');
  6. var path = require('path');
  7. var redis = require("redis");
  8. var request = require('superagent');
  9. var conf = get_conf();
  10. var flags = {};
  11. var files_struct = {
  12. name: null,
  13. type: null,
  14. size: 0,
  15. data: [],
  16. slice: 0,
  17. site_name: null,
  18. is_private: 0
  19. };
  20. var subscriber = redis.createClient(conf.redis_socketio || conf.redis_async_broker_port);
  21. // serve socketio
  22. server.listen(conf.socketio_port, function () {
  23. console.log('listening on *:', conf.socketio_port); //eslint-disable-line
  24. });
  25. // test route
  26. app.get('/', function (req, res) {
  27. res.sendfile('index.html');
  28. });
  29. // on socket connection
  30. io.on('connection', function (socket) {
  31. if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
  32. return;
  33. }
  34. if (!socket.request.headers.cookie) {
  35. return;
  36. }
  37. var sid = cookie.parse(socket.request.headers.cookie).sid
  38. if (!sid) {
  39. return;
  40. }
  41. if (flags[sid]) {
  42. // throttle this function
  43. return;
  44. }
  45. flags[sid] = sid;
  46. setTimeout(function () {
  47. flags[sid] = null;
  48. }, 10000);
  49. socket.user = cookie.parse(socket.request.headers.cookie).user_id;
  50. socket.files = {};
  51. // frappe.chat
  52. socket.on("frappe.chat.room:subscribe", function (rooms) {
  53. if (!Array.isArray(rooms)) {
  54. rooms = [rooms];
  55. }
  56. for (var room of rooms) {
  57. console.log('frappe.chat: Subscribing ' + socket.user + ' to room ' + room);
  58. room = get_chat_room(socket, room);
  59. console.log('frappe.chat: Subscribing ' + socket.user + ' to event ' + room);
  60. socket.join(room);
  61. }
  62. });
  63. socket.on("frappe.chat.message:typing", function (data) {
  64. const user = data.user;
  65. const room = get_chat_room(socket, data.room);
  66. console.log('frappe.chat: Dispatching ' + user + ' typing to room ' + room);
  67. io.to(room).emit('frappe.chat.room:typing', {
  68. room: data.room,
  69. user: user
  70. });
  71. });
  72. request.get(get_url(socket, '/api/method/frappe.async.get_user_info'))
  73. .type('form')
  74. .query({
  75. sid: sid
  76. })
  77. .end(function (err, res) {
  78. if (err) {
  79. console.log(err);
  80. return;
  81. }
  82. if (res.status == 200) {
  83. var room = get_user_room(socket, res.body.message.user);
  84. socket.join(room);
  85. socket.join(get_site_room(socket));
  86. }
  87. });
  88. socket.on('disconnect', function () {
  89. delete socket.files;
  90. })
  91. socket.on('task_subscribe', function (task_id) {
  92. var room = get_task_room(socket, task_id);
  93. socket.join(room);
  94. });
  95. socket.on('task_unsubscribe', function (task_id) {
  96. var room = get_task_room(socket, task_id);
  97. socket.leave(room);
  98. });
  99. socket.on('progress_subscribe', function (task_id) {
  100. var room = get_task_room(socket, task_id);
  101. socket.join(room);
  102. send_existing_lines(task_id, socket);
  103. });
  104. socket.on('doc_subscribe', function (doctype, docname) {
  105. can_subscribe_doc({
  106. socket: socket,
  107. sid: sid,
  108. doctype: doctype,
  109. docname: docname,
  110. callback: function (err, res) {
  111. var room = get_doc_room(socket, doctype, docname);
  112. socket.join(room);
  113. }
  114. });
  115. });
  116. socket.on('doc_unsubscribe', function (doctype, docname) {
  117. var room = get_doc_room(socket, doctype, docname);
  118. socket.leave(room);
  119. });
  120. socket.on('task_unsubscribe', function (task_id) {
  121. var room = 'task:' + task_id;
  122. socket.leave(room);
  123. });
  124. socket.on('doc_open', function (doctype, docname) {
  125. // show who is currently viewing the form
  126. can_subscribe_doc({
  127. socket: socket,
  128. sid: sid,
  129. doctype: doctype,
  130. docname: docname,
  131. callback: function (err, res) {
  132. var room = get_open_doc_room(socket, doctype, docname);
  133. socket.join(room);
  134. send_viewers({
  135. socket: socket,
  136. doctype: doctype,
  137. docname: docname,
  138. });
  139. }
  140. });
  141. });
  142. socket.on('doc_close', function (doctype, docname) {
  143. // remove this user from the list of 'who is currently viewing the form'
  144. var room = get_open_doc_room(socket, doctype, docname);
  145. socket.leave(room);
  146. send_viewers({
  147. socket: socket,
  148. doctype: doctype,
  149. docname: docname,
  150. });
  151. });
  152. socket.on('upload-accept-slice', (data) => {
  153. try {
  154. if (!socket.files[data.name]) {
  155. socket.files[data.name] = Object.assign({}, files_struct, data);
  156. socket.files[data.name].data = [];
  157. }
  158. //convert the ArrayBuffer to Buffer
  159. data.data = new Buffer(new Uint8Array(data.data));
  160. //save the data
  161. socket.files[data.name].data.push(data.data);
  162. socket.files[data.name].slice++;
  163. if (socket.files[data.name].slice * 24576 >= socket.files[data.name].size) {
  164. // do something with the data
  165. var fileBuffer = Buffer.concat(socket.files[data.name].data);
  166. const file_url = path.join((socket.files[data.name].is_private ? 'private' : 'public'),
  167. 'files', data.name);
  168. const file_path = path.join('sites', get_site_name(socket), file_url);
  169. fs.writeFile(file_path, fileBuffer, (err) => {
  170. delete socket.files[data.name];
  171. if (err) return socket.emit('upload error');
  172. socket.emit('upload-end', {
  173. file_url: '/' + file_url
  174. });
  175. });
  176. } else {
  177. socket.emit('upload-request-slice', {
  178. currentSlice: socket.files[data.name].slice
  179. });
  180. }
  181. } catch (e) {
  182. console.log(e);
  183. socket.emit('upload-error', {
  184. error: e.message
  185. });
  186. }
  187. });
  188. });
  189. subscriber.on("message", function (channel, message, room) {
  190. message = JSON.parse(message)
  191. io.to(message.room).emit(message.event, message.message)
  192. });
  193. subscriber.subscribe("events");
  194. function send_existing_lines(task_id, socket) {
  195. var room = get_task_room(socket, task_id);
  196. subscriber.hgetall('task_log:' + task_id, function (err, lines) {
  197. io.to(room).emit('task_progress', {
  198. "task_id": task_id,
  199. "message": {
  200. "lines": lines
  201. }
  202. });
  203. });
  204. }
  205. function get_doc_room(socket, doctype, docname) {
  206. return get_site_name(socket) + ':doc:' + doctype + '/' + docname;
  207. }
  208. function get_open_doc_room(socket, doctype, docname) {
  209. return get_site_name(socket) + ':open_doc:' + doctype + '/' + docname;
  210. }
  211. function get_user_room(socket, user) {
  212. return get_site_name(socket) + ':user:' + user;
  213. }
  214. function get_site_room(socket) {
  215. return get_site_name(socket) + ':all';
  216. }
  217. function get_task_room(socket, task_id) {
  218. return get_site_name(socket) + ':task_progress:' + task_id;
  219. }
  220. // frappe.chat
  221. // If you're thinking on multi-site or anything, please
  222. // update frappe.async as well.
  223. function get_chat_room(socket, room) {
  224. var room = get_site_name(socket) + ":room:" + room;
  225. return room
  226. }
  227. function get_site_name(socket) {
  228. if (socket.request.headers['x-frappe-site-name']) {
  229. return get_hostname(socket.request.headers['x-frappe-site-name']);
  230. } else if (['localhost', '127.0.0.1'].indexOf(socket.request.headers.host) !== -1 &&
  231. conf.default_site) {
  232. // from currentsite.txt since host is localhost
  233. return conf.default_site;
  234. } else if (socket.request.headers.origin) {
  235. return get_hostname(socket.request.headers.origin);
  236. } else {
  237. return get_hostname(socket.request.headers.host);
  238. }
  239. }
  240. function get_hostname(url) {
  241. if (!url) return undefined;
  242. if (url.indexOf("://") > -1) {
  243. url = url.split('/')[2];
  244. }
  245. return (url.match(/:/g)) ? url.slice(0, url.indexOf(":")) : url
  246. }
  247. function get_url(socket, path) {
  248. if (!path) {
  249. path = '';
  250. }
  251. return socket.request.headers.origin + path;
  252. }
  253. function can_subscribe_doc(args) {
  254. if (!args) return;
  255. if (!args.doctype || !args.docname) return;
  256. request.get(get_url(args.socket, '/api/method/frappe.async.can_subscribe_doc'))
  257. .type('form')
  258. .query({
  259. sid: args.sid,
  260. doctype: args.doctype,
  261. docname: args.docname
  262. })
  263. .end(function (err, res) {
  264. if (!res) {
  265. console.log("No response for doc_subscribe");
  266. } else if (res.status == 403) {
  267. return;
  268. } else if (err) {
  269. console.log(err);
  270. } else if (res.status == 200) {
  271. args.callback(err, res);
  272. } else {
  273. console.log("Something went wrong", err, res);
  274. }
  275. });
  276. }
  277. function send_viewers(args) {
  278. // send to doc room, 'users currently viewing this document'
  279. if (!(args && args.doctype && args.docname)) {
  280. return;
  281. }
  282. // open doc room
  283. var room = get_open_doc_room(args.socket, args.doctype, args.docname);
  284. var socketio_room = io.sockets.adapter.rooms[room] || {};
  285. // for compatibility with both v1.3.7 and 1.4.4
  286. var clients_dict = ("sockets" in socketio_room) ? socketio_room.sockets : socketio_room;
  287. // socket ids connected to this room
  288. var clients = Object.keys(clients_dict || {});
  289. var viewers = [];
  290. for (var i in io.sockets.sockets) {
  291. var s = io.sockets.sockets[i];
  292. if (clients.indexOf(s.id) !== -1) {
  293. // this socket is connected to the room
  294. viewers.push(s.user);
  295. }
  296. }
  297. // notify
  298. io.to(room).emit("doc_viewers", {
  299. doctype: args.doctype,
  300. docname: args.docname,
  301. viewers: viewers
  302. });
  303. }
  304. function get_conf() {
  305. // defaults
  306. var conf = {
  307. redis_async_broker_port: 12311,
  308. socketio_port: 3000
  309. };
  310. var read_config = function (path) {
  311. if (fs.existsSync(path)) {
  312. var bench_config = JSON.parse(fs.readFileSync(path));
  313. for (var key in bench_config) {
  314. if (bench_config[key]) {
  315. conf[key] = bench_config[key];
  316. }
  317. }
  318. }
  319. }
  320. // get ports from bench/config.json
  321. read_config('config.json');
  322. read_config('sites/common_site_config.json');
  323. // detect current site
  324. if (fs.existsSync('sites/currentsite.txt')) {
  325. conf.default_site = fs.readFileSync('sites/currentsite.txt').toString().trim();
  326. }
  327. return conf;
  328. }