å€ãã®å ŽåããµãŒãã¹ã€ãã³ãããã£ã«ã¿ãªã³ã°ããŠããããã®æŸåºãéãããã¯ã©ã€ã¢ã³ãã®ã»ããã«å¶éããå¿
èŠããããŸãïŒããšãã°ããã£ããã¢ããªã®1察1ãŸãã¯1察æ°ã®ãŠãŒã¶ãŒã¡ãã»ãŒãžïŒã ãã£ã«ã¿ã䜿çšãããšãããå®è¡ã§ããŸãããã€ãã³ãããšã«ãã¹ãŠã®æ¥ç¶ãå埩åŠçããå¿
èŠããããŸã...ããã«ãããã€ãã³ããæ¥ç¶ãããã¯ã©ã€ã¢ã³ãã®æ°ãéèŠãªå Žåã«ãäžèŠãªãµãŒããŒè² è·ãçºçããå¯èœæ§ããããŸãã
ãããæ¹åããããã«æ€èšã§ããåªããæ©èœã®1ã€ã¯ããµãŒãã¹ã€ãã³ããšãšãã«ãã£ã¹ãããã£ãæ€èšããæ¥ç¶ã®ãªã¹ããæäŸããå¯èœæ§ãè¿œå ããããšã§ãã ããããã°ãforeachã«ãŒãïŒio.sockets.clientsïŒïŒãforEachïŒfunctionïŒsocketïŒ{...}ïŒã¯ããã®å¶éãããæ¥ç¶ãªã¹ãã«å¯ŸããŠã®ã¿å®è¡ã§ããŸãïŒãŸããããã©ã«ãã§ã¯ããã¹ãŠã®æ¥ç¶ã«å¯ŸããŠå®è¡ã§ããŸãïŒããŸãã¯ããŠãŒã¶ãŒ_idã®ãªã¹ããæž¡ãã_idã®ãããã³ã°ããã§ã¶ãŒã®ã©ããã«èªåçã«æ¥ç¶ã«ä¿æããããšãã§ããŸãã
ãã®æ¹åã«ãããããšãã°ãuser._id <->æ¥ç¶ã®ãªã¹ããç¶æãïŒãã§ã¶ãŒã§åŠçãããŠããªãå ŽåïŒããã£ã¹ãããã£ãŒãåŒã³åºããŠã€ãã³ãïŒ1察1ã®ã¡ãã»ãŒãžãªã©ïŒãçºè¡ããããšãå¯èœã«ãªããŸããç¹å®ã®æ¥ç¶ïŒuser._id->æ¥ç¶ããã·ã¥ããŒãã«ããçŽæ¥ååŸãããŸããããã¯ãã¿ãŒã²ããã®æ¥ç¶ãèŠã€ããããã«ïŒãã£ã«ã¿ãŒã䜿çšããŠïŒãã¹ãŠã®æ¥ç¶ãå埩ãããããã¯ããã«é«éã§ãïŒ
ããªãã«ã¢ã€ãã¢ãäžããããã«ãç§ã¯æ¥ç¶ããã·ã¥ããŒãã«ãžã®ç¹å®ã®ãšã³ããªãæ¢ãããšãšæ¯èŒããŠãæ¯åæ¬åœã«åçŽãªãã¹ãïŒconnection.user._id === message.to_user_idã®ãããªïŒãè¡ãããšã®éãããã¹ãããããã«éåžžã«åçŽãªãã³ãããŒã¯ãäœæããŸããïŒ
çµæã¯æ¬¡ã®ãšããã§ãã
10kæ¥ç¶ã®å ŽåïŒ
foreachã¡ãœããïŒ3.608ms
ããã·ã¥æ¹åŒïŒ0.073ms
100kæ¥ç¶ã®å ŽåïŒ
foreachã¡ãœããïŒ27.761ms
ããã·ã¥æ¹åŒïŒ0.126ms
1Mæ¥ç¶ã®å ŽåïŒ
foreachã¡ãœããïŒ284.016ms
ããã·ã¥æ¹åŒïŒ0.288ms
ãããã£ãŠã10kã®æ¥ç¶ãŸã§ãéãã¯ãåççãã§ãã ãããããããééãããšãéãã¯éèŠã«ãªãå§ããŸãïŒ100äžäººã®ãŠãŒã¶ãŒã®å Žåãåäžã®ã€ãã³ãã®å Žåããã£ã¹ãããã£ã®æ¥ç¶ãã«ãŒãããã ãã§ã»ãŒ1/3ç§ã§ããã€ãŸãã3ã€ãè¶
ããã€ãã³ããåŠçããããšã¯ã§ããŸããã ïŒæè¯ã®å ŽåïŒ100äžäººã®åæãŠãŒã¶ãŒã®å Žåãæ¥ç¶ãäºåã«ãã£ã¹ãããããå Žæãç¥ã£ãŠããã°ã1000å以äžåŠçã§ããŸãïŒã
ãŸãã1ç§ãããã®ã€ãã³ãæ°ã¯ãéåžžããŠãŒã¶ãŒæ°ãšãšãã«å¢å ããããšãèŠããŠããå¿
èŠããããŸã...
ãããã£ãŠã倧ããªã¢ããªã«ãã§ã¶ãŒã䜿çšããå Žåããã£ã¹ãããã£ãŒã®foreachã«ãŒããå®éã®ããã«ããã¯ã«ãªãå¯èœæ§ããããŸã...ïŒ100äžäººã®åæãŠãŒã¶ãŒãããå ŽåãåããŒãã§3ã€ãã³ã/ç§ãè¶
ããåŠçãè¡ãããšã¯ã§ããŸãããããã®ïŒ
ãããç§ã®æ¬åœã«åçŽãªãã³ãããŒã¯ã«äœ¿çšãããã³ãŒãã§ãïŒ
var nbconnections = 1000000;
var array = new Array(nbconnections);
console.time("foreach method");
array.forEach(function(socket) {
if (socket === 0){
}
});
console.timeEnd("foreach method");
var hash = {};
for (i = 0; i < nbconnections; i++) {
hash[i+'']=i;
}
console.time("hash method");
var conn = hash['1000'];
console.timeEnd("hash method");
ããã¯ä»¥åã«åºãŠãããã®ã§ãããå°ã調æ»ãã䟡å€ããããšæããŸãã éšå±ã®äœãæ¹ã®è³ªåãšéåžžã«ãã䌌ãŠããŸãã ãããç§ãã©ã®ããã«èŠãããã«ã€ããŠã®ç§ã®æåã®äºè£ã§ãã ã©ãèããŠãããæããŠãã ããïŒ
// The `channel` service method returns a string which is the key for a
// registered channel
app.service('messages').channel(message => `rooms/${message.room_id}`);
app.service('todos').channel(todo => `company/${todo.company_id}`);
app.on('connection', socket => {
socket.on('authenticated', data => {
// data.token
// data.user
const { token, user } = data;
// For each user room add the socket to a channel
user.rooms.forEach(roomId => app.channel(`rooms/${roomId}`, socket));
// Register the socket in the `company/<company_id>` channel
app.channel(`company/${company_id}`, socket);
});
});
ãŸããçŸåšã®ã€ãã³ããã£ã«ã¿ãªã³ã°ã®ããã©ãŒãã³ã¹ãã³ãããŒã¯ã«ãèå³ããããŸãã ãããŸã§ã®ãšãããããã«ããã¯ã«ã¯ãªã£ãŠããŸãããããã£ãã«/ã«ãŒã ãäœæããç°¡åãªæ¹æ³ããããåæã«ããã©ãŒãã³ã¹ãåäžãããå¯èœæ§ãããã®ã¯çŽ æŽãããããšã§ãã
socket.ioã«ãããã®ãšåæ§ã®éšå±ã·ã¹ãã ã¯è¯ãèãã ãšæããŸãã 䟿å®äžãåãœã±ããã«ã¯ãèªåçã«ãµãã¹ã¯ã©ã€ãããç¬èªã®ã·ã³ã°ã«ã«ãŒã ïŒsocket.io http://socket.io/docs/rooms-and-namespaces/ã®ããã©ã«ãã«ãŒã ãªã©ïŒãå¿
èŠã§ããããã«ãããç°¡åã«éä¿¡ã§ããŸããåäžã®ã¯ã©ã€ã¢ã³ããžã®ã€ãã³ãïŒã¿ãŒã²ããã¯ã©ã€ã¢ã³ãã®ããã©ã«ãã«ãŒã ã«ãããŒããã£ã¹ãããããšã«ããïŒã
åé¡ã¯ãéšå±ã®ãã¹ãŠã®ãµãã¹ã¯ã©ã€ããŒã«ã€ãã³ããã©ã®ããã«ãã£ã¹ããããããã§ãã ãµãŒããŒã®ãã¹ãŠã®ãœã±ããæ¥ç¶ãã«ãŒãããŠç®çã®éšå±ã«å±ãããã®ããã£ã«ã¿ãªã³ã°ããã®ãäœããã®ãã£ã«ã¿ãŒã§ããå ŽåãçŸåšã®ãã£ã¹ãããã£ãŒãšåãå¹çã®åé¡ãçºçããŸãã ãã£ãã«å
ã®ãœã±ããã®ã¿ãã«ãŒãããå ŽåïŒ=ã€ãã³ãããããŒããã£ã¹ãããå¿
èŠã®ããéšå±ã«åå ããå ŽåïŒã¯åé¡ãããŸããã
ãããŸã§ã®ãšããããã£ã¹ãããã£ã®æ¥ç¶ã®ã«ãŒããããã«ããã¯ã«ãªã£ãŠããªãã®ã¯ã倧èŠæš¡ãªã¢ããªïŒåæãŠãŒã¶ãŒæ°ã5,000人ãè¶
ããïŒã§ãã§ã¶ãŒã䜿çšããããšããªãããã ãšæããŸãã ããããããã¯é
ããæ©ããæ¥ãã§ãããïŒçŸœã¯ãŸã æ¬åœã«æ°ããã§ãïŒããããŠç§ãç§ã®æ¬åœã«åçŽãªãã³ãããŒã¯ã§èŠããã®ãããããªãã矜ã§ã¹ã±ãŒãªã³ã°ããããšãããšããã®foreachã«ãŒããåé¡ã«ãªãããšã¯ééããããŸãã...
ãã§ã¶ãŒã®åäžãµãŒããŒããŒããš1kãã100kã®ã¯ã©ã€ã¢ã³ãæ¥ç¶ããšãã¥ã¬ãŒãããããã€ãã®ã¯ã©ã€ã¢ã³ããã·ã³ã䜿çšããŠãå®éã®ããã§ã¶ãŒã¹ãã¬ã¹ãã¹ããè¡ãããšã¯ããã§ã¶ãŒã®çŸåšã®å¶éãšããã«ããã¯ã確èªããããšããå§ãããŸãã ãã®ã¹ãã¬ã¹ãã¹ãã®ããã«ãµãŒããŒãžã®æ°åã®åææ¥ç¶ãå®è¡ããã¹ã¯ãªãããå®è¡ãããã©ã³ãã£ã¢ãå¿
èŠãªå Žåã¯ã2å°ã®ã³ã³ãã¥ãŒã¿ãŒïŒ2ã€ã®ç°ãªãã€ã³ã¿ãŒãããæ¥ç¶ãããïŒã§åãã§å®è¡ã§ããŸãã
ã¯ãã ãã£ãã«ã¯ãæ¥ç¶äžã®ã¯ã©ã€ã¢ã³ãã®æ°ãçµã蟌ãããšã§ãã ããšãã°ãç¹å®ã®ãŠãŒã¶ãŒãã£ãã«ãäœæããå Žåãæ¥ç¶ãªã¹ãã«ã¯1ã€ã®ãšã³ããªãããããŸããã Primusã¯éšå±ããµããŒãããŠããªãã®ã§ãããå°ãäžè¬çã§ããå¿ èŠããããŸãïŒè¿œå ããå¿ èŠããªããšæããã©ã°ã€ã³ã§ã®ã¿ïŒã
ãããåé²ãããã«ã¯ã次ã®ããšãå¿ èŠã ãšæããŸãã
ç§ã®çµéšã§ã¯ãåºæ¬çãªã¢ããªä»¥äžã®ãµãŒããŒããã5kãè¶ ããã¯ã©ã€ã¢ã³ãïŒå®éã®WebSocketæ¥ç¶ã䜿çšïŒã¯ããã¬ãŒã³ãªSocket.ioã§ã課é¡ã§ããã64k以äžã§ã¯ãµãŒããŒãåçŽã«äžè¶³ããããç©ççã«äžå¯èœã§ããããŒãã®æ°ïŒè£è¶³ïŒMeteorã¯æ°çŸã§ãã§ãŒã¯ããŸãïŒã åäžã€ã³ã¹ã¿ã³ã¹ã§ã®100k以äžã®åææ¥ç¶ã¯éåžžã«ããããããªãã®ã§ãããããå¿é ããå¿ èŠã¯ãããŸããïŒããã§ããã€ãã®Socket.ioãã³ãããŒã¯ãèŠã€ããŸã
ãšã¯èšããã®ã®ããã£ã³ãã«/ã«ãŒã ã®æ©èœã楜ãã¿ã«ããŠããŸããããã¯ãããã©ãŒãã³ã¹ãåäžããããšåæã«ãã¯ããã«ç°¡åã«ãªããšãããããã質åã ããã§ãã
64kã®å¶éã¯ãããã誀解ã§ãã TCPããŒãã¯16ãããæŽæ°ã§ããããããµãŒããŒã¯65,536ïŒ216ïŒãè¶
ããTCPãœã±ãããåãå
¥ããããšãã§ããªããšäººã
ã¯èããåŸåããããŸãã
ãã ããå®éã«ã¯ããã§ã¯ãããŸããããµãŒããŒã¯å®éã«ã¯ãã¹ãŠã®ãœã±ããã«å¯ŸããŠ1ã€ã®ãªã¹ãã³ã°ããŒãã®ã¿ã䜿çšããIPã¢ãã¬ã¹ãšåã¯ã©ã€ã¢ã³ãã®ããŒãã䜿çšããŠãœã±ãããåºå¥ã
node.jsãµãŒããŒã§100äžãè¶
ããåæWebSocketæ¥ç¶ãå®çŸããçŽç²ãªsocket.ioãµãŒããŒã§100Kãè¶
ããæ¥ç¶ãå®çŸãããšäž»åŒµãã人ã
ã®å ±åãèŠãŠããŸããã ãããã£ãŠãå°ã調æŽããã ãã§ãååãªCPUãã¯ãŒãšRAMãããã°ãåäžããŒãsoket.ioïŒfeathers.js;ïŒïŒãµãŒããŒã§çŽ50kã®åæWebãœã±ããæ¥ç¶ãå®çŸã§ããå¯èœæ§ããããŸãã
ããã¯èšã£ãŠããsocket.ioãšPrimusã®äž¡æ¹ã§æ©èœããchannelsã·ã¹ãã ãfeathers.jsã«å«ããããšã¯ãç§ãæãæ¬åœã®ã¡ãªããã§ãïŒããã©ãŒãã³ã¹ã®åäžãããçŸåšãã£ã«ã¿ãŒãå®çŸ©ããå¿
èŠãããå€ãã®äœ¿çšäŸãããããç°¡åã«ãªããŸãïŒ ïŒ
ããçŸå®çãªã¢ããªã®åçŸå¯èœãªãã³ãããŒã¯ã§äœãå¯èœããæ¬åœã«ç¥ãããšãã§ãããšæããŸãð
次ã«ãããããã¹ãŠã«å¯Ÿããå®éã®APIææ¡ã«ã€ããŠèª¬æããŸãã
ã€ãã³ãã®çºè¡ãšãã£ã«ã¿ãªã³ã°ãããã¯ã«ãªãã¡ã¯ã¿ãªã³ã°ããŸãã @ekryskiãšç§ã¯åã«ããã«ã€ããŠè©±ããŸããã åºæ¬çã«ããã§ã¶ãŒããã¯ã¯ã³ã¢ã®äŸåé¢ä¿ã«ãªããã€ãã³ãã®çºè¡ã¯åžžã«æåŸã«å®è¡ãããããã¯ã«ãªããŸãã
æååã§ããŒèšå®ãããããã£ãã«ãã«æ¥ç¶ïŒã€ãã³ããšããã¿ãŒïŒãåºå®ã§ããapp.channel
ã¡ãœãããè¿œå ããŸãã
const updateChannels = (connection, user) => {
// A channel just for this user
app.channel(user._id, connection);
// For each user room add the socket to the room channel
user.rooms.forEach(roomId => app.channel(`rooms/${roomId}`, connection));
// Register the socket in the `company/<company_id>` channel
app.channel(`company/${user.company_id}`, connection);
};
app.on('connection', updateChannels);
app.on('login', updateChannels);
ããã§æ³šæãå¿ èŠãªã®ã¯ããŠãŒã¶ãŒãæŽæ°ããããšãã«ãããã®ãã£ãã«ã®åæãç¶æããæ¹æ³ãèŠã€ããããšã§ããããšãã°ãæ¥ç¶ãããŸãŸéšå±ãé¢ãããªã©ã§ãã
ã€ãã³ããã£ã«ã¿ãªã³ã°ãå€æŽããŠãO(1)
ïŒååŸã§ããŸãã
app.service('messages').filter('eventname', (message, connections, hook) => {
// Just dispatch to one user
if(message.isPrivate) {
return connections.channel(message.receiver_id);
}
// The message room channel
return connections.channel(`rooms/${message.room_id}`);
// EVERYBODY!
return connections;
// Filter connections manually, e.g. if the connection user and message user are friends
return connections.filter(connection => connection.user.friends.indexOf(message.user) !== -1);
});
ããã¯é倧ãªå€æŽã«ãªããŸãã ã€ãã³ããã£ã«ã¿ãŒã¯ããã£ã¹ããããããŠããããŒã¿ãå€æŽã§ããªããªããŸãã ã€ãã³ãããŒã¿ã®å€æŽã¯ã hook.result
ãŸãã¯hook.dispatch
ãããããèšå®ããããã¯ã§å®è¡ã§ããŸãïŒïŒ376ãé¢é£ããŠããŸãïŒã ãã§ãŒã³ã䜿çšããŠæ¥ç¶ãçµã蟌ãããšã¯å¯èœã§ããããã£ãã«ãè¿ããšãåžžã«ãã®ãã£ãã«å
ã®ãã¹ãŠã®æ¥ç¶ãè¿ãããŸãã ãã®éãã€ãã³ããã£ã«ã¿ãŒãå¿
é ã«ããããšãã§ããŸãã
ç§ã«ã¯è¯ãããã§ãã
ãã£ãã«ã®åæãç¶æããæ¹æ³ã«ã€ããŠã ãããæ
åœããã®ã¯éçºè
ã®è²¬ä»»ã ãšæããŸãã èªåã§ãã£ãŠã¯ãªããŸããïŒãŠãŒã¶ãŒãåæããå Žåãé€ããŸãããã®å Žåããã¡ããããŠãŒã¶ãŒã®æ¥ç¶ã¯ããããå«ãŸããŠããåãã£ãã«ããèªåçã«åé€ãããŸãïŒã ãããã£ãŠãããçš®ã®app.unchannel()
é¢æ°ãããå Žåã¯ãããããµãŒãã¹ããã¯ã«åŒã³åºãããšãã§ããã¯ãã§ãã ããããã°ããŠãŒã¶ãŒãããããã¢ããããŒããŠãŒã¶ãŒãµãŒãã¹ãªã©ããéšå±ãé¢ããå Žåã app.unchannel(
Rooms / $ {roomId} , connection)
ãåŒã³åºããŠãéšå±ããæ¥ç¶ãåé€ããå¿
èŠããããŸãïŒ sïŒåœŒãå»ã£ãïŒãŸãã¯ãããŠãŒã¶ãŒããµãŒãã¹ãä»ããŠåŠçããã®ã§ã¯ãªããéšå±ãããå Žåã¯ãéšå±ããµãã¹ã¯ã©ã€ã/ãµãã¹ã¯ã©ã€ã解é€ããããã«äœ¿çšããããµãŒãã¹ã§ãã®é¢æ°ãçŽæ¥åŒã³åºãããšãã§ããŸãïŒã
çŽ æŽããããã£ã¹ã«ãã·ã§ã³ã®äººãã¡ãš@ramsestomãããã¯ãªãããŠãããŠããããšãïŒ @dafflç§ã¯ããªããããã§ææ¡ãããã¹ãŠã«åæããŸãð¯ãããŠ@ramsestomããã確å®ã«é²è¡ããã«ã€ããŠãã³ãããŒã¯ãæ¯æŽããããšæããŸãã åã ã®ã¹ã¿ã³ãã¢ãã³ãµãŒãã¹ã§ãŸãšãããªããžããªã®äŸãããã€ããããŸããå®äºãããããããã®ãã³ãããŒã¯ãååŸããã®ã¯çŽ æŽãããããšã§ãã ð
ããã§æ³šæãå¿ èŠãªã®ã¯ããŠãŒã¶ãŒãæŽæ°ããããšãã«ãããã®ãã£ãã«ã®åæãç¶æããæ¹æ³ãèŠã€ããããšã§ãã
åæããŸãã ããã§å€§å£°ã§èããŠã¿ããšããã®ãã£ãã«ç®¡çã¯ãµãŒãã¹/ã¢ããªã®ã¯ã©ã¹ã¿ãŒå šäœã§ã©ã®ããã«æ©èœããã®ã§ããããã ããã¯äœããå€ããã€ããã§ããïŒ
ãã£ã³ãã«ããµããŒãããããã«feathers-syncãé©å¿ãããå¿ èŠããããŸããïŒ ç§ã®äºæã¯ã€ãšã¹ã§ãã
ç§ã®æšæž¬ã§ã¯ãfeathers-syncã¯ãã£ãã«ããµããŒãããããã«é©åãããå¿
èŠããããŸãããããããããã»ã©é£ããã¯ãªãã§ãããã å®éãåäžã®ã€ãã³ãããã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã«äŒæãã代ããã«ããã¹ãŠã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ã«ïŒã€ãã³ã+ chanel_IDïŒãäŒæããå¿
èŠããããŸãïŒãããã£ãŠãæž¡ãããããŒã¿ã«chanel_IDãã©ã¡ãŒã¿ãŒãè¿œå ããããã«feathers-syncãé©å¿ãããã ãã§ããã¯ã©ã¹ã¿ããŒãéïŒã
å®éãã·ã£ãã«ã¯åé¡ãªãã¯ã©ã¹ã¿ãŒã®ããŒãéã§åå²ã§ããŸãã ããŒãã¯ã©ã¹ã¿ãŒéã§äžè²«ããã·ã£ãã«ã®ã©ãã«ä»ããç¶æãããã®ããŒãã«æ¥ç¶ãããæ¥ç¶ã®ã¿ãããŒãã¯ã©ã¹ã¿ãŒã«èšå®ããå¿
èŠããããŸãïŒãããã£ãŠãã€ãã³ããæ¥ç¶ãc1ãïŒ=ã¯ã©ã€ã¢ã³ã1ããïŒãã·ã£ãã«ãAãã«è¿œå ããããã«èŠæ±ããå Žåãããšãã°ãæ¥ç¶c1ãåŠçããã¯ã©ã¹ã¿ãŒããŒãã®ã¿ãèŠæ±ãæºãããä»ã®ããŒãã¯c1æ¥ç¶ãæ¥ç¶ãããŠããªãããããããé»ã£ãŠç¡èŠããŸãã
ãããã£ãŠãåäžããŒãã¢ããªã®æ¥ç¶c1ãc2ãc3ãc4ãå«ããã£ãã«ãAãã¯ãããŒãn1ã®æ¥ç¶c1ãc2ãå«ããã£ãã«ãAãããã³ããŒââãn2ã®æ¥ç¶c3ãc4ãå«ããã£ãã«ãAãã«ãªããŸãã 次ã«ãã€ãã³ããã·ã£ãã«Aã«äŒæããå¿
èŠãããããšãããã£ãŠããéãããã®ã·ã£ãã«ã®ãã¹ãŠã®æ¥ç¶ãåãããŒãã«æ¥ç¶ãããŠããããè€æ°ã®ããŒãã«åå²ãããŠãããã«éãã¯ãããŸããã
ç§ã¯äœãã足ããªããããããŸããããããã¯ãããŸããïŒ ãã£ã«ã¿ã¯ããã®ãµãŒããŒäžã®ãã¹ãŠã®_connected_ã¯ã©ã€ã¢ã³ãã«å¯ŸããŠå®è¡ãããŸãã åãã¢ããªãã¹ã±ãŒãªã³ã°ããã ãã®å Žåã§ãããã¹ãŠã®æ¥ç¶ã¯æ£ãããã£ãã«ã«é 眮ãããã€ãã³ãã¯äžèŽããæ¥ç¶ãããã¯ã©ã€ã¢ã³ãã«ã®ã¿ãã£ã¹ããããããŸãã
ãµãŒãã¹ã€ãã³ã以å€ã®ãã®ãåæããå¿ èŠã¯ãªããšæããŸããããã¯feathers-syncããã§ã«è¡ã£ãŠããããšã§ãã
ããã¯ãfethers-syncãçŸåšã©ã®ããã«æ©èœããŠãããã«ãã£ãŠç°ãªããŸãã ãªã¯ãšã¹ããµãŒãã¹ã€ãã³ããåæããŸããããããšããµãŒãã¹ã€ãã³ãã«å¿çããŸããïŒ ïŒdataãparamsïŒãå«ãcreate()
ãªã¯ãšã¹ããããå Žåããã¹ãŠã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ã«äŒæãããïŒãããŠããããã§åŠçãããïŒãªã¯ãšã¹ãã§ããïŒ ãããšãããã¹ãŠã®ã¢ããªãã£ã¹ãããã£ãŒã«äŒéãããã®ã¯ããã®ãªã¯ãšã¹ãïŒãªã¯ãšã¹ããåŠçãããåŸã«ã¯ã©ã€ã¢ã³ãã«è¿ããããããã¹ïŒã®çµæã§ããïŒ
ç§ã¯ããã2çªç®ã®ãªãã·ã§ã³ã ãšæã£ãŠããã§ãããïŒããã§ãªããã°ãããšãã°ããŒã¿ããŒã¹ã®ãšã³ããªãäœæãŸãã¯æŽæ°ãããµãŒãã¹ãªã¯ãšã¹ãã®å Žåããã¹ãŠã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ããªã¯ãšã¹ãã€ãã³ããåŠçãããšãåã¢ããªã€ã³ã¹ã¿ã³ã¹ããããå®è¡ããããšãããããåé¡ãçºçããŸãã ãïŒ
ç§ãç解ããããã«ã矜ã®ãã€ãã©ã€ã³ã¯ããã§ãïŒ
----------------------ãªã¯ãšã¹ããåä¿¡ããããŒãã€ã³ã¹ã¿ã³ã¹ã§ã®ã¿å®è¡ãããŸã
ã€ãã³ãã®ãªã¯ãšã¹ã
ããã¯ã®å
ãµãŒãã¹æ¹æ³èªäœ
ããã¯ã®åŸ
çµæã€ãã³ã
------------------ <-ããã¯ããã®æç¹ã§ãfeathers-syncã䜿çšããŠããŒãéã§åæãããŸãã
------------------åããŒãã€ã³ã¹ã¿ã³ã¹ã§å®è¡
ãã£ã«ã¿
çºè»ä¿
ãããfeathers-syncãšåæãããçµæã€ãã³ãã§ããå Žåã¯ãããããå€æŽããå¿ èŠããããŸãã çŸåšã®ãã£ã«ã¿ãŒã®å®è£ ã§ã¯ããã¹ãŠã®æ¥ç¶ãå埩åŠçããŠãããããåããŒãã®åæ¥ç¶ã§ãã£ã«ã¿ãŒãå®è¡ã§ããŸãã ãããã£ãŠããã£ã¹ãããããã€ãã³ã以å€ã®ãã®ãæäŸããå¿ èŠã¯ãããŸããã ãã ãããã£ãã«ãããå Žåã¯ãéžæããæ¥ç¶ã»ããã§ã€ãã³ãããã£ã¹ãããããå¿ èŠããããŸãã ïŒäžéšã®ãã¹ãé¢æ°ã«åºã¥ããŠïŒãã®ã»ãããéžæããããã«ãã£ã«ã¿ãŒã䜿çšããªããªã£ããããã€ãã³ããšãšãã«ãã£ãã«æ å ±ãæž¡ããŠãããŒãã®ã©ã®æ¥ç¶ã§ã€ãã³ããçºè¡ããå¿ èŠãããããç¥ãå¿ èŠããããŸãïŒãã ãããã®ãã£ãã«æ å ±ã¯ãã¡ãããã€ãã³ããªããžã§ã¯ãèªäœã®ããããã£ãšããŠçµ±åãããŸãããã®å ŽåãçŸåšè¡ãããŠããããã«ãeventããªããžã§ã¯ããæž¡ãããã£ã¹ãããã£ã§ã€ãã³ãã®ãã®ãchannelãããããã£ã調ã¹ãŠãé©åãªæ¥ç¶ã§åºåããå¿ èŠããããŸããããã¯ããªãããããã©ã®ããã«å®è£ ãããã«ãããŸãïŒã
ããã¯ãããã«å¯ŸããŠéåžžã«ãŸããªãå®è£ ããããã®ã®çŸåšã®æçµææ¡ã§ãã
socket.feathers
ãªããPrimusã®å Žåã¯socket.request.feathers
app.channels
ã app.channel(... names)
æå®ãããååã®æ°ãããã£ãã«ãäœæããŠè¿ãããè€æ°ã®ãã£ãã«ã1ã€ã«çµåããŸã
// A list of all channel names
app.channels
// A channel only for admins
app.channel('admins')
// A channel for message room with id 2
app.channel('rooms/2')
// A combined channel for admins and rooms/2
app.channel('admins', 'rooms/2');
// All channels
app.channel(app.channels)
.join(connection)
ãš.leave(connection)
ããã£ãã«ã§åŒã³åºããŠãæ¥ç¶ããã£ãã«ã«åå ããããããã£ãã«ããé¢è±ãããã§ããŸãã
// Join the admin channel
app.channel('admins').join(connection);
// Leave the admin channel
app.channel('admins').leave(connection);
// Leave a channel conditionally
app.channel('admins', 'rooms').leave(connection => connection.userId === user._id);
// Leave all room channels
const roomChannels = app.channels.filter(channel => channel.indexOf('room/') === 0);
app.channel(roomChannels).leave(connection);
// Leave all channels
app.channel(app.channels).leave(connection);
ã€ãã³ããã£ã«ã¿ãŒã¯ãã€ãã³ãã®éä¿¡å ã®ãã£ãã«ã決å®ããŸãã è€æ°ã®ã€ãã³ããã£ã«ã¿ãŒãç»é²ããŠãè€æ°ã®ãã£ãã«ã«ããŒã¿ãéä¿¡ã§ããŸãã æ¥ç¶ãè€æ°ã®ãã£ãã«ã«ããå Žåãã€ãã³ãã¯1åã ãéä¿¡ãããŸãïŒããŒã¿ãåãã§ããå Žåããã®æ¹æ³ãç解ããå¿ èŠãããå ŽåããããŸãïŒã
// Handle a certain event for all services
app.dispatch('eventname', (message, hook) => {
// Just dispatch to one user
if(message.isPrivate) {
return app.channel(message.receiver_id);
}
// Returning falsy or nothing will do nothing
});
// Handle a certain event for a specific service
app.dispatch('servicename', 'eventname', (message, hook) => {
// Just dispatch to one user
if(message.isPrivate) {
return app.channel(message.receiver_id);
}
// Returning falsy or nothing will do nothing
});
// Send to a certain room
app.dispatch('messages', 'eventname', (message, hook) => {
return app.channel(`rooms/${message.roomId}`);
});
// EVERYONE
app.dispatch('messages', 'eventname', (message, hook) => {
return app.channel(app.channels);
});
// Filter connections manually, e.g. if the connection user and message user are friends
// This works similar to the old event filters
app.dispatch('messages', 'eventname', (message, hook) => {
return app.channel(app.channels).filter(connection => connection.user.friends.indexOf(message.user) !== -1);
});
泚ïŒã«ã¹ã¿ã ã€ãã³ãã®hook
ãªããžã§ã¯ãã«ã¯ã { service, app, path, event }
ãå«ãŸããŸãã
ãŸããã©ã®ããŒã¿ã䜿çšããŠæ±ºå®ããããšãã§ããŸãã
app.dispatch('messages', 'eventname', (message, hook) => {
const modifiedMessage = cloneAndModify(message);
return app.channel(`rooms/${message.roomId}`, `rooms/general`).send(modifiedMessage);
});
ãŠãŒã¶ãŒãŸãã¯ãã°ã€ã³ã¹ããŒã¿ã¹ãå€æŽããããšãã«ãã£ãã«ãæŽæ°ããæ¹æ³ã®äŸïŒ
app.on('connection', connection => {
app.channel('anonymous').join(connection);
});
app.on('login', (payload, meta) => {
const connection = meta.connection;
// Connection can be undefined e.g. when logging in via REST
if(connection) {
// Leave anonymous channel first
app.channel('anonymous').leave(connection);
// Get the user object and stick into channels
app.service('users').get(payload.userId).then(user => {
// A channel just for this user
app.channel(`users/${user._id}`).join(connection);
// Put user into the chat rooms they joined
user.rooms.forEach(roomId => {
app.channel(`rooms/${roomId}`).join(connection);
});
});
}
});
app.service('users').on('patched', user => {
// Find all connections belonging to this user
app.channel(app.channels).leave(connection => connection.user._id === user._id)
// Re-add the user to their channels
// A channel just for this user
app.channel(`users/${user._id}`).join(connection);
// Put user into the chat rooms they joined
user.rooms.forEach(roomId => {
app.channel(`rooms/${roomId}`).join(connection);
});
});
connection
ãªããžã§ã¯ãã¯ããã¯ã§å©çšã§ããŸããïŒ ããã¯ã§ãã£ãã«ã¡ã³ããŒã·ããã管çããæ¹æ³ãå¿
èŠã«ãªããŸãã ãœã±ããæ¥ç¶ã®ããã¯ãªããžã§ã¯ãã«context.connection
ãå«ããå¿
èŠããããŸããïŒ
// Join the admin channel
app.channel('admins').join(connection);
// Leave the admin channel
app.channel('admins').leave(connection);
ãœã±ããã®connection
ãªããžã§ã¯ãã¯ããµãŒãã¹ã¡ãœããåŒã³åºãparams
ããŒãžããããã®ã§ãïŒãã ããåããªããžã§ã¯ãã§ã¯ãããŸããïŒã ããã¯ã§äœã®ããã«æ¥ç¶ããå¿
èŠããããŸããïŒ
ç§ãèŠãããšãã§ãã1ã€ã®ããšã¯ãã¡ãœãããåŒã³åºãããŠãŒã¶ãŒã«ã€ãã³ããéä¿¡ããªãæ¹ãç°¡åã«ãªããšããããšã§ãããç§ãã¡ã¯åžžã«ããããªãããã«ã¢ããã€ã¹ããŠããŸããã
ããšãã°ããŠãŒã¶ãŒããã£ããã¢ããªã§æ°ããéšå±ãäœæããå Žåããã£ãã«ãäœæãããã®éšå±ã®ãã£ãã«ãžã®ãŠãŒã¶ãŒã®æ¥ç¶ã«åå ããããã®ã³ãŒãã¯ã©ãã«ãããŸããïŒ
ããã¯è¯ã質åã§ãã ããã©ã«ãã§ã¯ãçŸåšãã£ã«ã¿ãŒãããŒãããã³èšå®ããŠãããŠãŒã¶ãŒãµãŒãã¹ã»ããã¢ãããã¡ã€ã«ã«ããã€ãã®ãã³ãã¬ãŒããé 眮ã§ã
æ¥ç¶ããŒã¿ã¯paramsãšåãã§ãããããããã¯ã§ãã£ãã«ã¡ã³ããŒã·ãããå®è¡ã§ããããã«ããã®ã¯å°ãé£ãããããããŸããããããã¯ã§ãããå®è¡ããã®ã¯éåžžã«èªç¶ãªããšã®ããã§ãã
ãŸã 説æããŠããªããã1ã€ã®ããšã¯ãããã¯ã§ãœã±ããã€ãã³ããçºè¡ã§ããªãçç±ã§ãã ããã¯ã§app.channel('admins').dispatch({...})
ã§ãããšããã§ããã ãªãããŸããããªãã®ããšãã£ããã£ãŠããŸããããèãåããŸããã§ããã
ããã¯å
ã®ãã£ãã«ã¡ã³ããŒã·ããã®å Žåã解決çã¯ããŠãŒã¶ãŒããã°ã€ã³ãŸãã¯ãã°ã¢ãŠããããã³ã«ããã§ã¶ãŒã¢ããªã®ã«ãŒãã®ã©ããã«{user_id => connection}ã®åæãããèŸæžããããä¿æããããšã§ãã
ãã®ããã«ãjoinïŒïŒãšleaveïŒïŒã¯ãæ¥ç¶ãªããžã§ã¯ããããã¯ã«çŽæ¥æž¡ãããšãªããmap [params.user.id]ã䜿çšããŠããã¯ã®å
éšããåŒã³åºãããšãã§ããŸãã
ã¢ããªã®ä»»æã®æç¹ã§ã«ã¹ã¿ã ã€ãã³ãïŒãµãŒãã¹ã€ãã³ãã ãã§ãªããåºæ¬çã«ã«ã¹ã¿ã ããŒã¿ã䜿çšããã«ã¹ã¿ã ã€ãã³ãïŒããã£ã¹ãããããå¯èœæ§ã«ã€ããŠã¯ã app.channel('admins').dispatch({data to dispatch})
ãããªããšãã§ãããšçŽ æŽããããšæããŸããããã¯
ãŸã 説æããŠããªããã1ã€ã®ããšã¯ãããã¯ã§ãœã±ããã€ãã³ããçºè¡ã§ããªãçç±ã§ãã ããã¯ã§app.channelïŒ 'admins'ïŒãdispatchïŒ{...}ïŒãã§ãããšäŸ¿å©ã§ãã ãªãããŸããããªãã®ããšãã£ããã£ãŠããŸããããèãåããŸããã§ããã
åæããŸããã ããã¯ã@ dafflã§ãå°ããããŸãã§ãã ãããã§ããããã«ãªããããšæããŸãã
ããšãã°ããŠãŒã¶ãŒããã£ããã¢ããªã§æ°ããéšå±ãäœæããå Žåããã£ãã«ãäœæãããã®éšå±ã®ãã£ãã«ãžã®ãŠãŒã¶ãŒã®æ¥ç¶ã«åå ããããã®ã³ãŒãã¯ã©ãã«ãããŸããïŒ
@ramsestomãææ¡ãããããªããšãããå¿ èŠããããããããŸããã ãœã±ããIDãŸãã¯ãã®ãœã±ããã«æ¥ç¶ããããšã³ãã£ãã£IDïŒã€ãŸããŠãŒã¶ãŒïŒã®ããããã«ãã£ãŠãœã±ããæ¥ç¶ãååŸããããã®äŸ¿å©ãªã¡ãœãããå¿ èŠã«ãªããããããªããšèããŠããŸãã å®è¡å¯èœã§ãããè€æ°ã®ã¢ããªã€ã³ã¹ã¿ã³ã¹ãšå€æ°ã®ãœã±ãããè¡ãæ¥ããå Žåãããã¯å°ãåä»ã«ãªãå§ããå¯èœæ§ããããŸãã
ãããã @ marshallswainã®ãŠãŒã¹ã±ãŒã¹ãã«ããŒããããã«ããã«ã€ããŠããå°ãèããã®ã§ãããã¯2ã€ã®APIåŒã³åºãã§ã¯ãªãå¯èœæ§ããããŸããïŒ
ããã«ã€ããŠããå°ãèããŠã¿ãŠãã ããã2ã€ã®APIåŒã³åºãã¯æ©èœããŸãããåå ã§ãããã£ãã«ãç¥ã£ãŠããå Žåã«éããŸãã åºæ¬çã«ããŠãŒã¶ãŒã¯èªåèªèº«ããã£ã³ãã«ã«è¿œå ããããšããã§ããŸããã ãã£ã³ãã«ã«å¥ã®ãŠãŒã¶ãŒãè¿œå ã§ããSlackã®ãããªããšããããã®ãªããããã¯äžå¯èœãããããŸãã...
ãã®å Žåã2ã€ã®éžæè¢ããããšæããŸãã
ãŠãŒã¶ãŒãããªãã®ç¥ããªããã£ã³ãã«ã«ããªããè¿œå ããŸãã å®éã«è¿œå ãããã®ã§ã¯ãªãããã£ãã«ãžã®æåŸ ãåãåãããã£ãã«ã«ãåå ãããããšã確èªããŸãã ãããã£ãŠãããªãã¯ãŸã èªåèªèº«ãè¿œå ããŠããŸãã
ãŠãŒã¶ãŒãå®éã«ããªãããã£ã³ãã«
éèã«å°ãå ¥ã...
ãã®ãããªããšã¯ã user id -> connection
ãããã³ã°ããªããŠãã @ dafflãææ¡ããææ¡ã§æããŸãã ããã¯ããã¬ãªãªãŒã¹ãè¡ãããããããã€ãã®ã¢ããªã®è£œå/ã¹ããŒãžã³ã°ã«å
¥ããŠããšããžã±ãŒã¹ãã©ãã«ãããã確èªããã®ãè¯ãçç±ã§ããããŸãã
ãã¶ãããããã³ã°ãªãã§ããã®æåã®ã«ãããè¡ããŸããïŒ ã©ãæããŸããïŒ
åæããŸããã ããã¯ã@ dafflã§ãå°ããããŸãã§ãã ãããã§ããããã«ãªããããšæããŸãã
@marshallswainãš@ekryskiãããã«ã€ããŠèšåããã®ã§ã ããã¯ã§ç¬èªã®ïŒå Žåã«ãã£ãŠã¯å¥ã®ïŒãµãŒãã¹ã«ã€ãã³ããçºè¡ããããšã¯åé¡ãªããšæããŸãããæ¥ç¶ãããã¯ã©ã€ã¢ã³ããŸãã¯ãã£ãã«ã«ããã¯ããçŽæ¥ããŒã¿ãéä¿¡ããããšã¯ã§ã
ãµãŒãã¹ã¯ãã©ã³ã¹ããŒãã«äŸåããªãå¿
èŠããããšèšãã®ãšåãããã«ããµãŒãã¹èªäœïŒããã³ãã®ããã¯ïŒã¯ãå®è¡äžã®ãµãŒããŒã«èª°ãæ¥ç¶ããŠããããå¿é
ããå¿
èŠããªãããã«ããæ¥ç¶ãèªèããªããå¿
èŠããããšæããŸãã ç§ãã¡ã¯ãŸã ãµãŒãã¹ã«app.service('myservice').dispatch
ãä»ããŠãã£ã«ã¿ãŒ/ãã£ã¹ãããã£ãŒãç»é²ããŠããã®ã§ãããã¯å®å
šã«ã¯çå®ã§ã¯ãªãããšãç解ããŠããŸãããå°ãªããšãããã¯ãã®ç¹å®ã®ç®çã®ããã ãã§ãããããã¯ã¯äœã§ãã§ããŸãã
ããšãã°ããŠãŒã¶ãŒããã£ããã¢ããªã§æ°ããéšå±ãäœæããå Žåããã£ãã«ãäœæãããã®éšå±ã®ãã£ãã«ãžã®ãŠãŒã¶ãŒã®æ¥ç¶ã«åå ããããã®ã³ãŒãã¯ã©ãã«ãããŸããïŒ
ããã¯æ£ç¢ºã«ã¯äœã§ã¯ãããŸãã
app.service('users').on('patched', user => {
// Leave all channels belonging to a user
app.channel(app.channels).leave(connection => connection.user._id === user._id)
// Re-add the user to their channels
// A channel just for this user
app.channel(`users/${user._id}`).join(connection);
// Put user into the chat rooms they joined
user.rooms.forEach(roomId => {
app.channel(`rooms/${roomId}`).join(connection);
});
});
ãŠãŒã¶ãŒãéšå±ã«åå ãããšãã«patched
åãåããšä»®å®ããŸããïŒ
@dafflãããããŸãããã ããã ð
@daffl @ekryski @marshallswainç§ã¯ãã®ã·ããªãªãæ£ç¢ºã«è§£æ±ºããŸããããåçãã§ã¶ãŒãµãŒãã¹ã䜿çšãããšãã£ãšç°¡åã«ãªããããããŸããã
ã¯ã©ã€ã¢ã³ãã®/ channel / nameã®ãããªã«ã¹ã¿ã åå空éã«ã«ã¹ã¿ã ã¡ãã»ãŒãžãµãŒãã¹ãç»é²ãããµãŒãã¹ãäœæããŸãããåã/ channel / nameãµãŒãã¹ã«æ¥ç¶ããã ãã§ãã¡ãã»ãŒãžã³ã°ãå¯èœã«ãªããŸãã
ãªã¢ã«ã¿ã€ã ã䜿çšãããã倧ããªå±éã§ãç°ãªãéšå±ã®ç°ãªãããã€ã¹ãæ¥ç¶ããããã«ããã䜿çšããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸã
ããã¯ã1ç§ãããçŽ1åã®ã¡ãã»ãŒãžãç°¡åã«åŠçãããkafkaãããã€ã¡ã³ãã®ãããªç°ãªãããã¯ã¹ã«ãåŸã§åãã£ãã«åãéä¿¡ã§ããããšãç¥ã£ãŠããã®ã§ãæãæ¡åŒµæ§ããããŸãã
ãã®åé¡ã¯ãã¯ããŒãºãããåŸãæè¿ã®ã¢ã¯ãã£ããã£ããªããããèªåçã«ããã¯ãããŠããŸãã é¢é£ãããã°ã«ã€ããŠã¯ããã®åé¡ãžã®ãªã³ã¯ãå«ãæ°ããåé¡ãéããŠãã ããã
æãåèã«ãªãã³ã¡ã³ã
ããçŸå®çãªã¢ããªã®åçŸå¯èœãªãã³ãããŒã¯ã§äœãå¯èœããæ¬åœã«ç¥ãããšãã§ãããšæããŸãð
次ã«ãããããã¹ãŠã«å¯Ÿããå®éã®APIææ¡ã«ã€ããŠèª¬æããŸãã
1ïŒããã¯ãšããŠã®ã€ãã³ããšã€ãã³ããã£ã«ã¿ãªã³ã°
ã€ãã³ãã®çºè¡ãšãã£ã«ã¿ãªã³ã°ãããã¯ã«ãªãã¡ã¯ã¿ãªã³ã°ããŸãã @ekryskiãšç§ã¯åã«ããã«ã€ããŠè©±ããŸããã åºæ¬çã«ããã§ã¶ãŒããã¯ã¯ã³ã¢ã®äŸåé¢ä¿ã«ãªããã€ãã³ãã®çºè¡ã¯åžžã«æåŸã«å®è¡ãããããã¯ã«ãªããŸãã
2ïŒapp.channel
æååã§ããŒèšå®ãããããã£ãã«ãã«æ¥ç¶ïŒã€ãã³ããšããã¿ãŒïŒãåºå®ã§ãã
app.channel
ã¡ãœãããè¿œå ããŸããããã§æ³šæãå¿ èŠãªã®ã¯ããŠãŒã¶ãŒãæŽæ°ããããšãã«ãããã®ãã£ãã«ã®åæãç¶æããæ¹æ³ãèŠã€ããããšã§ããããšãã°ãæ¥ç¶ãããŸãŸéšå±ãé¢ãããªã©ã§ãã
3ïŒæŽæ°ãããã€ãã³ããã£ã«ã¿ãªã³ã°
ã€ãã³ããã£ã«ã¿ãªã³ã°ãå€æŽããŠã
O(1)
ïŒååŸã§ããŸããããã¯é倧ãªå€æŽã«ãªããŸãã ã€ãã³ããã£ã«ã¿ãŒã¯ããã£ã¹ããããããŠããããŒã¿ãå€æŽã§ããªããªããŸãã ã€ãã³ãããŒã¿ã®å€æŽã¯ã
hook.result
ãŸãã¯hook.dispatch
ãããããèšå®ããããã¯ã§å®è¡ã§ããŸãïŒïŒ376ãé¢é£ããŠããŸãïŒã ãã§ãŒã³ã䜿çšããŠæ¥ç¶ãçµã蟌ãããšã¯å¯èœã§ããããã£ãã«ãè¿ããšãåžžã«ãã®ãã£ãã«å ã®ãã¹ãŠã®æ¥ç¶ãè¿ãããŸãã ãã®éãã€ãã³ããã£ã«ã¿ãŒãå¿ é ã«ããããšãã§ããŸãã