处理Meteor中的EventEmitter事件?

时间:2013-12-02 22:16:22

标签: meteor

我正在尝试在Meteor中使用Asterisk Manager NPM module,但在处理发出的事件时遇到了困难。

此NPM模块与Asterisk Manager建立永久连接,并发出从Asterisk收到的任何事件。我已经设法修补代码,以便它在Meteor中运行。它连接到Asterisk,发出事件,我可以将它们记录到控制台,但是一旦我尝试对数据执行某些操作,比如将其插入到集合中,我会收到以下错误:

错误:流星代码必须始终在光纤内运行。尝试使用Meteor.bindEnvironment包装传递给非Meteor库的回调。

我如何克服这个问题?谢谢。

服务器端代码:

var ami = new AsteriskManager( { username: 'meteor', password: '123456' } );

ami.on('ami_data', function(data){
    console.log(data); // <- this works fine
    // the following causes the error
    EventsLog.insert({ timestamp: (new Date()).getTime(), 
                       data: data});
});

ami.connect(function(){});//creates a socket connection and sends the login action

修补后的npm模块代码:

var util = Npm.require('util');
var events = Npm.require('events').EventEmitter;
var net = Npm.require('net');


var AsteriskConstructor = function AsteriskManager(params){
    params = params || {};

    this.net = net;

    this.CRLF = "\r\n";
    this.END = "\r\n\r\n";
    this.buffer = "";

    this.port = params.port || 5038;
    this.host = params.host || 'localhost';
    this.username = params.username || 'username';
    this.password = params.password || 'password';
    this.enable_debug = params.debug || false;
    this.reconnect = params.reconnect || false;
    this.reconnect_after = params.reconnect_after || 3000;
    this.events = (params.events != undefined ? params.events : true);
    this.identifier = params.identifier || false;
    this.ami_encoding = params.ami_encoding || 'ascii';
};
AsteriskManager = AsteriskConstructor;

util.inherits(AsteriskManager, events);

AsteriskManager.prototype.connect = function(connect_cb, data_cb){
    var self = this;
    self.debug('running ami connect');
    self.socket = null;
    self.socket = this.net.createConnection(this.port, this.host);//reopen it
    self.socket.setEncoding(this.ami_encoding);
    self.socket.setKeepAlive(true, 500);

    self.socket.on('connect', function(){
        self.debug('connected to Asterisk AMI');
        //login to the manager interface
        self.send({Action: 'login', Username : self.username, Secret : self.password, Events: (self.events ? 'on' : 'off')});
        if(connect_cb && typeof connect_cb == 'function'){
            connect_cb();
        }
    }).on('data', function(data){
            if(data_cb && typeof data_cb == 'function'){
                data_cb(data);
            }
            var all_events = self.processData(data);
            for(var i in all_events){
                var result = all_events[i];
                if(result.response && result.message && /Authentication/gi.exec(result.message) == 'Authentication'){
                    self.emit('ami_login', ((result.response == 'Success') ? true : false) ,result);
                }
                self.emit('ami_data', result);
            }
        }).on('drain', function(){
            self.debug('Asterisk Socket connection drained');
            self.emit('ami_socket_drain');
        }).on('error', function(error){
            if(error){
                self.debug('Asterisk Socket connection error, error was: ' + error);//prob lost connection to ami due to asterisk restarting so restart the connection
            }
            self.emit('ami_socket_error', error);
        }).on('timeout',function(){
            self.debug('Asterisk Socket connection has timed out');
            self.emit('ami_socket_timeout');
        }).on('end', function() {
            self.debug('Asterisk Socket connection ran end event');
            self.emit('ami_socket_end');
        }).on('close', function(had_error){
            self.debug('Asterisk Socket connection closed, error status - ' + had_error);
            self.emit('ami_socket_close', had_error);
            if(self.reconnect){
                self.debug('Reconnecting to AMI in ' + self.reconnect_after);
                setTimeout(function() {
                    self.connect(connect_cb, data_cb);
                }, self.reconnect_after);
            }
        });
}

AsteriskManager.prototype.disconnect = function(){
    this.reconnect = false;//just in case we wanted it to reconnect before, we've asked for it to be closed this time so make sure it doesnt reconnect
    this.socket.end(this.generateSocketData({Action: 'Logoff'}));
}

AsteriskManager.prototype.destroy = function(){
    this.socket.destroy();
}

AsteriskManager.prototype.processData = function(data, cb){
    /*
     Thanks to mscdex for this bit of code that takes many lots of data and sorts them out into one if needed!
     https://github.com/mscdex/node-asterisk/blob/master/asterisk.js
     */
    data = data.toString();
    if (data.substr(0, 21) == "Asterisk Call Manager"){
        data = data.substr(data.indexOf(this.CRLF)+2); // skip the server greeting when first connecting
    }
    this.buffer += data;
    var iDelim, info, headers, kv, type, all_events = [];
    while ((iDelim = this.buffer.indexOf(this.END)) > -1) {
        info = this.buffer.substring(0, iDelim+2).split(this.CRLF);
        this.buffer = this.buffer.substr(iDelim + 4);
        result = {}; type = ""; kv = [];
        for (var i=0,len=info.length; i<len; i++) {
            if (info[i].indexOf(": ") == -1){
                continue;
            }
            kv = info[i].split(": ", 2);
            kv[0] = kv[0].toLowerCase().replace("-", "");
            if (i==0){
                type = kv[0];
            }
            result[kv[0]] = kv[1];
        }
        if(this.identifier){
            result.identifier = this.identifier;
        }
        all_events.push(result);
    }
    return all_events;
}

AsteriskManager.prototype.debug = function(data){
    if(this.enable_debug){
        console.log(data);
    }
}

AsteriskManager.prototype.generateRandom = function(){
    return Math.floor(Math.random()*100000000000000000);
}

AsteriskManager.prototype.generateSocketData = function(obj){
    var str = '';
    for(var i in obj){
        str += (i + ': ' + obj[i] + this.CRLF);
    }
    return str + this.CRLF;
}

AsteriskManager.prototype.send = function(obj, cb) {
    //check state of connection here, if not up then bail out
    if(!obj.ActionID){
        obj.ActionID = this.generateRandom();
    }

    //maybe i should be checking if this socket is writeable
    if(this.socket != null && this.socket.writable){
        this.debug(obj);
        this.socket.write(this.generateSocketData(obj), this.ami_encoding, cb);
    }else{
        this.debug('cannot write to Asterisk Socket');
        this.emit('ami_socket_unwritable');
    }
}

1 个答案:

答案 0 :(得分:1)

正如错误消息所示“尝试包装您使用Meteor.bindEnvironment传递给非Meteor库的回调”

ami.on('ami_data', Meteor.bindEnvironment( function(data){
  console.log(data); // <- this works fine
  // the following causes the error
  EventsLog.insert({ timestamp: (new Date()).getTime(), 
                   data: data});
 }, function( error) { console.log( error);})
);

还有很多其他examples around

如果上面的服务器代码不在光纤中,您可能会得到“Meteor代码必须始终在光纤内运行”error