2016-04-04 4 views
0

Ich versuche, Funktionen im ami-io npm-Paket zu überladen/zu ersetzen. Dieses Paket wurde erstellt, um mit asterisk AMI, einer Socket-Schnittstelle, zu kommunizieren.Einige Funktionen in einem öffentlichen npm-Paket ändern

Ich muss mit einem Dienst sprechen, der fast die exakt gleiche Schnittstelle hat, aber es zeigt eine andere Begrüßung bei der Anmeldung, und es erfordert ein zusätzliches Feld in der Anmeldung. Der ganze Rest ist gleich. Anstatt einfach das 600 LOC ami-io Paket zu kopieren und zwei oder drei Zeilen zu ändern, möchte ich die Funktion außer Kraft setzen, die die Grußzeichenfolge und die Login-Funktion erkennt und weiterhin das ami-io Paket verwendet.

Im Inneren des ami-io Paket gibt es eine Datei index.js, die die folgende Funktion enthält:

Client.prototype.auth = function (data) { 
    this.logger.debug('First message:', data); 
    if (data.match(/Asterisk Call Manager/)) { 
     this._setVersion(data); 
     this.socket.on('data', function (data) { 
      this.splitMessages(data); 
     }.bind(this)); 
     this.send(new Action.Login(this.config.login, this.config.password), function (error, response) { 
      if (response && response.response === 'Success') this.emit('connected'); 
      else this.emit('incorrectLogin'); 
     }.bind(this)); 
    } else { 
     this.emit('incorrectServer', data); 
    } 
}; 

Jetzt möchte ich auf Asterisk Call Manager nicht übereinstimmen, aber auf MyService, und ich will und Action.LoginExt(this.config.login, this.config.password) mit einem anderen verwenden definieren mit einem zusätzlichen Parameter.

Ist das möglich? Ich habe versucht, dies in meinem eigenen Modul:

var AmiIo = require('ami-io'); 
var amiio = AmiIo.createClient({port:5038, host:'x.x.x.x', login:'system', password:'admin'}); 


amiio.prototype.auth = function (data) { 
    this.logger.debug('First message:', data); 
    if (data.match(/MyService Version/)) { 
    this._setVersion(data); 
    this.socket.on('data', function (data) { 
     this.splitMessages(data); 
    }.bind(this)); 
    this.send(new Action.LoginExt(this.config.login, this.config.password, this.config.extra), function (error, response) { 
     if (response && response.response === 'Success') this.emit('connected'); 
     else this.emit('incorrectLogin'); 
    }.bind(this)); 
    } else { 
    this.emit('incorrectServer', data); 
    } 
}; 

... aber es führte zu TypeError: Cannot set property 'auth' of undefined, und jetzt ist ich ratlos. Kann ich auch ein neues Action.LoginExt Objekt in meinem eigenen Modul definieren? Wie?

Das action.js Modul definiert die Aktion Objekte wie folgt:

function Action(name) { 
    Action.super_.bind(this)(); 
    this.id = this.getId(); 
    this.set('ActionID', this.id); 
    this.set('Action', name); 
} 

(function(){ 
    var Message = require('./message.js'); 
    var util = require('util'); 
    util.inherits(Action, Message); 
})(); 

Action.prototype.getId = (function() { 
    var id = 0; 
    return function() { 
     return ++id; 
    } 
})(); 

function Login(username, secret) { 
    Login.super_.bind(this, 'Login')(); 
    this.set('Username', username); 
    this.set('Secret', secret); 
} 

... more functions ... 

(function() { 
    var actions = [ 
     Login, 
     ... more functions ... 
    ]; 
    var util = require('util'); 
    for (var i = 0; i < actions.length; i++) { 
     util.inherits(actions[i], Action); 
     exports[actions[i].name] = actions[i]; 
    } 
    exports.Action = Action; 
})(); 

Was ich glaube, ich verstehe, dass Aktion von Nachricht subclassed ist. Die Login-Funktion wird wiederum von Action abgeleitet und exportiert (im letzten Codeblock). So denke ich meinen Code in ich etwas ähnliches versuchen könnte:

// extend ami-io with LoginExt function 
function LoginExt(username, secret, company) { 
    Login.super_.bind(this, 'LoginExt')(); 
    this.set('Username', username); 
    this.set('Secret', secret); 
    this.set('Company', company); 
} 

var util = require('util'); 
util.inherits(LoginExt, amiio.Action); 

Aber util.inherits mit undefinierten ausfällt. Ich habe auch ein Problem bei ami-io eröffnet.

Antwort

1

können Sie verwenden:

var AmiIo = require('ami-io'); 
AmiIo.Action.Login = function NewConstructor(){}; //to override Login action 
//new constructor shold extend AmiIo.Action.Action(actionName) 
//and also, you can use 
AmiIo.Action.SomeNewAction = function SomeNewAction(){};//to create new actuion 
//it also should extend AmiIo.Action.Action(actionName); 

AmiIo.Action ist nur ein Objekt. Alle Konstruktoren sind Felder davon.

Um neue Ereignisse zu erstellen, müssen Sie nichts tun, weil es nur ein Objekt ist. Wenn Server

Event: Armageddon 
SomeField: 123 

ami-io wird 'Armageddon' senden Ihnen Event mit Namen erstellen.

To Client # Auth() Methode überschreiben, sollten Sie nur

var AmiIo = require('ami-io'); 
AmiIo.Client.prototype.auth = function(){};//new function 
0

amiio ist eine Instanz eines Client. Die prototype-Eigenschaft ist nur für Konstruktorfunktionen wie Client sinnvoll. Es ist nicht sinnvoll auf das Ergebnis einer Konstruktorfunktion (außer im seltenen Fall, dass die Instanz auch eine Funktion selbst ist - aber selbst in diesem Fall hat die Änderung der Instanz keinen Einfluss auf ihren übergeordneten Konstruktor).

Stattdessen müssen Sie die Instanz des Prototyps mit Object.getPrototypeOf bekommen:

Object.getPrototypeOf(amiio).auth = function() { ... } 

Wenn Sie dies nicht für jeden Kunden ändern müssen, sondern nur einen einzigen Client, müssen Sie nicht die ändern müssen Prototyp überhaupt. Ändern der Instanz auth ausreichend ist:

amiio.auth = function() { ... } 

Beachten Sie, dass Sie Code funktioniert nicht, wenn Action.LoginExt an das Modul Umfang lokal ist. Wenn das Modul es exportiert, können Sie wahrscheinlich AmiIo.Action.LoginExt stattdessen tun. Wenn es LoginExt nicht exportiert, müssen Sie den Code kopieren, der es implementiert, und es in Ihrem Importbereich erneut implementieren. Es kann einfacher sein, das Modul selbst zu modifizieren.

+0

Danke. Es ist so einfach. Ich bin jetzt mit dem Wrestling beim Hinzufügen/Erweitern einer Action beschäftigt. Es könnte tatsächlich einfacher sein, das Modul selbst zu modifizieren, aber dann muss ich es in meine eigene Codebasis ziehen, die technische Schulden generiert. Oder ... fork es, benenne es um und lege es in den NPM-Repo. Für nur ein paar Zeilen Code ... – raarts

0

Hier tun die Lösung, die ich arbeitete angewendet:

// Override the AmiIo auth procedure, because the other login is slightly different 
// Write our own Login function (which adds a company) 
function Login(username, secret, company) { 
    Login.super_.bind(this, 'Login')(); 
    this.set('Username', username); 
    this.set('Secret', secret); 
    this.set('Company', company); 
} 

// This function should inherit from Action 
var util = require('util'); 
util.inherits(Login, AmiIo.Action.Action); 
AmiIo.Action.Login = Login; 

// replace the auth with our own, to add the company. Also 
// this sends a slightly different greeting: "Service Version 1.0" 
AmiIo.Client.prototype.auth = function (data) { 
    if (data.match(/Service Version/)) { 
    this._setVersion(data); 
    this.socket.on('data', function (data) { 
     this.splitMessages(data); 
    }.bind(this)); 
    this.send(new AmiIo.Action.Login(this.config.login, this.config.password, this.config.company), function (error, response) { 
     if (response && response.response === 'Success') this.emit('connected'); 
     else this.emit('incorrectLogin'); 
    }.bind(this)); 
    } else { 
    this.emit('incorrectServer', data); 
    } 
}; 

// our own function to grab the version number from the new greeting 
AmiIo.Client.prototype._setVersion = function(version){ 
    var v = version.match(/Service Version ([\d\.]*[\-\w\d\.]*)/i); 
    if (v){ 
    this.version = v[1]; 
    } 
}; 

es dies als machbar war so stellt sich heraus, wie ich gehofft es wäre. Beide Antworten von @NumminorihSF und @apsillers haben mir hier geholfen, aber ich konnte nur eine von ihnen als beste Antwort markieren.

Verwandte Themen