WebSockets - Basic Workflow

I’ve received a few requests to provide some information on how to work with websockets, specifically in the context of the Notification API. This one is in a bit of a grey area since on the one hand, WebSocket is just a standard communications protocol which we can’t train you on non-Mitel stuff, but on the other hand it’s an important component of using the Notification API and we want you to actually use it. That said I’ve written guides to REST concepts on the Developer Portal, but to be fair that’s a lot easier to explain (and much more fundamental to using the APIs) than websockets are.

So with that in mind, I do want to at least go over the necessary steps at a very high level to give you all a frame of reference when writing your own websocket code. This information came from a Mitel Engineer who writes in JavaScript, so keep that in mind for context here. It’s also important to know that the Notifications API uses MQTT:

  • Setup and Prerequisites (JavaScript)
    • npm packages
      • paho-mqtt - client-side mqtt implementation
      • rxjs - useful for wrapping and managing paho-mqtt
      • ws - (optional) node.js websocket implementation for using paho-mqtt on node if desired. Best practice is to use webhooks on node.
  • Build MqTT wrapper for handling Websocket events
    • Create connection (POST) to Notifications Service
      • Body: { transport: 'websocket' }
      • Returns the websocket URL
    • Create subscription (POST) on Notifications Service
      • Returns subscription with a subscriptionId
    • Connect with the paho-mqtt instance
      • Use the websocket URL from Notifications Service
    • Subscribe with paho-mqtt
      • Use subscriptionId from Notifications Service
  • Code
    • Setup connection
      • Obtain Auth Token from Authentication Service
      • Initialize MqTT wrapper with Auth token
    • Subscribe to MqTT ebsocket events
    • Setup a subscription on Notifications Service
      • Need a Topic and (optional) Subject Filter
    • Handle the event stream…
    • On close unsubscribe from Notifications Service

If you have any questions about this stuff, I’ll do my best to answer…but remember that this is one of those things where we have to draw the line somewhere between teaching you non-Mitel concepts and supporting the API.

When connecting to mqtt instance, it is asking for port number and client id. How do I get these?

Are you using the SDK that I sent to your team last week? It has web socket stuff you can use which will make life easier for you. That said…

What is prompting you for that information? Defining a port shouldn’t be necessary. As for the Client ID, that also depends on what is prompting you. There is a Client ID that exists in a database on our side which us used by the OICD Authentication workflow and is meant to identify the application making the request. In Dev, it’s a static value that you can use for any application you are developing (I will email that to you now). In Production, we will generate one for each application you develop and provide it to you when you get to that stage.

I am not using the SDK. I have installed the paho-mqtt package using npm and I am trying to follow the documentation on the npmjs page. In there I came across these details that I have to pass to connect. Please refer to the documentation screenshot below.

I believe location.hostname would be the websocket url that I get by making POST request to /connections endpoint. I need clarification about the port and client ID that is required to be passed. I tried without passing the port but it is mandatory.

Ah, in that case I believe you should use the Paho Client constructor overload (there are multiple) that takes just hostURI (the websocket URI) and clientId. So it should look something like this:

client = new Paho.Client(hostUri, clientId)

As for the clientId, I’m actually not 100% sure where/how that gets used presently, but I do know that generating your own works fine.

The SDK has a pretty good example under samples/notifications/node/app.js

Hi Budd, thanks for the prompt reply. I wanted to know one thing, does the websocket url that I get by making POST request to /connections endpoint expire after sometime? Do I have to get new websocket url after sometime?

It’s meant to be used immediately, so there is a timeout. I’m not 100% certain but I believe it’s only valid for 60 seconds and has to be used before then.

I am using the websocket url immediately after generating in code but when I try to connect to it using paho-mqtt in angular, connection is successful but immediately I get the message that says “Socket closed”. What seems to be the issue?

If you can give me a timestamp of when the error occurred, I will take a look at the server side logs to see what’s going on.

I reproduced the error just now. Its time stamp should be around 07:33 PM to 07:34 PM IST, September 3 2021

After doing some digging, I think the user that I am using to obtain the authentication token might not have the necessary permissions to subscribe to the topic published by the server.

The error code that I am getting in error message is “8”. Can you please confirm?

Are there any additional credentials required to be passed while connecting to websocket url?

I’ve had an initial look at the logs, and all I can see is:

  • You request the websocketURI with the /connections route
  • The server returns the websocketURI
  • You request the creation of the subscription
  • The server confirms the subscription has been created

I don’t actually see the websocket connection attempt, however I believe that’s being reported by an application layer that I don’t have access to the logs for. I’ve asked my team to look into this further and see what we can find, but your theory regarding permissions is worth looking into. Can you please provide the request body for the subscription creation so I can review?

Hi Budd,
The request body for the subscription is as follows:

{
“deviceId”: “2c7963c1-982c-4eff-9f2e-465875caf322-1yi25aqe73”,
“transport”: “websocket”,
“topic”: “platform-api-media”,
“subjectFilter”: “2017-09-01/endpoints/130001/calls”
}

I have some confusion as to what the exact subscription filter should be but passing this request body for subscription creation gets me the subscription id that I am subscribing to in the end. I believe device id can be any unique UUID.

On exploring the error online, I found that some people reported it being caused due to some missing IAM policy regarding AWS IoT. Please refer to the following link for details:
https://github.com/aws-amplify/amplify-js/issues/2739

I don’t see any issues with that subscription, although the deviceID should be the client ID that you created when setting up the MQTT connection.

Thanks for the linked info, I will pass it on to the team that’s looking at this, but I’m not sure it’s the issue given how many Mitel apps are currently using the Notification API in the exact same way that you’re attempting to.

I will provide another update ASAP.

I am using the same value for client id and device id but I am still facing this issue.

I thought maybe this issue is with subject filter that I am passing to create subscription, so I thought of using subject filters from debugging the mitel one website in the browser but my socket connection is immediately closed as soon as try to subscribe to any subscription id.

Just to close the loop on this for posterity, the root cause of this issue was never identified or resolved. The team who encountered this issue is developing Mitel applications under contract and was given a Mitel-internal SDK.

If anyone else encounters any issues working with websockets and the Notification API, especially those who encounter a similar issue, I encourage you to let us know!

I am trying to setup a WebSocket, but the WebSocket address is below, is this correct? it looks way too long, is this correct? struggling to get a connection, just want to make sure it is correct before spending to much time chansing my tail

wss://a6gj67bb0zxp6-ats.iot.ap-southeast-2.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential={REDACTED}

Hi Paul - That’s a valid connection URL, though I’ve gone ahead and masked it in your original post as the information could be used to access information in your CL account.

1 Like

Thanks Budd, ok I will spend some time and work this out. Thanks again for the quick response

Cheers

HI Budd,

I’m getting a little further but not the full way yet.

When I try and connect to the web socket, I get a 426 upgrade required. but with no info on what to upgrade to, I also see an InternalFailureException in the response not sure if that is because of something that I am doing, any idea? (I know its a broad subject but just in case you have seen this before)

GET:
Upgrade: websocket
Host: a6gj67bb0zxp6-ats.iot.ap-southeast-2.amazonaws.com
Origin: https://a6gj67bb0zxp6-ats.iot.ap-southeast-2.amazonaws.com
Sec-WebSocket-Key: {WS KEY}
Sec-WebSocket-Version: 13
Connection: Upgrade

— response header —
HTTP/1.1 426 Upgrade Required
content-type: application/json
content-length: 134
date: Fri, 05 Aug 2022 08:56:10 GMT
x-amzn-RequestId: 8524f623-aa24-6bc8-94f9-48b30a5101e0
connection: keep-alive
x-amzn-ErrorType: InternalFailureException:
sec-websocket-version: 13,8,7
access-control-allow-origin: *
access-control-expose-headers: x-amzn-ErrorMessage
access-control-expose-headers: x-amzn-RequestId
access-control-expose-headers: x-amzn-ErrorType
access-control-expose-headers: Date