Allow setting push rules to be handled on workers

This commit is contained in:
Erik Johnston 2024-03-27 11:44:50 +00:00
parent 59ceabcb97
commit eb4513c78a
5 changed files with 107 additions and 14 deletions

View file

@ -18,15 +18,15 @@
# [This file includes modifications made by New Vector Limited]
#
#
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
import attr
from typing import TYPE_CHECKING, Any, Dict, List, Union
from synapse.api.errors import SynapseError, UnrecognizedRequestError
from synapse.push.clientformat import format_push_rules_for_user
from synapse.replication.http.push import PushSetRuleAttrRestServlet
from synapse.storage.push_rule import RuleNotFoundException
from synapse.synapse_rust.push import get_base_rule_ids
from synapse.types import JsonDict, StreamKeyType, UserID
from synapse.types.push import RuleSpec
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -35,14 +35,6 @@ if TYPE_CHECKING:
BASE_RULE_IDS = get_base_rule_ids()
@attr.s(slots=True, frozen=True, auto_attribs=True)
class RuleSpec:
scope: str
template: str
rule_id: str
attr: Optional[str]
class PushRulesHandler:
"""A class to handle changes in push rules for users."""
@ -50,8 +42,27 @@ class PushRulesHandler:
self._notifier = hs.get_notifier()
self._main_store = hs.get_datastores().main
self._push_attr_repl_client = None
if hs.config.worker.worker_app is not None:
self._push_attr_repl_client = PushSetRuleAttrRestServlet.make_client(hs)
async def set_rule_attr(
self, user_id: str, spec: RuleSpec, val: Union[bool, JsonDict]
) -> None:
if self._push_attr_repl_client:
await self._push_attr_repl_client(
user_id=user_id,
scope=spec.scope,
template=spec.template,
rule_id=spec.rule_id,
attr=spec.attr,
val=val,
)
else:
await self._set_rule_attr(user_id, spec, val)
async def _set_rule_attr(
self, user_id: str, spec: RuleSpec, val: Union[bool, JsonDict]
) -> None:
"""Set an attribute (enabled or actions) on an existing push rule.

View file

@ -66,7 +66,7 @@ from synapse.handlers.auth import (
AuthHandler,
)
from synapse.handlers.device import DeviceHandler
from synapse.handlers.push_rules import RuleSpec, check_actions
from synapse.handlers.push_rules import check_actions
from synapse.http.client import SimpleHttpClient
from synapse.http.server import (
DirectServeHtmlResource,
@ -141,6 +141,7 @@ from synapse.types import (
UserProfile,
create_requester,
)
from synapse.types.push import RuleSpec
from synapse.types.state import StateFilter
from synapse.util import Clock
from synapse.util.async_helpers import maybe_awaitable

View file

@ -20,13 +20,14 @@
#
import logging
from typing import TYPE_CHECKING, Tuple
from typing import TYPE_CHECKING, Tuple, Union
from twisted.web.server import Request
from synapse.http.server import HttpServer
from synapse.replication.http._base import ReplicationEndpoint
from synapse.types import JsonDict
from synapse.types.push import RuleSpec
if TYPE_CHECKING:
from synapse.server import HomeServer
@ -77,5 +78,59 @@ class ReplicationRemovePusherRestServlet(ReplicationEndpoint):
return 200, {}
class PushSetRuleAttrRestServlet(ReplicationEndpoint):
"""Updates an attr of a push rule
Request format:
POST /_synapse/replication/push_set_rule_attr/:user_id/:scope/:template/:rule_id/:attr
{
"vale": <new_val>,
}
"""
NAME = "push_set_rule_attr"
PATH_ARGS = ("user_id", "scope", "template", "rule_id", "attr")
CACHE = False
def __init__(self, hs: "HomeServer"):
super().__init__(hs)
self._push_rules_handler = hs.get_push_rules_handler()
@staticmethod
async def _serialize_payload( # type: ignore[override]
user_id: str,
scope: str,
template: str,
rule_id: str,
attr: str,
val: Union[bool, JsonDict],
) -> JsonDict:
payload = {"val": val}
return payload
async def _handle_request( # type: ignore[override]
self,
request: Request,
content: JsonDict,
user_id: str,
scope: str,
template: str,
rule_id: str,
attr: str,
) -> Tuple[int, JsonDict]:
spec = RuleSpec(scope=scope, template=template, rule_id=rule_id, attr=attr)
await self._push_rules_handler.set_rule_attr(user_id, spec, val=content["val"])
return 200, {}
def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
ReplicationRemovePusherRestServlet(hs).register(http_server)
PushSetRuleAttrRestServlet(hs).register(http_server)

View file

@ -27,7 +27,7 @@ from synapse.api.errors import (
SynapseError,
UnrecognizedRequestError,
)
from synapse.handlers.push_rules import InvalidRuleException, RuleSpec, check_actions
from synapse.handlers.push_rules import InvalidRuleException, check_actions
from synapse.http.server import HttpServer
from synapse.http.servlet import (
RestServlet,
@ -39,6 +39,7 @@ from synapse.push.rulekinds import PRIORITY_CLASS_MAP
from synapse.rest.client._base import client_patterns
from synapse.storage.push_rule import InconsistentRuleException, RuleNotFoundException
from synapse.types import JsonDict
from synapse.types.push import RuleSpec
from synapse.util.async_helpers import Linearizer
if TYPE_CHECKING:

25
synapse/types/push.py Normal file
View file

@ -0,0 +1,25 @@
#
# This file is licensed under the Affero General Public License (AGPL) version 3.
#
# Copyright (C) 2024 New Vector, Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# See the GNU Affero General Public License for more details:
# <https://www.gnu.org/licenses/agpl-3.0.html>.
from typing import Optional
import attr
@attr.s(slots=True, frozen=True, auto_attribs=True)
class RuleSpec:
scope: str
template: str
rule_id: str
attr: Optional[str]