npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

telos-client

v1.0.3

Published

An interactive TCP client for the Telos VX Prime phone system

Downloads

9

Readme

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]);

| 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 | '' |

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

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"

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


GET: studioList

--Purpose

  • Get a read-only list of available studios.

--Definition

studioList() : Promise<Object>

--Usage

var Data = await client.studioList();

--Output "Data"

| Property | Description | Type | |------------ |---------------------------------------------------------------------------- |------- | | studioList | This is a read-only list property containing the list of available studios | Array of Objects |

--studioList Array element object definition

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


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"

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


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

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

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

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


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"

| Property | Description | Type | |---------- |------------------------------------------------------------------------------------------- |------------------ | | showList | This is a read-only list property containing the list of available shows for this studio. | Array of Objects |

--studioList Array element object definition

| Property | Description | Type | |---------- |--------------------------- |-------- | | showId | The unique id of the show | Number | | showName | The name of the show | String |


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"

| Property | Description | Type | |---------- |--------------------------------------------------------------------------- |------------------ | | lineList | This is a read-only list property containing the list of available lines. | Array of Objects |

--lineList Array element object definition

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


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"

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


ACTION: selectStudio

--Purpose

  • Selected a studio on the server

--Definition

selectStudio(studioId: Number) : Promise<Boolean>

--Arguments

| Property | Description | Default | Type | |---------- |-------------------------------- |--------- |-------- | | studioId | The ID or Number of the studio | | Number |

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

| Property | Description | Default | Type | |---------- |-------------------------------- |--------- |-------- | | showId | The ID or Number of the show within the selected studio | 1 | Number |

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

| Property | Description | Default | Type | |---------- |----------------- |--------- |-------- | | from | Sender's name | | String | | message | Message to send | | String |

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

| Property | Description | Default | Type | |---------- |----------------------------------------- |--------- |--------- | | state | Whether to set all lines to busy or not | true | Boolean |

--Usage

await client.setBusyAll(false);

ACTION: dropHybrid

--Purpose

  • Drop the call on a hybrid line

--Definition

dropHybrid(hybrid: Number) : Promise

--Arguments

| Property | Description | Default | Type | |---------- |---------------------------- |--------- |-------- | | hybrid | The id for the hybrid line | | Number |

--Usage

await client.dropHybrid(1);

ACTION: holdHybrid

--Purpose

  • Hold the call on a hybrid line

--Definition

holdHybrid(hybrid: Number) : Promise

--Arguments

| Property | Description | Default | Type | |---------- |---------------------------- |--------- |-------- | | hybrid | The id for the hybrid line | | Number |

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

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

| Property | Description | Default | Type | |---------- |---------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number | | comment | The comment text to assign to the line | | String |

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

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

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

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

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

--additionalConfig - Definition

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

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

| Property | Description | Default | Type | |------------------ |-------------------------------------------------- |--------- |-------- | | lineId | The number of the line to take | | Number | | additionalConfig | Additional configuration settings detailed below | | Object |

--additionalConfig - Definition

| Property | Description | Default | Type | Required | |---------- |---------------------------- |--------- |--------- |---------- | | handset | Whether to use the handset | | Boolean | NO | | hybrid | The hybrid id to use | | Number | NO |

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

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

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

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

| Property | Description | Default | Type | |---------- |-------------------------------------- |--------- |-------- | | lineId | The number of the line to operate on | | Number |

--Usage

await client.raiseLine(2);