oca-ocb-core/odoo-bringout-oca-ocb-iot_drivers/iot_drivers/webrtc_client.py
Ernad Husremovic aee3ee8bf7 add missing payment providers and iot modules for 19.0
Add 19 payment provider modules needed by the sale module:
payment_adyen, payment_aps, payment_asiapay, payment_authorize,
payment_buckaroo, payment_demo, payment_dpo, payment_flutterwave,
payment_iyzico, payment_mercado_pago, payment_mollie, payment_nuvei,
payment_paymob, payment_paypal, payment_razorpay, payment_redsys,
payment_stripe, payment_worldline, payment_xendit

Add 3 IoT modules needed for point_of_sale:
iot_base, iot_box_image, iot_drivers

Note: Stripe test API keys replaced with placeholders.

🤖 assisted by claude
2026-03-09 15:45:22 +01:00

100 lines
3.7 KiB
Python

import asyncio
import json
import logging
import pprint
from threading import Thread
import time
from aiortc import RTCDataChannel, RTCPeerConnection, RTCSessionDescription
from odoo.addons.iot_drivers import main
_logger = logging.getLogger(__name__)
class WebRtcClient(Thread):
daemon = True
def __init__(self):
super().__init__()
self.connections: set[RTCDataChannel] = set()
self.chunked_message_in_progress: dict[RTCDataChannel, str] = {}
self.event_loop = asyncio.get_event_loop_policy().get_event_loop()
def offer(self, request: dict):
return asyncio.run_coroutine_threadsafe(
self._offer(request), self.event_loop
).result()
def send(self, data: dict):
asyncio.run_coroutine_threadsafe(
self._send(data), self.event_loop
)
async def _offer(self, request: dict):
offer = RTCSessionDescription(sdp=request["sdp"], type=request["type"])
peer_connection = RTCPeerConnection()
@peer_connection.on("datachannel")
def on_datachannel(channel: RTCDataChannel):
self.connections.add(channel)
@channel.on("message")
async def on_message(message_str: str):
# Handle chunked message
if self.chunked_message_in_progress.get(channel) is not None:
if message_str == "chunked_end":
message_str = self.chunked_message_in_progress.pop(channel)
else:
self.chunked_message_in_progress[channel] += message_str
return
elif message_str == "chunked_start":
self.chunked_message_in_progress[channel] = ""
return
# Handle regular message
message = json.loads(message_str)
message_type = message["message_type"]
_logger.info("Received message of type %s:\n%s", message_type, pprint.pformat(message))
if message_type == "iot_action":
device_identifier = message["device_identifier"]
data = message["data"]
data["session_id"] = message["session_id"]
if device_identifier in main.iot_devices:
_logger.info("device '%s' action started with: %s", device_identifier, pprint.pformat(data))
await self.event_loop.run_in_executor(None, lambda: main.iot_devices[device_identifier].action(data))
else:
# Notify that the device is not connected
self.send({
'owner': message['session_id'],
'device_identifier': device_identifier,
'time': time.time(),
'status': 'disconnected',
})
@channel.on("close")
def on_close():
self.connections.discard(channel)
@peer_connection.on("connectionstatechange")
async def on_connectionstatechange():
if peer_connection.connectionState == "failed":
await peer_connection.close()
await peer_connection.setRemoteDescription(offer)
answer = await peer_connection.createAnswer()
await peer_connection.setLocalDescription(answer)
return {"sdp": peer_connection.localDescription.sdp, "type": peer_connection.localDescription.type}
async def _send(self, data: dict):
for connection in self.connections:
connection.send(json.dumps(data))
def run(self):
self.event_loop.run_forever()
webrtc_client = WebRtcClient()
webrtc_client.start()