The im status service subscribes to the `become_main_tab`,
`no_longer_main_tab` events.
Since the PR improving the multi tab service, the multi tab
itself is not an event target anymore but exposes a bus instance
that should be used to subscribe to those events.
The im status service is still based on the first version (that was
using env.bus) which means the event will never be received. This
commit fixes this issue.
closesodoo/odoo#99635
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The `displays reconnect notification` bus test relies on a `nextTick`
to assert that a notification is present after the websocket
disconnection.
The issue is that we can't be sure that the notification will be
displayed after this tick. Indeed, we need to wait for: the `postMessage`
to reach the bus service, the notification to be added, the notification
to be added in the DOM.
This commit solves this issue, by waiting for the next render after the
`simulateConnectionLost` method to occur.
closesodoo/odoo#99590
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
When executing python tests with Odoo opened in the browser, the
websocket connection coming from the browser can lead to issues
with savepoints/rollbacks. Indeed, during test set up, a savepoint
is created. This savepoint is released at the end of each test.
The issue occurs when the websocket connection opens a cursor (and
thus creates a savepoint) after the one created by the test but releases
it after the one created by the test:
- SAVEPOINT TEST
- SAVEPOINT WS
- ROLLBACK TO SAVEPOINT TEST
- SAVEPOINT WS DOES NOT EXIST
In order to solve this issue, let's prevent browsers from opening a
websocket connection during python tests. This does not apply to chrome
headless since remaining threads are awaited before the end of every tour
(which means the websocket connection will be close before releasing the
test cursor).
closesodoo/odoo#99538
Signed-off-by: Julien Castiaux <juc@odoo.com>
Before the websockets were introduced, longpolling coroutines were
sleeping until postgres notify. Each coroutine was then wake up and
notifications were fetched.
Since the websocket introduction, the main loop, responsible for listening
to postgres sends the notifications itself. This means, the postgres loop
is blocked during message fetch/dispatching and notifications are dispatched
in a sequential fashion resulting in a slow message dispatching.
In order to solve this issue, websocket coroutines are now responsible to
fetch/dispatch notifications, letting the main loop free to relay notifications
as they come and allowing notifications to be sent simultaneously.
When instructed to dispatch available notifications, the websocket coroutines
will try to acquire a cursor. Each coroutine will try up to `MAX_TRY_ON_POOL_ERROR`
times, sleeping between each try. If no cursor can be acquired, the connection is
closed with the TRY_LATER` close code.
closesodoo/odoo#98880
Signed-off-by: Antony Lesuisse <al@odoo.com>
* = bus, hr_holidays, test_discuss_full
- use channel member instead of partner for typing
- use channel member instead of partner for all other return values from server
- remove temporary partner hack in livechat and keep public partner
- remove some obsolete convert data
- adapt format methods accordingly
task-2664853
closesodoo/odoo#98923
Related: odoo/enterprise#30760
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
Before this PR, disconnecting the websocket for a keep alive timeout
would skip the terminate method. When the loop would exit, gevent loop
will keep running and use the CPU up to 100%. This commit ensures the
termiante method is called when disconnecting due to a keep alive
timeout and solves this issue.
closesodoo/odoo#99308
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
The test_user_logout_outgoing_message is undeterministic because
it speculate on the fact that the channel subscription was made
when we try to dispatch notifications. Sometimes it is not and
the websocket to channel map is empty resulting in a StopIteration
exception being raised. Let's wait for the subscribe to occur to
ensure the websocket will be registered before trying to dispatch
the message.
closesodoo/odoo#99204
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The bus test "display reconnect notification" sometimes fails because
the notification is removed before the assertion occurs. Let's block
the start method of the worker to block the reconnection until the
assertion is made.
closesodoo/odoo#99160
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
When a websocket is disconnected, its subscription is removed.
Each channel leads to a set of subscribed websockets. When no
more sockets are listening to a channel, this channel should be
pop from this mapping or the map will keep growing.
closesodoo/odoo#98766
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The websocket client library is used during tests but is not in
requirements.txt. Therefore, imports are usually wrap into a try/except.
An import present in `websocket_rate_limiting` is not wrapped leading to
errors for those who have not the library installed. This PR fixes this
issue by wrapping this import in a try/except block.
closesodoo/odoo#98763
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
*: bus, calendar, hr_attendance, iap_mail, im_livechat, project, snailmail,
snailmail_account, survey, web, web_editor, website_livechat.
This commit is part of the websocket integration in Odoo.
This bus service now communicates with a shared worker in order to provide
a single websocket connection for multiple tabs. It is designed to
be used as a websocket except that events are slightly different,
re-connection is handled automatically. If the browser does not support shared
worker (Safari), the service fallback on a simple web worker.
Available events are:
- connect : fired upon a successful connection.
- disconnect : fired upon reception of the websocket close event.
The close code and reason are given to the listeners callback.
- reconnect : fired upon a successful re-connection.
- reconnecting : triggered when the worker starts to try reconnecting.
- notification : fired upon the reception of notifications.
Since multiple tabs are now handled by a worker, the cross_tab bus is no longer
required and has been removed.
Part-of: odoo/odoo#75510
*: hr_presence, web_editor.
This commit is part of the websocket integration in Odoo.
It focuses on adapting the bus to support websockets:
- last notification id is now kept on the server
- channel list is built by overriding the `_build_bus_channel_list`
method of the `ir_websocket` model instead of overriding the `_poll`
method of the bus controller.
- The bus presence was updated during polls, since there is no more poll,
bus presence update will be the responsability of the client.
- The `/websocket/peek_notifications`, `/websocket/update_bus_presence`
routes will be available so that odoo sh can access notifications/update presence
from http requests.
- /longpolling routes are now prefixed with /bus thus won't be redirected to the
gevent worker anymore except for `/longpolling/health` which is the
health check route of the gevent server.
Since websocket now handle incoming messages, a way to manage authentication
have been introduced :
- The session is retrieved from the HTTP handshake.
- When a websocket message comes/leaves the session is retrieved
on the file system so that we're sure it still exists and that
it is up to date.
- The session is checked
- If no session is found on the file system or `check_session`
fails, the websocket connection is closed with the `SESSION_EXPIRED`
close code (which is a custom close code: 4001).
- Note that websocket connections are closed every `KEEP_ALIVE_TIMEOUT`
seconds to ensure no websocket connection will stay open if the user
clears its cookies.
- Note that a wsrequest object is available when processing incoming
messages. It is similar to the http request and contains various
useful informations (session, env, ...).
Part-of: odoo/odoo#75510
This commit is part of the websocket integration in Odoo.
It focuses on implementing websocket lifecycle events.
Two lifecycle hooks are currently available:
- onopen: called after the websocket opening
- onclose: called after the websocket closure.
Those callbacks will be passed an environment and the websocket
related to the lifecycle event.
In order to subscribe to websocket lifecycle events, one must decorate
a free functions with either `@Websocket.onopen` or `@Websocket.onclose`.
Part-of: odoo/odoo#75510
This commit is part of the websocket integration in Odoo.
It focuses on implementing rate limiting to the incoming
websocket messages. When opening a connection, a burst of messages
is allowed. When requests are received too fast, an exception is
raised and the websocket is closed.
Two config parameters are added to customize the rate limtier
behavior:
- websocket_rate_limit_delay: Integer specifying the seconds that
should space out two requests.
- websocket_rate_limit_burst: Integer specifying how many websocket
frames can be accepted in excess of the specified rate.
Part-of: odoo/odoo#75510
This commit is the first commit of the websocket integration in Odoo.
It focuses on the implementation of the websocket protocol as per RFC6455.
The implementation is tested thanks to the autobahn test suite.
A config parameter is available to customize the websocket connection:
- websocket_keep_alive_timeout (default 600): Integer specifying how
many seconds a websocket connection should be kept alive
Part-of: odoo/odoo#75510
The bus tests rely to heavily on the underlying technology (polling).
In order to keep the test intact in the PR introducing the websockets
in Odoo, let's convert the test to be less technical.
task-2053917
closesodoo/odoo#97975
Related: odoo/enterprise#30360
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
*: mail, web.
The pyEnv used during tests is based on the mock server to provide
server like api. This issue is that when creating multiple environments
during tests, a new mock server is created each time. This is not realistic
since in a real world scenario, multiple tabs would share a single server.
In order to make pyEnv work with multiple tabs tests (e.g. multiple env tests),
let's create a single mock server shared between js environment during a test.
task-2053917
Part-of: odoo/odoo#97975
The model_definition_setup has been moved in [1] but adds some models
to be fetched that are not related to the bus module. This would lead
to error in single module builds.
closesodoo/odoo#97937
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
In order to prepare the ground/reduce the noise in the PR
introducing the websockets in Odoo, the mocks of the longpolling
route in tests is replaced by calls to sendone/sendmany.
This will allow to keep the same code while changing the underlying
technology.
task-2053917
closesodoo/odoo#97771
Related: odoo/enterprise#30244
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The BusService class only adds the possibilty to send notifications.
This is only used in the mail module. Let's remove this unnecessary
override and move this functionnality into mail models.
closesodoo/odoo#97685
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The mock of sendone/many was relying on the bus_service. Since owl.Component.env
is changing during tests setup, the bus_service was not always defined. In order
to make this more reliable, the longpolling/poll route is now mocked, returning a
promise that can be resolved by the sendone/many methods.
closesodoo/odoo#97298
Related: odoo/enterprise#30059
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
Commit b743fda doesn't seem to work properly.
Steps to reproduce:
- Open a spreadsheet A in one tab
- Open a spreadsheet B in another tab
=> the master tab should poll both spreadsheet channels but it
does not.
The condition here sheems wrong
https://github.com/odoo/odoo/blob/bf2ce0aa0c7d45c90d7ff104d5af5f99b29d59ae/addons/bus/static/src/js/crosstab_bus.js#L299
`peerChannelsBefore` is not really "before the channel was added".
It's "before outdated channels are cleared".
It already contains the new channel added to local storage by the slave tab!
Hence it wrongly returns `false` which means the poll request is not
restarted.
Additional fix required since e2aeb5f
-------------------------------------
Commit e2aeb5f broke a little more the feature.
It is assumed the ids in `channels` are matching the ids in `lastPresenceByTab`
(previously named `peers`). It was no longer true since `lastPresenceByTab`
is now managed by multi_tab service (with it's own id).
With those non-matching ids, channels from other tabs were always considered
outdated and therefore cleaned up.
Small comment on the change in the mock server
----------------------------------------------
Cross tab bus tests were not working properly.
The error message string "XmlHttpRequestError abort" was stringified
(stringifying a string), leading to "\"XmlHttpRequestError abort\"". Since the
implementation depends on the exact error message, tests didn't propely
reflect reality.
This is technically not needed anymore since bus tests are no longer using
the legacy mock server but it can't hurt to fix it. (the new mock server
doesn't have this issue)
closesodoo/odoo#97036
X-original-commit: f25f36a
Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
Co-authored-by: Goaman <nby@odoo.com>
Co-authored-by: tsm-odoo <tsm@odoo.com>
When a tab is closed (unloads), the main tab is still considered the main tab
and event listeners are not properly removed.
In practice, it's probably not an issue because the tab is killed by the browser,
but it could still potentially have unexpected and undesired side effects.
It's safer to clean everything properly.
The issue is much more visible in tests because the mutli_tab and bus services
are still "active" after we simulated a tab unload.
Part-of: odoo/odoo#97036
Co-authored-by: tsm-odoo <tsm@odoo.com>
*: im_livechat, snailmail_account, survey, web_editor.
The callback registered by the bus service method onNotification was
not the same unregistered by offNotification. Since those method were
superfluous, they have been removed in favor of (add/remove)EventListener.
closesodoo/odoo#96684
Related: odoo/enterprise#29819
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
*: calendar, im_livechat, survey.
Following @ged-odoo review, the multi tab service has been improved:
- multi_tab_service.js has been moved to the correct location.
- _callLocalStorage method has been removed and replaced by
getItemFromLocalStorage/setItemToLocalStorage.
- underscore.js calls have been removed.
- multi_tab_service is now using function closure style instead of class.
- multi_tab service is now using its own bus instance.
- service name is now in snake case as per convention.
- tests have been added.
- multi tab service now handles setting/removing/getting values
shared between all the tabs.
closesodoo/odoo#96386
Enterprise: https://github.com/odoo/enterprise/pull/29694
Related: odoo/enterprise#29694
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
*: calendar, survey.
In order to ease the PR introducing websockets in Odoo, introduce
the multi service. Indeed, the cross tab bus won't be necessary
anymore but there will still be a need to elect a main tab: some actions
should only be triggered once. To achieve this, the code electing the main
tab has been split with the one handling the longpolling. The crosstab
bus now relies on the multi tab service to known whether or not the
current tab is the main tab.
task-2053917
closesodoo/odoo#96174
Related: odoo/enterprise#29573
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
on/off are deprecated in favor of addEventListener/removeEventListener.
Calls to the bus service have been updated to reflect those changes.
task-2053917
closesodoo/odoo#96017
Related: odoo/enterprise#29501
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
The code handling user presence and the one handling bus notifications
are mixed up. In order to ease the PR introducing the websocket in Odoo
and to clear this mess, the presence service has been introduced.
task-2053917
closesodoo/odoo#95981
Related: odoo/enterprise#29524
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
*: calendar, iap_mail.
Now that the bus service is a wowl service, we don't need to wait for
the webclient to be ready before using it. Indeed, the services now
have the bus service as a dependency which means it will always be ready
in time. This also showed that the rpc service was missing as a bus service
dependency. It has been added.
Some part of the code were also checking if the bus service was in
`env.services`. Those calls have been removed as well since we now
have the guarantee that it is.
closesodoo/odoo#96002
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
*: bus, calendar, iap_mail, im_livechat, project, web.
In order to ease the PR introducing the websockets in Odoo, the bus service
has to be updated to be a wowl service. This PR takes care of it.
task-2053917
closesodoo/odoo#95824
Related: odoo/enterprise#29361
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit make messaging service available in the frontend and in
the livechat external lib bundle.
This is preparation to refactoring JS livechat to use models and OWL.
*: bus, mail, survey, web, website_livechat
Task-2870899
closesodoo/odoo#92786
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
In fixing leftover jammy warnings in #92078 I mistakenly updated the
setting of `_daemonic` to the public `daemon`, missing that it was a
dedicated and explicit workaround for Python's checks (cf
d03b4f8675).
closesodoo/odoo#92255
X-original-commit: e35a4d87578a588e33f604638289ca7e7ee02029
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Python 3.10 formally deprecated the old threading API. This was missed
in #88803.
Also apply a few other fixes and improvements:
- `Thread._daemonic` is a non-public unchecked internal attribute, use
the corresponding documented property
- remove unused assignment to unused local
- define `Event` attribute in `__init__` where it belongs
- cleanup spawning on thread to do everything in ctor (permissible
since 3.3)
- fix import to not rely in implicit sub-module imports
closesodoo/odoo#92187
X-original-commit: 87d087ff7d53394dd991099cf7eac37d1ef68423
Signed-off-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This commit is the 14th commit of a comprehensive refactor of our HTTP
framework. See odoo/odoo#78857 for complete historic, discussions and
rationnals.
* `request.uid = x` => `request.update_env(user=x)`.
* `request.context = x` => `request.update_env(context=x)`.
* `request.context = dict(request.context, x=y)`
=> `request.update_context(x=y)`.
* `request.cr = None` => `request.cr.close()`.
* `http.mono_db()` => `request.db`.
* `http.dispatch_rpc()` => `service.dispatch_rpc()`.
* `@service.model.check` => `service.model.retrying()`.
* `request.endpoint`
=> `env['ir.http']._match(request.httprequest.path)[0].endpoint`.
* `request.routing_iteration `=> `removed`.
* `request.jsonrequest` => `request.dispatcher.jsonrequest`.
Note that `request.params` is now set much later in the process. If you
are in a situation where you values from the query string or the
http body you can use `request.get_http_params()`.
Note that using the new `request.future_response`, it is possible to
add headers and cookies on the response object before the response
object is initialized. Please note that headers/cookies saved on
the future response will NOT be injected in case of error.
PR: odoo#78857
Task: 2571224
In the next version of Owl, all exported terms are directly available
from the top level `owl` object. This commit aims to adapt existing
imports to this new system. This is done by importing any Owl property
used in files at the top, right after the `import` or `require`
statements.
closesodoo/odoo#82736
Related: odoo/enterprise#23609
Signed-off-by: Géry Debongnie <ged@odoo.com>
Before this commit: a notification asking to reload the current window
appeared as soon as the server detected a change in one of the assets
bundles, even on first load.
To fix this problem and make the feature more meaningful, it has been
decided to only notify the client when the server version (not the
bundle version) is outdated (i.e. on database upgrades, when the changes
in the code are actually relevant).
closesodoo/odoo#82032
X-original-commit: a3b5a9d715be6a93c7f2859074b916f3249f97c3
Signed-off-by: Antony Lesuisse <al@odoo.com>
Signed-off-by: Julien Mougenot (jum) <jum@odoo.com>
*: base_address_city, base_address_extended, bus, crm, im_livechat,
l10n_ae_pos, lunch, pos_restaurant_adyen, test_assetsbundle,
test_converter, test_lint.
It is spelled `auto_install`, the `complexity` key is long gone, `qweb`
has been moved to `assets: {'web.assets_qweb': []}`. `js` and `css` are
long gone too, `maintainer` is redundant with `author` which is
"Odoo S.A." by default already, the `certificate` key is long gone.
closesodoo/odoo#80988
Related: odoo/enterprise#22766
Signed-off-by: Julien Castiaux <juc@odoo.com>
* = auth_signup, calendar, im_livechat, snailmail_account, survey, test_mail,
web_editor, website_crm_iap_reveal, website_livechat
The aim of this PR is to improve/fix various flaws and limitation of the current
API, to make it easier to use and more efficient.
Notification are now defined with 3 distinct parts:
- the channel determines which client(s) should receive it
- the type determines how it should be handled
- the payload determines any extra information helpful for handling it
Channel
=======
Business code
-------------
- Record channel is introduced for ease of subscribing to and sending
notifications to specific partners, channels, documents, ...
- String channel is still supported (but it is converted internally to the tuple
channel).
- Tuple channel is still supported without any change (but should be avoided
whenever possible due to its complex syntax).
The channel is no longer sent to the client. When the channel was used for
business purpose, the information it contained has been moved into either the
new type, or the payload itself.
Technical note
--------------
All channels are now internally converted to the tuple (db, ...) channel, which
is necessary for the platform code (saas/sh).
Internally, the bus.bus table is not changed, type and payload are grouped
together into what was (and still is) called message.
Type
====
Type is introduced to uniformize the way notifications are sent and handled.
All existing notifications already had some kind of manually-built type in them.
This is now officially supported at the bus API.
In client code this will allow (to be done in future commits) to register one
handler per specific type, instead of having to iterate and to filter all
received notifications on every handler.
Payload
=======
Payload (ex message) did not change, it can still be anything depending on
business needs.
Few adaptations:
- When the type was included on the payload, the type has been moved to the new
type parameter.
- When the channel was used in business code, its data has been copied into the
payload.
task-1891151
closesodoo/odoo#79201
X-original-commit: 543af27c7d6836ffac9e80ff8490b6ddbd849221
Related: odoo/enterprise#21998
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Move user unique index back in bus module so that it is defined even
without mail module installed.
closesodoo/odoo#76454
X-original-commit: beb25dff5af816fa30341490374c9da44da175c1
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit prepares the ground for the collaborative feature.
Before this commit, it was impossible to have different channels for
each tabs. In collaboration, multiples tabs could listen to differents set
of channels.
Example:
One tab X could be subscribed to channel [a, b] and tab Y on channel
[a, b] and a tab Z on [a, c].
Before this commit, only the channels of the master tab were
listened. So in this case it was either [a, b] or [a, c] depending on
which tab is the master.
So either channel b or channel c were not listened depending on which tab
is the master.
Now, each time a tab listens or stops listens to a channel, the
master tab listen all channels for all tabs.
task-2497931
odoo pr: 75768
Part-of: odoo/odoo#75768
Previously, when killing the server, the longpolling bus stopped but
didn't start polling again after a few seconds, this was caused by the
fact that ConnectionLostError wasn't treated like a legacy error and
remapped to an object with a message, meaning it didn't trigger
guardedCatch callbacks.
Since ConnectionLostErrors should be handled much the same way as
RPCError when interacting with legacy code this commit simply adds
ConnectionLostError in the same places we already have RPCError during
error handling of legacy errors, but delegates behaviour to the new
lostConnectionHandler when appropriate.
closesodoo/odoo#74530
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>