1.0.3 • Published 6 years ago

telos-client v1.0.3

Weekly downloads
2
License
ISC
Repository
github
Last release
6 years ago

CircleCI

telos-client

An interactive TCP client abstraction for the Telos VX Prime phone server.

Table Of Contents

Overview

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 vs. VX Client

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.

Note on Promises

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.

Disclaimer

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.

Installation

Yarn

$ yarn add telos-client

NPM

$ npm install --save telos-client

Basic Usage

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();
})

Configuring the Client

  • Most configuration details can be initialized when creating the client. These configuration settings can also easily be overwritten with applicable configuration methods

Via Options

new TelosClient(options);

PropertyDescriptionTypeRequiredDefault
logSpecify the types of log messages to display. Formatted as a colon separated string (ex. "err:warn:input").StringNO
hostSpecify the host address to connect toStringNO
portSpecify the port to connect onNumberNO20518
studioIdSpecify the default studio id to connect toNumberNO1
usernameSpecify the username for logging in to the serverStringNO'user'
passwordSpecify the password for logging in to the serverStringNO''

Via Methods

Set Host Address

client.setHost(host: String)

Set Port Number

client.setPort(port: Number)

Set Studio ID

client.setStudioId(studioId: Number)

Set Username

client.setUsername(username: String)

Set Password

client.setPassword(password: String)

Console Logging

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 TypeColorDescriptionAliases
errorredError 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
warningorangeWarning 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
tracemagentaTrace 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
inputgreenInput 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
outputgreenOutput 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

Enabling console message types

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"
})

Events

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'

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'

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}`);
})

'book'

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
})

'im'

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}`)
})

Getting Started

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.

Connecting

client.connect() : Promise\<boolean>

Example

...
client.setHost('your.vxserver.net');

client.connect().then(function(success){
    console.log(success? "Connected" : "Failed to connect");
})

Logging In

NOTE: Logging in is a prerequisite for ALL methods except getServer.

client.login([username: String , password: String]) : Promise\<boolean>

  • If a username is not passed, it will default to 'user'
  • If a password is not passed, it will default to the empty string ''
  • The client instance will keep track of whether or not you are logged in for you

Example

/** assume we are inside an async function **/
var loggedIn = await client.login('myusername', 'somepassword');
console.log(loggedIn? "Logged in" : "Failed to log in");

Selecting A Studio

NOTE: Selecting a studio is a prerequisite for ALL methods except studioList, date, getServer, setMode, and ping.

client.selectStudio(studioId: Number) : Promise\<boolean>

  • The studio Id must be greater than 0
  • The client instance will keep track of whether or not you are in a studio for you.

Example

...
var studioSelected = await client.selectStudio(1);
console.log(studioSelected? "Studio selected": "Studio NOT selected");

Shortcut

Flow without shortcut

  • Because almost every method requires you to be connected, authenticated, and have a studio selected, you will often see this repetitive flow of events.
  +----------------+
  |client.connect()| <-------+
  +----------------+         |
          |                  |
          |                  |
          v                  |
   +--------------+          |
   |client.login()|          |
   +--------------+          |
          |                  |
          |                  |
          |                  |
+---------------------+      |
|client.selectStudio()|      |
+---------------------+      |
          |                  |
          |                  |
          v                  |
  +----------------+         |
  |Still Connected?+-----NO--+
  +----------------+
          |     ^
         YES    |
          |     |
          |     |
          v     |
+--------------------------------------+
|client.*() //Execute some other method|
+--------------------------------------+

Shortcut Method

  • Since this flow is so common, a built-in method has been included to simplify it

client.connectLoginSelect() : Promise\<boolean>

  • This method performs all three actions for you

Example

...
var initialized = await client.connectLoginSelect();
console.log(initialized? "Ready to go" : "Something went wrong");

Flow with shortcut

+---------------------------+
|client.connectLoginSelect()+<------+
+------------+--------------+       |
             |                      |
             |                      |
             v                      |
     +-------+--------+             |
     |Still Connected?+-----NO------+
     +----+-----------+
          |     ^
         YES    |
          |     |
          |     |
          v     |
+--------------------------------------+
|client.*() //Execute some other method|
+--------------------------------------+

Server Methods

  • Each section below outlines the getter and action methods for the respective "object" and "subobject" combinations According to the Livewire Control Protocol Spec pertaining to the VX Prime system

cc -- general server methods


GET: getServer

--Purpose

  • Get the current state of attributes related to the server

--Definition

getServer() : Promise<Object>

--Usage

var Data = await client.getServer();

--Output "Data"

PropertyDescriptionType
serverIdThis is a read-only string property containing server identification stringString
serverVersionThis is a read-only string property containing server version stringString
serverCapabilitesThis is a read-only string property containing server capabilities stringString
lwcpVersionThis is a read-only integer property containing the VX LWCP version the server is usingNumber

GET: studioList

--Purpose

  • Get a read-only list of available studios.

--Definition

studioList() : Promise<Object>

--Usage

var Data = await client.studioList();

--Output "Data"

PropertyDescriptionType
studioListThis is a read-only list property containing the list of available studiosArray of Objects

--studioList Array element object definition

PropertyDescriptionType
studioIdA read-only property for the id of a studioNumber
studioNameA read-only property for the name of the studioString

GET: date

--Purpose

  • Get a read-only string property mostly used for the VX phones to set their time because they don't have any RTC. ISO 8601 Date String Format.

--Definition

date() : Promise<Object>

--Usage

var Data = await client.date();

--Output "Data"

PropertyDescriptionType
dateThis 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

ACTION: ping

--Purpose

  • To test if VX server is still alive.

--Definition

ping() : Promise<Boolean>

--Usage

var pong = await client.ping();
if(!pong)
    console.log("Server connection has died");

ACTION: setMode

--Purpose

  • Write-only operation to tell the server of the current client's mode

--Definition

setMode(mode: String) : Promise

--Arguments

PropertyDescriptionDefaultType
modeThis 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)TALENTString

--Usage

//This method does not produce a response
await client.setMode();

ACTION: login

studio -- Studio Methods


GET: getStudio

--Purpose

  • Get the state of attributes related to the currently selected studio

--Definition

getStudio() : Promise<Object>

--Usage

var Data = await client.getStudio()

--Output "Data"

PropertyDescriptionType
studioIdThis is a read-only integer property containing studio ID.Number
studioNameThis is a read-only string property containing studio name.String
showIdThis is a read-only integer property containing currently selected show ID.Number
showNameThis is a read-only string property containing the name of currently selected show.String
numberOfLinesThis is a read-only integer property containing the total number of lines in the selected studio.Number
numberOfHybridsThis is a read-only integer property containing the total number of configured hybrids (fixed + selectable) in this studio.Number
numberOfFixedHybridsThis is a read-only integer property containing the number of configured fixed hybrids in this studio.Number
nextThis 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
producerNextThis 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
allBusyThis is a read-only enumerated boolean property that tells if the studio is in “busy all” state.Boolean
mutedThis is a read-only enumerated boolean property that tells if the “mute” flag was set in this studio.Boolean
showLockedThis is a read-only enumerated boolean property that tells if the selected show is locked in this studio.Boolean
autoAnswerOnThis is a read-only enumerated boolean property that tells if the “auto_answer” flag was set in this studio.Boolean

GET: showList

--Purpose

  • Get the list of shows in the currently selected studio

--Definition

showList() : Promise<Object>

--Usage

var Data = await client.showList();

--Output "Data"

PropertyDescriptionType
showListThis is a read-only list property containing the list of available shows for this studio.Array of Objects

--studioList Array element object definition

PropertyDescriptionType
showIdThe unique id of the showNumber
showNameThe name of the showString

GET: lineList

--Purpose

  • Get the list of lines and their attributes in the currently selected studio

--Definition

lineList() : Promise<Object>

--Usage

var Data = await client.lineList();

--Output "Data"

PropertyDescriptionType
lineListThis is a read-only list property containing the list of available lines.Array of Objects

--lineList Array element object definition

PropertyDescriptionType
stateThis is a read-only enumerated property that holds the current state of the line.String
callstateThis is a read-only enumerated property that holds the current state of the call that resides on this line.String
nameThis is a read-only string property that holds the name of the line.String
localThis 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
remoteThis is a read-only string property that holds the remote number which has called this line.Number
hybridThis is a read-only integer property that holds the hybrid currently assigned to this line.Number
timeThis 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
commentThis 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
directionThis is a read-only enumerated property that holds the direction of the call. Can be on of three valuesString

GET: hybridList

--Purpose

  • Get the list of hybrid lines in the currently selected studio

--Definition

hybridList() : Promise<Object>

--Usage

var Data = await client.hybridList();

--Output "Data"

PropertyDescriptionType
hybridListThis is a read-only list property containing the list of configured hybrids in this studio. List elements are strings with hybrid names.Array

ACTION: selectStudio

--Purpose

  • Selected a studio on the server

--Definition

selectStudio(studioId: Number) : Promise<Boolean>

--Arguments

PropertyDescriptionDefaultType
studioIdThe ID or Number of the studioNumber

--Usage

var selected = await client.selectStudio(1);
if(!selected)
    console.log("Failed to select a studio");

ACTION: selectShow

--Purpose

  • Select a show within the currently selected studio

--Definition

selectShow(showId: Number) : Promise<Boolean>

--Arguments

PropertyDescriptionDefaultType
showIdThe ID or Number of the show within the selected studio1Number

--Usage

var selected = await client.selectShow(1);
if(!selected)
    console.log("Failed to select a show");

ACTION: im

--Purpose

  • Send an instant message to all other clients within the currently selected studio

--Definition

im(from: String, message: String) : Promise

--Arguments

PropertyDescriptionDefaultType
fromSender's nameString
messageMessage to sendString

--Usage

await client.im("Me", "Hello World");

ACTION: setBusyAll

--Purpose

  • Set the state of all lines in the studio to busy or not busy

--Definition

setBusyAll(state: Boolean) : Promise

--Arguments

PropertyDescriptionDefaultType
stateWhether to set all lines to busy or nottrueBoolean

--Usage

await client.setBusyAll(false);

ACTION: dropHybrid

--Purpose

  • Drop the call on a hybrid line

--Definition

dropHybrid(hybrid: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
hybridThe id for the hybrid lineNumber

--Usage

await client.dropHybrid(1);

ACTION: holdHybrid

--Purpose

  • Hold the call on a hybrid line

--Definition

holdHybrid(hybrid: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
hybridThe id for the hybrid lineNumber

--Usage

await client.holdHybrid(1);

studio.line -- studio line methods


GET: getLine

--Purpose

  • Get the attributes of a specific line

--Definition

getLine(lineId: Number) : Promise<Object>

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

var Data = await client.getLine(1);

--Output "Data"


GET: getCallerId

--Purpose

  • Get the caller ID value of a specific line

--Definition

getCallerId(lineId: Number) : Promise<Object>

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

var Data = await client.getCallerId(1);

--Output "Data"


ACTION: setLineComment

--Purpose

  • Set the comment string of a specific line. Can only be set when not "IDLE"

--Definition

setLineComment(lineId: Number, comment: String) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber
commentThe comment text to assign to the lineString

--Usage

await client.setLineComment(1, "Caller Name: John Smith, Topic: Programming");

ACTION: setCallerId

--Purpose

  • Set the caller ID string of a specific line. Can only be set when not "IDLE"

--Definition

setCallerId(lineId: Number, callerId: String) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber
callerIdThe caller id string to assign to the lineString

--Usage

await client.setCallerId(1, "John Smith");

ACTION: seizeLine

--Purpose

  • Reserve the specified line for the current client so that nobody can call from it except the client

--Definition

seizeLine(lineId: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

await client.seizeLine(3);

ACTION: callLine

--Purpose

  • Creates all call to the specified number and puts it on a hybrid or handset

--Definition

callLine(lineId: Number, number: String [, additionalConfig: Object]) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber
numberThe remote number to callString
additionalConfigAdditional configuration settings detailed belowObject

--additionalConfig - Definition

PropertyDescriptionDefaultTypeRequired
handsetIf true the hybrid option will be considered otherwise the port option will be consideredBooleanNo
hybridThe identifier for which hybrid to use in the callNumberNo
portThe port to use in the callNumberNo

--Usage

await client.callLine(1,'18001231234');

ACTION: takeLine

--Purpose

  • Takes the call on the specified line to the air on.

--Definition

takeLine(lineId: Number [, additionalConfig: Object]) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to takeNumber
additionalConfigAdditional configuration settings detailed belowObject

--additionalConfig - Definition

PropertyDescriptionDefaultTypeRequired
handsetWhether to use the handsetBooleanNO
hybridThe hybrid id to useNumberNO

--Usage

await client.takeLine();

ACTION: takeNext

--Purpose

  • Takes the call on the air specified by the next or producerNext studio attribute depending on the client mode (TALENT or PRODUCER)

--Definition

takeNext() : Promise

--Usage

await client.takeNext();

ACTION: dropLine

--Purpose

  • Drops the call on the line specified.

--Definition

dropLine(lineId: Number) : Promise

--Arguments

--Usage

await client.dropLine(2);

ACTION: lockLine

--Purpose

  • Locks the call on the line specified if the call is "ON_AIR"

--Definition

lockLine(lineId: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

await client.lockLine(4);

ACTION: unlockLine

--Purpose

  • Unlocks the call on the line specified if the call is "ON_AIR_LOCKED"

--Definition

unlockLine(lineId: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

await client.unlockLine(4);

ACTION: holdLine

--Purpose

  • Holds a call in either the "ON_HOLD" OR "ON_HOLD_READ" state

--Definition

holdLine(lineId: Number, ready: Boolean) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber
readySpecifying true will set the line to "ON_HOLD_READY", whereas setting it to false will set the line to "ON_HOLD"falseString

--Usage

await client.holdLine(2, false);

ACTION: raiseLine

--Purpose

  • Raises the priority of the selected line in the next queue.

--Definition

raiseLine(lineId: Number) : Promise

--Arguments

PropertyDescriptionDefaultType
lineIdThe number of the line to operate onNumber

--Usage

await client.raiseLine(2);