2015-11-18 21 views
6

Node.jsを使用してメディアアップロードマイクロサービスを作成しています。このサービスは、アップロードのバイナリデータをバッファに取り込み、次にS3 npmパッケージを使用してS3バケットにアップロードすることによって機能します。私はS3にアップロードされたデータの量を示すそのパッケージにあるeventEmitterを使用しようとしており、アップロードを行っているクライアントにそれを送り返す(アップロードの進行状況を見ることができるように)。私はsocket.ioを使ってこの進捗データをクライアントに送り返しています。Socket.ioがクライアントのユニークなルームにデータを送信できません

私が抱えている問題は、socket.ioの.emitイベントがアップロードを開始したクライアントだけでなく、接続されているすべてのクライアントにアップロードの進行状況データを送信することです。私が理解しているように、ソケットは 'connection'のデフォルトルームに接続します。これはクライアント側の 'id'によって反映されます。公式のドキュメントによると、socket.to(id).emit()を使用すると、そのクライアントにのみスコープされたデータを送信するはずですが、これは私のためには機能しません。

UPDATED例コード:

server.js:

var http = require('http'), 
users = require('./data'), 
app = require('./app')(users); 

var server = http.createServer(app); 

server.listen(app.get('port'), function(){ 
    console.log('Express server listening on port ' + app.get('port')); 
}); 

var io = require('./socket.js').listen(server); 

socket.js:

var socketio = require('socket.io'); 

var socketConnection = exports = module.exports = {}; 

socketConnection.listen = function listen(app) { 
    io = socketio.listen(app); 
    exports.sockets = io.sockets; 

    io.sockets.on('connection', function (socket) { 
     socket.join(socket.id); 
     socket.on('disconnect', function(){ 
      console.log("device "+socket.id+" disconnected"); 
     }); 
     socketConnection.upload = function upload (data) { 
     socket.to(socket.id).emit('progress', {progress:(data.progressAmount/data.progressTotal)*100}); 
    }; 
}); 
return io; 
}; 

s3upload.js:

var config = require('../config/aws.json'); 
var s3 = require('s3'); 
var path = require('path'); 
var fs = require('fs'); 
var Busboy = require('busboy'); 
var inspect = require('util').inspect; 

var io = require('../socket.js'); 
... 
var S3Upload = exports = module.exports = {}; 
.... 
S3Upload.upload = function upload(params) { 
// start uploading to uploader 
var uploader = client.uploadFile(params); 

uploader.on('error', function(err) { 
    console.error("There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection: ", err.stack); 
    res.json({responseHTML: "<span>There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection. Please refresh and try again.</span>"}); 
    throw new Error(err); 
}), 

uploader.on('progress', function() { 
    io.upload(uploader); 
}), 

uploader.on('end', function(){ 
    S3Upload.deleteFile(params.localFile); 
}); 
}; 

DEBUGを使用= *ノードmyapp.js、socket.io-paが表示されますRSERは、この情報に取って、それはそれをクライアントに放出されていない:私はこのコードの.TO部分を削除する場合

socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} +0ms 


socket.io-parser encoded {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} as 2["progress",{"progress":95.79422221709825}] +0ms 

はしかし、それは、すべてのクライアントにもかかわらず(クライアントにデータを送信しますこれは)まったく助けにはなりません。

io.sockets.on('connection', function(socket) { 
    socket.join(socket.id); 
    socket.emit('progress', {progress: (data.progressAmount/data.progressTotal)*100}); 
}); 

DEBUG = *ノードmyapp.js:

socket.io:client writing packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms 
    socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms 
    socket.io-parser encoded {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} as 2["progress",{"progress":99.93823786632886}] +0ms 
    engine:socket sending packet "message" (2["progress",{"progress":99.93823786632886}]) +0ms 
    engine:socket flushing buffer to transport +0ms 
    engine:ws writing "42["progress",{"progress":99.84186540937002}]" +0ms 
    engine:ws writing "42["progress",{"progress":99.93823786632886}]" +0ms 

私はここで間違って何をしているのですか?サーバーから特定のクライアントだけにイベントを送信する方法はありますか?

答えて

3

投稿したコードの2番目の例が正常に動作するはずです。そうでない場合は、さらにコードを投稿する必要があります。

私が理解しているように、ソケットは の 'connection'のデフォルトルームに接続します。これはクライアント側の 'id'によって反映されます。 公式の文書によると、socket.to(id).emit()を使用すると、 のデータはそのクライアントにのみスコープされますが、これは私のためには機能しません。

Socket.ioはそれよりかなり簡単です。以下のコードは、接続時に各クライアントに「hello」メッセージを送信します。

io.sockets.on('connection', function (socket) { 
    socket.emit('hello'); 
}); 

新しいクライアントが毎回ソケットに接続します。その特定のソケットをパラメータとして使用して、指定されたコールバックを実行します。 socket.idはそのソケットを識別するための一意のコードですが、実際にはその変数は必要ありません。上のコードでは、特定のsocketを介してメッセージを送信する方法を示しています。

Socket.ioもあなたには、いくつかの識別子(ルーム名)の下で、グループの接続をすることができますし、それらのすべてにメッセージをブロードキャストすることができるように、名前空間/部屋を作成するためにあなたにいくつかの機能を提供します。

io.sockets.on('connection', function (socket) { 
    // This will be triggered after the client does socket.emit('join','myRoom') 
    socket.on('join', function (room) { 
     socket.join(room); // Now this socket will receive all the messages broadcast to 'myRoom' 
    }); 
... 

今、あなたがすべきsocket.join(socket.id)はソケットがソケットIDを共有しないため意味が分かりません。

編集新しいコードで質問に答えるために:あなたがここに二つの問題を持っている

を、最初:io.sockets.on('connection',function (socket) {内部のことはすべて上記のコードで

socketConnection.upload = function upload (data) { 
     socket.to(socket.id).emit('progress', {progress:(data.progressAmount/data.progressTotal)*100}); 
    }; 

ノートは、クライアントが接続するたびに実行されますサーバーに送信します。最新のユーザーのソケットを指すように関数を上書きしています。

もう1つの問題は、ソケットとs3操作をリンクしていないことです。同じファイルにsocket.jss3upload.jsをマージする方法を示します。

var config = require('../config/aws.json'); 
var s3 = require('s3'); 
var path = require('path'); 
var fs = require('fs'); 
var Busboy = require('busboy'); 
var inspect = require('util').inspect; 
var io = require('socket.io'); 

var socketConnection = exports = module.exports = {}; 
var S3Upload = exports = module.exports = {}; 

io = socketio.listen(app); 
exports.sockets = io.sockets; 

io.sockets.on('connection', function (socket) { 

    socket.on('disconnect', function(){ 
     console.log("device "+socket.id+" disconnected"); 
    }); 

    socket.on('upload', function (data) { //The client will trigger the upload sending the data 
     /* 
      some code creating the bucket params using data 
     */ 
     S3Upload.upload(params,this); 
    }); 
}); 

S3Upload.upload = function upload(params,socket) { // Here we pass the socket so we can answer him back 
    // start uploading to uploader 
    var uploader = client.uploadFile(params); 

    uploader.on('error', function(err) { 
     console.error("There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection: ", err.stack); 
     res.json({responseHTML: "<span>There was a problem uploading the file to bucket, either the params are incorrect or there is an issue with the connection. Please refresh and try again.</span>"}); 
     throw new Error(err); 
    }), 

    uploader.on('progress', function() { 
     socket.emit('progress', {progress:(uploader.progressAmount/uploader.progressTotal)*100}); 
    }), 

    uploader.on('end', function(){ 
     S3Upload.deleteFile(params.localFile); 
    }); 
}; 
+0

基本的なコードアーキテクチャの詳細を表示するために質問を編集しました。別のルートからの情報をソケットに渡しているので、単に接続しても出力できません。 –

+0

あなたのコードに従って自分の答えを編集しました。同じファイルに 'socket.js'と' s3upload.js'をマージしました。それらを分離しておく必要がある場合は、S3をインポートするsocket.jsの依存関係を切り替えることをお勧めします。ソケットイベントに基づいて関数を呼び出す必要があるので、 's3upload.js'関数にアクセスする必要があります。 –

+0

私はあなたの提案で、私のアプリを再構築しようとします、助けてくれてありがとう。私のコードを移動するあなたの提案に基づいて関連する質問:ソケットを使用すると、ソケットハンドラを介してすべてのロジックが渡されるように、アプリケーションは本当にsocket.ioの周りに設計されるべきですか?それが本当であれば、ソケットを使用している間は専用ルートを書くことができないでしょうか? –

1

ドキュメントによると、すべてのユーザーはソケットIDで識別されるdefault roomに参加しているため、接続する必要はありません。それにもかかわらず、特定のソケットから名前空間の部屋に放したい場合は、その特定の部屋に接続されているすべてのクライアントにメッセージをブロードキャストしたい場合は、socket.broadcast.to(room).emit('my message', msg)を使用する必要があります。

+0

私は同じ問題です。パーサーは実行されていますが、エンジンまたは書き込みストリームは実行されていません。私はsocket.io 1.3.6を実行しているので、これらの関数は明確に定義されています。私のコードをもっと見れば助けになるか、それをさらにデバッグする方法があるかどうか私に教えてください。 –

1

すべての新しい接続が自動的にそのソケットに等しい名前を持つ部屋に接合されている:あなたは本当に分離それらを維持する必要がある場合には、S3の操作へのソケット接続をリンクするための別の方法を見つける必要があります。 .id。これを使用して特定のユーザーにメッセージを送信できますが、このユーザーによって初期化された接続にはsocket.idが関連付けられている必要があります。あなたは(それのためのアレイを有することにより、データベースを経由して、またはメモリに)この関連性をどのように管理するかを決定する必要がありますが、あなたはそれを持ってたら、ちょうど経由して進行状況の割合を送信:

それが与えていると私のコードの更新
socket.broadcast.to(user_socket_id).emit("progress", number_or_percent); 
関連する問題