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.

socketio.js 7.0 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. var app = require('express')();
  2. var http = require('http').Server(app);
  3. var io = require('socket.io')(http);
  4. var cookie = require('cookie')
  5. var fs = require('fs');
  6. var redis = require("redis");
  7. var request = require('superagent');
  8. var conf = get_conf();
  9. var subscriber = redis.createClient(conf.redis_socketio || conf.redis_async_broker_port);
  10. // serve socketio
  11. http.listen(conf.socketio_port, function(){
  12. console.log('listening on *:', conf.socketio_port);
  13. });
  14. // test route
  15. app.get('/', function(req, res){
  16. res.sendfile('index.html');
  17. });
  18. // on socket connection
  19. io.on('connection', function(socket){
  20. if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
  21. return;
  22. }
  23. // console.log("connection!");
  24. var sid = cookie.parse(socket.request.headers.cookie).sid
  25. if(!sid) {
  26. return;
  27. }
  28. socket.user = cookie.parse(socket.request.headers.cookie).user_id;
  29. // console.log("firing get_user_info");
  30. request.get(get_url(socket, '/api/method/frappe.async.get_user_info'))
  31. .type('form')
  32. .query({
  33. sid: sid
  34. })
  35. .end(function(err, res) {
  36. if(err) {
  37. console.log(err);
  38. return;
  39. }
  40. if(res.status == 200) {
  41. var room = get_user_room(socket, res.body.message.user);
  42. // console.log('joining', room);
  43. socket.join(room);
  44. socket.join(get_site_room(socket));
  45. }
  46. });
  47. socket.on('task_subscribe', function(task_id) {
  48. var room = get_task_room(socket, task_id);
  49. socket.join(room);
  50. });
  51. socket.on('task_unsubscribe', function(task_id) {
  52. var room = get_task_room(socket, task_id);
  53. socket.leave(room);
  54. });
  55. socket.on('progress_subscribe', function(task_id) {
  56. var room = get_task_room(socket, task_id);
  57. socket.join(room);
  58. send_existing_lines(task_id, socket);
  59. });
  60. socket.on('doc_subscribe', function(doctype, docname) {
  61. // console.log('trying to subscribe', doctype, docname)
  62. can_subscribe_doc({
  63. socket: socket,
  64. sid: sid,
  65. doctype: doctype,
  66. docname: docname,
  67. callback: function(err, res) {
  68. var room = get_doc_room(socket, doctype, docname);
  69. // console.log('joining', room)
  70. socket.join(room);
  71. }
  72. });
  73. });
  74. socket.on('doc_unsubscribe', function(doctype, docname) {
  75. var room = get_doc_room(socket, doctype, docname);
  76. socket.leave(room);
  77. });
  78. socket.on('task_unsubscribe', function(task_id) {
  79. var room = 'task:' + task_id;
  80. socket.leave(room);
  81. });
  82. socket.on('doc_open', function(doctype, docname) {
  83. // show who is currently viewing the form
  84. can_subscribe_doc({
  85. socket: socket,
  86. sid: sid,
  87. doctype: doctype,
  88. docname: docname,
  89. callback: function(err, res) {
  90. var room = get_open_doc_room(socket, doctype, docname);
  91. // console.log('joining', room)
  92. socket.join(room);
  93. send_viewers({
  94. socket: socket,
  95. doctype: doctype,
  96. docname: docname,
  97. });
  98. }
  99. });
  100. });
  101. socket.on('doc_close', function(doctype, docname) {
  102. // remove this user from the list of 'who is currently viewing the form'
  103. var room = get_open_doc_room(socket, doctype, docname);
  104. socket.leave(room);
  105. send_viewers({
  106. socket: socket,
  107. doctype: doctype,
  108. docname: docname,
  109. });
  110. });
  111. // socket.on('disconnect', function (arguments) {
  112. // console.log("user disconnected", arguments);
  113. // });
  114. });
  115. subscriber.on("message", function(channel, message) {
  116. message = JSON.parse(message);
  117. io.to(message.room).emit(message.event, message.message);
  118. // console.log(message.room, message.event, message.message)
  119. });
  120. subscriber.subscribe("events");
  121. function send_existing_lines(task_id, socket) {
  122. var room = get_task_room(socket, task_id);
  123. subscriber.hgetall('task_log:' + task_id, function(err, lines) {
  124. io.to(room).emit('task_progress', {
  125. "task_id": task_id,
  126. "message": {
  127. "lines": lines
  128. }
  129. });
  130. });
  131. }
  132. function get_doc_room(socket, doctype, docname) {
  133. return get_site_name(socket) + ':doc:'+ doctype + '/' + docname;
  134. }
  135. function get_open_doc_room(socket, doctype, docname) {
  136. return get_site_name(socket) + ':open_doc:'+ doctype + '/' + docname;
  137. }
  138. function get_user_room(socket, user) {
  139. return get_site_name(socket) + ':user:' + user;
  140. }
  141. function get_site_room(socket) {
  142. return get_site_name(socket) + ':all';
  143. }
  144. function get_task_room(socket, task_id) {
  145. return get_site_name(socket) + ':task_progress:' + task_id;
  146. }
  147. function get_site_name(socket) {
  148. if (socket.request.headers['x-frappe-site-name']) {
  149. return get_hostname(socket.request.headers['x-frappe-site-name']);
  150. }
  151. else if (['localhost', '127.0.0.1'].indexOf(socket.request.headers.host) !== -1
  152. && conf.default_site) {
  153. // from currentsite.txt since host is localhost
  154. return conf.default_site;
  155. }
  156. else if (socket.request.headers.origin) {
  157. return get_hostname(socket.request.headers.origin);
  158. }
  159. else {
  160. return get_hostname(socket.request.headers.host);
  161. }
  162. }
  163. function get_hostname(url) {
  164. if (!url) return undefined;
  165. if (url.indexOf("://") > -1) {
  166. url = url.split('/')[2];
  167. }
  168. return ( url.match(/:/g) ) ? url.slice( 0, url.indexOf(":") ) : url
  169. }
  170. function get_url(socket, path) {
  171. if (!path) {
  172. path = '';
  173. }
  174. return socket.request.headers.origin + path;
  175. }
  176. function can_subscribe_doc(args) {
  177. if(!args) return;
  178. request.get(get_url(args.socket, '/api/method/frappe.async.can_subscribe_doc'))
  179. .type('form')
  180. .query({
  181. sid: args.sid,
  182. doctype: args.doctype,
  183. docname: args.docname
  184. })
  185. .end(function(err, res) {
  186. if (!res) {
  187. console.log("No response for doc_subscribe");
  188. } else if (res.status == 403) {
  189. return;
  190. } else if (err) {
  191. console.log(err);
  192. } else if (res.status == 200) {
  193. args.callback(err, res);
  194. } else {
  195. console.log("Something went wrong", err, res);
  196. }
  197. });
  198. }
  199. function send_viewers(args) {
  200. // send to doc room, 'users currently viewing this document'
  201. if (!(args && args.doctype && args.docname)) {
  202. return;
  203. }
  204. // open doc room
  205. var room = get_open_doc_room(args.socket, args.doctype, args.docname);
  206. var socketio_room = io.sockets.adapter.rooms[room] || {};
  207. // for compatibility with both v1.3.7 and 1.4.4
  208. var clients_dict = ("sockets" in socketio_room) ? socketio_room.sockets : socketio_room;
  209. // socket ids connected to this room
  210. var clients = Object.keys(clients_dict || {});
  211. var viewers = [];
  212. for (var i in io.sockets.sockets) {
  213. var s = io.sockets.sockets[i];
  214. if (clients.indexOf(s.id)!==-1) {
  215. // this socket is connected to the room
  216. viewers.push(s.user);
  217. }
  218. }
  219. // notify
  220. io.to(room).emit("doc_viewers", {
  221. doctype: args.doctype,
  222. docname: args.docname,
  223. viewers: viewers
  224. });
  225. }
  226. function get_conf() {
  227. // defaults
  228. var conf = {
  229. redis_async_broker_port: 12311,
  230. socketio_port: 3000
  231. };
  232. var read_config = function(path) {
  233. if(fs.existsSync(path)){
  234. var bench_config = JSON.parse(fs.readFileSync(path));
  235. for (var key in bench_config) {
  236. if (bench_config[key]) {
  237. conf[key] = bench_config[key];
  238. }
  239. }
  240. }
  241. }
  242. // get ports from bench/config.json
  243. read_config('config.json');
  244. read_config('sites/common_site_config.json');
  245. // detect current site
  246. if(fs.existsSync('sites/currentsite.txt')) {
  247. conf.default_site = fs.readFileSync('sites/currentsite.txt').toString().trim();
  248. }
  249. return conf;
  250. }