An interactive TCP client abstraction for the Telos VX Prime phone server.
Telos Client is Node.js implementation of the interactive TCP protocol used by "Telos VX Prime" VoIP (Voice over IP) phone systems. The Livewire Control Protocol "LWCP" used by the VX-Prime server is designed to allow direct interaction with the system to monitor the state of the studio and its phone lines, and perform actions on the system. Telos client is a simple, clean API for managing a connection with the VX-Prime server, listening for studio changes, and performing actions within the studio.
Telos Client can be considered as version 1.0.0 of the package "vx-client" as it performs the same functionality. The reason that telos client is a seperate package is because it does not offer legacy syntax support for systems already using vx-client. Telos Client has a nearly identical set of methods, but the logging system is brand new and the entire library is strictly Promise based to adopt a more modern feel whereas vx-client is strictly callback based.
The decision to adopt a Promise based system for Telos Client was made to result in a cleaner implementation when incoporated into an application.
PLEASE READ THIS: Every implementation of Promises in this library will NEVER "reject", but instead will resolve a "null" value in the case of an error. This was decided to reduce the subjectively unappealing usage of try/catch statements in application code to catch errors. Instead, if the Promise resolves a null value, you can use the built in logging system to print out errors, warnings, stack traces, and I/O messages from the server in order to debug unexpected behavior.
This library is in active developement and will be tested over time. The syntax of this library will not change dramatically over the period of testing, but the functionality may change. Use at your own risk.
$ yarn add telos-client
$ npm install --save telos-client
const TelosClient = require('telos-client');
const client = new TelosClient();
client.setHost('10.1.1.1');
client.connect().then(async function(success){
if(success)
var server = await client.getServer();
})
Property | Description | Type | Required | Default |
---|---|---|---|---|
log | Specify the types of log messages to display. Formatted as a colon separated string (ex. "err:warn:input"). | String | NO | |
host | Specify the host address to connect to | String | NO | |
port | Specify the port to connect on | Number | NO | 20518 |
studioId | Specify the default studio id to connect to | Number | NO | 1 |
username | Specify the username for logging in to the server | String | NO | 'user' |
password | Specify the password for logging in to the server | String | NO | '' |
client.setHost(host: String)
client.setPort(port: Number)
client.setStudioId(studioId: Number)
client.setUsername(username: String)
client.setPassword(password: String)
Telos Client includes a logging system to optimize application building and debugging. There are various different message types that are used throughout the system and can be toggled with the "log" option when configuring the client.
Message Type | Color | Description | Aliases |
---|---|---|---|
error | red | Error messages are displayed whenever a fatal error occurs as a result of using the library incorrectly or passing an invalid message. Errors will not terminate the application so it is important to enable this option whenever developing to ensure that all errors are noticed. | error, errors, err |
warning | orange | Warning messages are displayed whenever an error occurs that does not affect the performance of the client and are typically mitigated through the use of default values. | warning, warnings, warn |
trace | magenta | Trace messages are displayed in tandem with error messages if the end-user needs to see the stack trace leading to the error. They will only display if the error type is also enabled. | trace, stack, stack trace, stacktrace |
input | green | Input messages are displayed whenever TCP message is received by the client. Input messages are not parsed other than ignoring trailing or leading whitespace. | input, in, request, req |
output | green | Output messages are displayed whenever a TCP message is sent by the client. Output messages are the actual representation of what is sent. | output, out, response, res |
const TelosClient = require('telos-client');
const client = new TelosClient({
// Enable message types by passing a ":" seperated string of any combination of message type aliases
log: "err:in:out"
})
The Telos VX system takes input from many different sources and thus changes frequently while being used. For many methods that retrieve data, they are tracked and resolved internally as part of the Promise resolution flow. For any other event triggered by the system, you will need to listen and track them using the events detailed below.
Studio events are fired whenever a change within the studio has been made. Primarily these are called in response to changes of attributes within the studio such as setting the studio to the "busy all" state.
client.on('studio', (data) => {
// Analyze studio changes here
})
Line events are fired whenever a change is made to a studio line. These can occur from a change requested by the end-user or naturally by the making and receive of calls on the line. This should be the application's primary way of reacting to changes within the system and staying up to date. NOTE: The "callerId" attribute may not be sent with the line event or the studio even. Be sure to manually request callerId fields if they are not returned and desired.
client.on('line', (data) => {
// Analyze line changes here
// Line events will always include the additional "line" property
// This indicates the number of the line that has triggered the event
console.log(`Line Number: ${data.line}`);
})
The book system is not thoroughly documented here as it has been untested. But if you decide to test the methods related to "studio.book", you can listen to the changes here.
client.on('book', (data) => {
// Analyze book changes here
})
Instant messages can be tracked within the selected studio using the 'im' event. Refer to the im method for more details on sending messages. Keep in mind that you will only receive instant messages that have been sent within the studio that has been selected.
client.on('im', (data) => {
console.log(`A message has been sent from "${data.from}": ${data.message}`)
})
NOTE: The next three "sub-sections" describe the manual way to connect to the server, login, and select a studio, while the forth section provides a nice shortcut to condense it all.
...
client.setHost('your.vxserver.net');
client.connect().then(function(success){
console.log(success? "Connected" : "Failed to connect");
})
NOTE: Logging in is a prerequisite for ALL methods except [getServer]().
/** assume we are inside an async function **/
var loggedIn = await client.login('myusername', 'somepassword');
console.log(loggedIn? "Logged in" : "Failed to log in");
NOTE: Selecting a studio is a prerequisite for ALL methods except [studioList](), [date](), [getServer](), [setMode](), and [ping]().
...
var studioSelected = await client.selectStudio(1);
console.log(studioSelected? "Studio selected": "Studio NOT selected");
+----------------+
|client.connect()| <-------+
+----------------+ |
| |
| |
v |
+--------------+ |
|client.login()| |
+--------------+ |
| |
| |
| |
+---------------------+ |
|client.selectStudio()| |
+---------------------+ |
| |
| |
v |
+----------------+ |
|Still Connected?+-----NO--+
+----------------+
| ^
YES |
| |
| |
v |
+--------------------------------------+
|client.*() //Execute some other method|
+--------------------------------------+
...
var initialized = await client.connectLoginSelect();
console.log(initialized? "Ready to go" : "Something went wrong");
+---------------------------+
|client.connectLoginSelect()+<------+
+------------+--------------+ |
| |
| |
v |
+-------+--------+ |
|Still Connected?+-----NO------+
+----+-----------+
| ^
YES |
| |
| |
v |
+--------------------------------------+
|client.*() //Execute some other method|
+--------------------------------------+
getServer() : Promise
var Data = await client.getServer();
Property | Description | Type |
---|---|---|
serverId | This is a read-only string property containing server identification string | String |
serverVersion | This is a read-only string property containing server version string | String |
serverCapabilites | This is a read-only string property containing server capabilities string | String |
lwcpVersion | This is a read-only integer property containing the VX LWCP version the server is using | Number |
studioList() : Promise
var Data = await client.studioList();
Property | Description | Type |
---|---|---|
studioList | This is a read-only list property containing the list of available studios | Array of Objects |
Property | Description | Type |
---|---|---|
studioId | A read-only property for the id of a studio | Number |
studioName | A read-only property for the name of the studio | String |
date() : Promise
var Data = await client.date();
Property | Description | Type |
---|---|---|
date | This is a read-only string property mostly used for the VX phones to set their time because they don't have any RTC. ISO 8601 Formatted. | String |
ping() : Promise
var pong = await client.ping();
if(!pong)
console.log("Server connection has died");
setMode(mode: String) : Promise
Property | Description | Default | Type |
---|---|---|---|
mode | This is a write-only enumerated property that tells server of a current client mode. Must be one of two possible values: "TALENT" or "PRODUCER" (case insensitive) | TALENT | String |
//This method does not produce a response
await client.setMode();
getStudio() : Promise
var Data = await client.getStudio()
Property | Description | Type |
---|---|---|
studioId | This is a read-only integer property containing studio ID. | Number |
studioName | This is a read-only string property containing studio name. | String |
showId | This is a read-only integer property containing currently selected show ID. | Number |
showName | This is a read-only string property containing the name of currently selected show. | String |
numberOfLines | This is a read-only integer property containing the total number of lines in the selected studio. | Number |
numberOfHybrids | This is a read-only integer property containing the total number of configured hybrids (fixed + selectable) in this studio. | Number |
numberOfFixedHybrids | This is a read-only integer property containing the number of configured fixed hybrids in this studio. | Number |
next | This is a read-only integer property which holds the ID number of the line that will be taken when take next operation is used. This is the queue for “TALENT” mode. | Number |
producerNext | This is a read-only integer property which holds the ID number of the line that will be taken when take next operation is used. This is the queue for “PRODUCER” mode. | Number |
allBusy | This is a read-only enumerated boolean property that tells if the studio is in “busy all” state. | Boolean |
muted | This is a read-only enumerated boolean property that tells if the “mute” flag was set in this studio. | Boolean |
showLocked | This is a read-only enumerated boolean property that tells if the selected show is locked in this studio. | Boolean |
autoAnswerOn | This is a read-only enumerated boolean property that tells if the “auto_answer” flag was set in this studio. | Boolean |
showList() : Promise
var Data = await client.showList();
Property | Description | Type |
---|---|---|
showList | This is a read-only list property containing the list of available shows for this studio. | Array of Objects |
Property | Description | Type |
---|---|---|
showId | The unique id of the show | Number |
showName | The name of the show | String |
lineList() : Promise
var Data = await client.lineList();
Property | Description | Type |
---|---|---|
lineList | This is a read-only list property containing the list of available lines. | Array of Objects |
Property | Description | Type |
---|---|---|
state | This is a read-only enumerated property that holds the current state of the line. | String |
callstate | This is a read-only enumerated property that holds the current state of the call that resides on this line. | String |
name | This is a read-only string property that holds the name of the line. | String |
local | This is a read-only string property that holds the local number of the line dialing which the call will be assigned to this line. | String |
remote | This is a read-only string property that holds the remote number which has called this line. | Number |
hybrid | This is a read-only integer property that holds the hybrid currently assigned to this line. | Number |
time | This is a read-only integer property that holds the time that passed from the beginning of the call in seconds. It resets when the line state is changed to a different one. | Number |
comment | This is a read-write string property that holds the comment assigned to this line. Comment will reset when the call is dropped. Also comment can only be set when line state is not idle, when there is an active call. | String |
direction | This is a read-only enumerated property that holds the direction of the call. Can be on of three values | String |
hybridList() : Promise
var Data = await client.hybridList();
Property | Description | Type |
---|---|---|
hybridList | This is a read-only list property containing the list of configured hybrids in this studio. List elements are strings with hybrid names. | Array |
selectStudio(studioId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
studioId | The ID or Number of the studio | Number |
var selected = await client.selectStudio(1);
if(!selected)
console.log("Failed to select a studio");
selectShow(showId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
showId | The ID or Number of the show within the selected studio | 1 | Number |
var selected = await client.selectShow(1);
if(!selected)
console.log("Failed to select a show");
im(from: String, message: String) : Promise
Property | Description | Default | Type |
---|---|---|---|
from | Sender's name | String | |
message | Message to send | String |
await client.im("Me", "Hello World");
setBusyAll(state: Boolean) : Promise
Property | Description | Default | Type |
---|---|---|---|
state | Whether to set all lines to busy or not | true | Boolean |
await client.setBusyAll(false);
dropHybrid(hybrid: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
hybrid | The id for the hybrid line | Number |
await client.dropHybrid(1);
holdHybrid(hybrid: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
hybrid | The id for the hybrid line | Number |
await client.holdHybrid(1);
getLine(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
var Data = await client.getLine(1);
getCallerId(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
var Data = await client.getCallerId(1);
setLineComment(lineId: Number, comment: String) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number | |
comment | The comment text to assign to the line | String |
await client.setLineComment(1, "Caller Name: John Smith, Topic: Programming");
setCallerId(lineId: Number, callerId: String) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number | |
callerId | The caller id string to assign to the line | String |
await client.setCallerId(1, "John Smith");
seizeLine(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
await client.seizeLine(3);
callLine(lineId: Number, number: String [, additionalConfig: Object]) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number | |
number | The remote number to call | String | |
additionalConfig | Additional configuration settings detailed below | Object |
Property | Description | Default | Type | Required |
---|---|---|---|---|
handset | If true the hybrid option will be considered otherwise the port option will be considered | Boolean | No | |
hybrid | The identifier for which hybrid to use in the call | Number | No | |
port | The port to use in the call | Number | No |
await client.callLine(1,'18001231234');
takeLine(lineId: Number [, additionalConfig: Object]) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to take | Number | |
additionalConfig | Additional configuration settings detailed below | Object |
Property | Description | Default | Type | Required |
---|---|---|---|---|
handset | Whether to use the handset | Boolean | NO | |
hybrid | The hybrid id to use | Number | NO |
await client.takeLine();
takeNext() : Promise
await client.takeNext();
dropLine(lineId: Number) : Promise
await client.dropLine(2);
lockLine(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
await client.lockLine(4);
unlockLine(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
await client.unlockLine(4);
holdLine(lineId: Number, ready: Boolean) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number | |
ready | Specifying true will set the line to "ON_HOLD_READY", whereas setting it to false will set the line to "ON_HOLD" | false | String |
await client.holdLine(2, false);
raiseLine(lineId: Number) : Promise
Property | Description | Default | Type |
---|---|---|---|
lineId | The number of the line to operate on | Number |
await client.raiseLine(2);