Files
odoo_source/addons/mail/models/partner_devices.py
T
Thanh Dodeur 5cdd63c457 [ADD] discuss: add sfu server support for calls
The SFU is a server used to relay streaming between the participants of
a call to provide better scalability and performance than the current
peer-to-peer connections.

The required fields have been added in https://github.com/odoo/odoo/pull/138581

* `/mail/static/lib/discuss_sfu` contains the client code that is used
by the odoo client to interact with the SFU.
From: https://github.com/odoo/sfu/releases/tag/v1.0.0
* The Json Web Token code has been extracted from `web_push` while
adding support for the HS256 algorithm, to be used as the authentication
method between the SFU and Odoo.
* The python code has been updated so that the odoo server requests a
channel from the SFU when going above a participant threshold, and swap
the participants to a SFU connection afterward.
* `rtc_service.js` has been updated to support both peer-to-peer and
SFU modes.
* The `call_context_menu` has been updated to display information
relative to the SFU connection when in SFU mode.

task-2765922

closes odoo/odoo#132153

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
2023-12-08 17:19:10 +00:00

89 lines
3.7 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging as logger
from odoo import api, fields, models
from ..tools.jwt import generate_vapid_keys
_logger = logger.getLogger(__name__)
class InvalidVapidError(Exception):
pass
class PartnerDevice(models.Model):
_name = 'mail.partner.device'
_description = 'Partner Web Push Device'
partner_id = fields.Many2one('res.partner', string='Partner', index=True, required=True,
default=lambda self: self.env.user.partner_id)
endpoint = fields.Char(string='Browser endpoint', required=True)
keys = fields.Char(string='Browser keys', required=True,
help=("It's refer to browser keys used by the notification: \n"
"- p256dh: It's the subscription public key generated by the browser. The browser will \n"
" keep the private key secret and use it for decrypting the payload\n"
"- auth: The auth value should be treated as a secret and not shared outside of Odoo"))
expiration_time = fields.Datetime(string='Expiration Token Date')
_sql_constraints = [('endpoint_unique', 'unique(endpoint)', 'The endpoint must be unique !')]
@api.model
def get_web_push_vapid_public_key(self):
ir_params_sudo = self.env['ir.config_parameter'].sudo()
public_key = 'mail.web_push_vapid_public_key'
public_key_value = ir_params_sudo.get_param(public_key)
# Regenerate new Keys if public key not present
if not public_key_value:
self.sudo().search([]).unlink() # Reset all devices (ServiceWorker)
private_key_value, public_key_value = generate_vapid_keys()
ir_params_sudo.set_param('mail.web_push_vapid_private_key', private_key_value)
ir_params_sudo.set_param(public_key, public_key_value)
_logger.info("WebPush: missing public key, new VAPID keys generated")
return public_key_value
@api.model
def register_devices(self, **kw):
sw_vapid_public_key = kw.get('vapid_public_key')
valid_sub = self._verify_vapid_public_key(sw_vapid_public_key)
if not valid_sub:
raise InvalidVapidError("Invalid VAPID public key")
endpoint = kw.get('endpoint')
browser_keys = kw.get('keys')
if not endpoint or not browser_keys:
return
search_endpoint = kw.get('previousEndpoint', endpoint)
user_device = self.sudo().search([('endpoint', '=', search_endpoint)])
if user_device:
if user_device.partner_id is not self.env.user.partner_id:
user_device.write({
'endpoint': endpoint,
'expiration_time': kw.get('expirationTime'),
'keys': json.dumps(browser_keys),
'partner_id': self.env.user.partner_id,
})
else:
self.sudo().create([{
'endpoint': endpoint,
'expiration_time': kw.get('expirationTime'),
'keys': json.dumps(browser_keys),
'partner_id': self.env.user.partner_id.id,
}])
@api.model
def unregister_devices(self, **kw):
endpoint = kw.get('endpoint')
if not endpoint:
return
user_device = self.sudo().search([
('endpoint', '=', endpoint)
])
if user_device:
user_device.unlink()
def _verify_vapid_public_key(self, sw_public_key):
ir_params_sudo = self.env['ir.config_parameter'].sudo()
db_public_key = ir_params_sudo.get_param('mail.web_push_vapid_public_key')
return db_public_key == sw_public_key