In this article, we will provide examples in Python to demonstrate how the client application interacts with the PortSIP PBX IM service. For these examples, we assume the PBX server is hosted at https://pbx.portsip.com:8887.
Connecting IM Server
The client application needs to use WebSocket to connect to the URL wss://pbx.portsip.com:8887/im.
Once the connection to the IM server is successfully established, the client must authenticate with the server in order to send and receive messages.
Obtain Access Token
The IM service authenticates the client application using the PortSIP PBX access token. Please follow the instructions in the article "PortSIP PBX REST API Authentication" to obtain the token.
Authenticate with IM Service using the Access Token
Once the access token is obtained, you can authenticate with the IM service by sending the login command to the server.
["ctrl"]["params"]["user"]: Represents the user ID.
["ctrl"]["params"]["token"]: Represents the user's authentication token, which can be used for verifying permissions in future HTTP file uploads to the IM server.
Subscribe to P2P Topic
P2P topics represent a communication channel between two users, and these topics do not have an owner.
The topic IDs for the two participating users are different. Each user views the other user’s ID as the P2P topic ID. For example, if the two users in the topic are usr804252613548703744 and usr804252613548777777, the first user will see the topic ID as usr804252613548777777, while the second user will see the topic ID as usr804252613548703744.
You can send a message to a P2P topic for another user using the following code snippet. The ["pub"]["id"] is a UUID that the client application must generate. The server will return this ID in its response, allowing the client to track the message by this ID.
uuid4 = uuid.uuid4()message ={"pub":{"id":str(uuid4),"topic":"usr804252613548703744","noecho":False,"content":"test test test"}}try:await websocket.send(json.dumps(message)) response =await websocket.recv()except ConnectionClosedError as e: logger.error("Connection closed unexpectedly : "+str(e))breaklogger.debug("pub_message to : usr804252613548703744 response : "+ response)ret = json.loads(response)if'ctrl'in ret and ret["ctrl"]["code"] >=300: logger.error("pub_message retcode error response : "+ response)
The user with the ID 804252613548777777 will receive the message as shown below:
{"data": {"topic":"usr804252613548703744","from":"usr804252613548777777","ts":"2024-10-24T08:24:41.913558Z","seq":377,"content":"test test test","reqid":"99c5075a-cf52-493c-8572-9e30437a02ce" }}
Get the Topics I Have Subscribed To
You can use the following code to retrieve the topics you have subscribed to.
You can use the following message {get what="desc"} to query the details of a topic. For example, group-related information can be found within the details of a group topic.
By using the ["meta"]["desc"]["seq"] field returned from the {get what="desc"} message, you can retrieve the number of messages in the subscribed topic. You can then use {get what="data"} to fetch historical messages.
uuid4 = uuid.uuid4()message ={"get":{"data":{"before":10000,"limit":1000,"since":0},"id":str(uuid4),"topic":"usr804252613548703744","what":"data"}}try:await websocket.send(json.dumps(message)) response =await websocket.recv()except ConnectionClosedError as e: logger.error("Connection closed unexpectedly : "+str(e))breaklogger.debug("sub_message to usr804252613548703744 response : "+ response)ret = json.loads(response)if'ctrl'in ret and ret["ctrl"]["code"] >=300: logger.error("sub_message retcode error response : "+ response)while IS_RUNNING:try: message =await asyncio.wait_for(websocket.recv(), timeout=SENDER_SLEEP) logger.debug("sub_message : "+ message) ret = json.loads(message)if'ctrl'in ret and ret["ctrl"]["code"] >=300: logger.error("sub_message retcode error response : "+ message)if'data'in ret://recived msgexcept asyncio.TimeoutError:breakexcept ConnectionClosedError as e: logger.error("Connection closed unexpectedly : "+str(e))break
Creating a Group Chat
You can use the following message to create a group chat.
The response will look like the following, the ["ctrl"]["topic"] represents the group topic. Then other users can subscribe to group messages by sending {sub topic="grpf0NlkdDEQHs"}.
The user can send the following message to subscribe to the group topic, allowing them to join the group and send or receive messages within the group.
The following message will be sent to all users who have subscribed to the group topic.
{"data": {"topic":"grpf0NlkdDEQHs","from":"usr901636310534455296","ts":"2024-10-24T07:04:01.120034Z","seq":2,"content":"test test test","reqid":"c1dd7a45-93db-4af9-870d-10643222b7e7" }}
Leave From a Group
Users can unsubscribe from a group by sending a {leave} message. This is the opposite function of the {sub} message. The {leave} message supports two options:
Leave without unsubscribing (unsub=false)
Unsubscribe and leave (unsub=true)
The server will respond to a {leave} message with a {ctrl} packet.
Leave without unsubscribing (unsub=false) only affects the current WebSocket session. You will still receive messages if you establish a new WebSocket session with the IM server, and if the user is connected to the IM server from another app, they will also continue receiving messages.
Unsubscribe and leave (unsub=true) affects all sessions for that user. The user will no longer receive messages from this group across any session unless he subscribes to this group topic again.
The group administrator can update the group information by sending the following message. The information structure is defined in the Publicattributesof the group topic.
The group administrator can transfer ownership of the group to another user by sending the following message. In this example, usr804252613548777777 indicates that the group ownership will be transferred to the user with the ID 804252613548777777.
To send a file in a chat, you first need to upload the file to the IM server using an HTTP POST form request to https://pbx.portsip.com:8887/im/file. An example code is provided below:
//uuid4 = uuid.uuid4()filename =str(uuid4)withopen(TEMP_DIR +'/'+ filename, 'w')as f: f.write(str(uuid4) * REPEAT_SIZE)form =FormData()form.add_field('id', str(uuid4))form.add_field('file', open(TEMP_DIR +'/'+ filename, 'rb'), filename=filename)header ={'Authorization':'token '+ token}try:if'https'in upload_url:asyncwith aiohttp.ClientSession(connector=TCPConnector(ssl=False))as session:asyncwith session.post(upload_url, data=form, headers=header)as response:if response.status ==200: text =await response.text() logger.debug(text)count_upload()else: text =await response.text() logger.error("http post error status :"+str(response.status) +" response : "+ text)else:asyncwith aiohttp.ClientSession()as session:asyncwith session.post(upload_url, data=form, headers=header)as response:if response.status ==200: text =await response.text() logger.debug(text)count_upload()else: text =await response.text() logger.error("http post error status :"+str(response.status) +" response : "+ text)except aiohttp.ClientError as e: logger.error("http post error : "+str(e))continueos.remove(TEMP_DIR +'/'+ filename)await asyncio.sleep(UPLOAD_SLEEP)
The response will look like the following if succeeds:
["ctrl"]["params"]["url"] is the file download URL. The sender can send this URL in a message to the recipient. After receiving the message, the recipient can download the file and display it in the chat according to the file type.
Download the Chat File
Once a user receives a message containing the file URL, they can assemble the URL as shown below and download the file using an HTTP GET request.