我正在尝试在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');
}
}
答案 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。