Files
odoo_source/addons/bus/controllers/websocket.py
T
tsm-odoo 461f1c7998 [IMP] bus: last notification id reset after restoring db
Before this PR, the last notification id known by the client
was not reset after restoring the database. This was an issue
since there can be a gap between the last notification  and the
one that has been restored with the database. In this scenario,
messages are not received after restoring the database since the
client subscribes to higher notification ids that the ones that are
created.

This PR fixes this issue by defaulting to 0 if the one the client
passed is higher.

closes odoo/odoo#103311

X-original-commit: 5118da53a6e9adb94577a4f16999522a7e1e8c10
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Signed-off-by: Stockbauer Matthieu (tsm) <tsm@odoo.com>
2022-10-17 17:11:05 +02:00

67 lines
3.0 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from werkzeug.exceptions import ServiceUnavailable
from odoo.http import Controller, request, route, SessionExpiredException
from odoo.addons.base.models.assetsbundle import AssetsBundle
from ..models.bus import channel_with_db
from ..websocket import WebsocketConnectionHandler
class WebsocketController(Controller):
@route('/websocket', type="http", auth="public", cors='*', websocket=True)
def websocket(self):
"""
Handle the websocket handshake, upgrade the connection if
successfull.
"""
is_headful_browser = request.httprequest.user_agent and 'Headless' not in request.httprequest.user_agent.string
if request.registry.in_test_mode() and is_headful_browser:
# Prevent browsers from interfering with the unittests
raise ServiceUnavailable()
return WebsocketConnectionHandler.open_connection(request)
@route('/websocket/health', type='http', auth='none', save_session=False)
def health(self):
data = json.dumps({
'status': 'pass',
})
headers = [('Content-Type', 'application/json'),
('Cache-Control', 'no-store')]
return request.make_response(data, headers)
@route('/websocket/peek_notifications', type='json', auth='public', cors='*')
def peek_notifications(self, channels, last, is_first_poll=False):
if not all(isinstance(c, str) for c in channels):
raise ValueError("bus.Bus only string channels are allowed.")
if is_first_poll:
# Used to detect when the current session is expired.
request.session['is_websocket_session'] = True
elif 'is_websocket_session' not in request.session:
raise SessionExpiredException()
channels = list(set(
channel_with_db(request.db, c)
for c in request.env['ir.websocket']._build_bus_channel_list(channels)
))
last_known_notification_id = request.env['bus.bus'].sudo().search([], limit=1, order='id desc').id or 0
if last > last_known_notification_id:
last = 0
notifications = request.env['bus.bus']._poll(channels, last)
return {'channels': channels, 'notifications': notifications}
@route('/websocket/update_bus_presence', type='json', auth='public', cors='*')
def update_bus_presence(self, inactivity_period, im_status_ids_by_model):
if 'is_websocket_session' not in request.session:
raise SessionExpiredException()
request.env['ir.websocket']._update_bus_presence(int(inactivity_period), im_status_ids_by_model)
return {}
@route('/bus/websocket_worker_bundle', type='http', auth='public', cors='*')
def get_websocket_worker_bundle(self):
bundle = 'bus.websocket_worker_assets'
files, _ = request.env["ir.qweb"]._get_asset_content(bundle)
asset = AssetsBundle(bundle, files)
stream = request.env['ir.binary']._get_stream_from(asset.js())
return stream.get_response()