Add real-time bridge status push option

This commit is contained in:
Tulir Asokan
2021-06-09 20:04:17 +03:00
parent ec152cbd9d
commit c385aa0b8d
4 changed files with 32 additions and 12 deletions
+4
View File
@@ -10,6 +10,10 @@ homeserver:
asmux: false
# Number of retries for all HTTP requests if the homeserver isn't reachable.
http_retry_count: 4
# The URL to push real-time bridge status to.
# If set, the bridge will make POST requests to this URL whenever a user's Telegram connection state changes.
# The bridge will use the appservice as_token to authorize requests.
status_endpoint: null
# Application service host/registration related details
# Changing these values requires regeneration of the registration.
+25 -9
View File
@@ -15,7 +15,6 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import (Awaitable, Dict, List, Iterable, NamedTuple, Optional, Tuple, Any, cast,
TYPE_CHECKING)
from collections import defaultdict
from datetime import datetime, timezone
import logging
import asyncio
@@ -32,7 +31,7 @@ from telethon.tl.functions.account import UpdateStatusRequest
from mautrix.client import Client
from mautrix.errors import MatrixRequestError, MNotFound
from mautrix.types import UserID, RoomID, PushRuleScope, PushRuleKind, PushActionType, RoomTagInfo
from mautrix.bridge import BaseUser
from mautrix.bridge import BaseUser, BridgeState
from mautrix.util.logging import TraceLogger
from mautrix.util.opt_prometheus import Gauge
@@ -52,6 +51,11 @@ SearchResult = NamedTuple('SearchResult', puppet='pu.Puppet', similarity=int)
METRIC_LOGGED_IN = Gauge('bridge_logged_in', 'Users logged into bridge')
METRIC_CONNECTED = Gauge('bridge_connected', 'Users connected to Telegram')
BridgeState.human_readable_errors.update({
"tg-not-connected": "Your Telegram connection failed",
"logged-out": "You're not logged into Telegram",
})
class User(AbstractUser, BaseUser):
log: TraceLogger = logging.getLogger("mau.user")
@@ -74,8 +78,9 @@ class User(AbstractUser, BaseUser):
saved_contacts: int = 0, is_bot: bool = False,
db_portals: Optional[Iterable[Tuple[TelegramID, TelegramID]]] = None,
db_instance: Optional[DBUser] = None) -> None:
super().__init__()
AbstractUser.__init__(self)
self.mxid = mxid
BaseUser.__init__(self)
self.tgid = tgid
self.is_bot = is_bot
self.username = username
@@ -87,12 +92,8 @@ class User(AbstractUser, BaseUser):
self.db_portals = db_portals or []
self._db_instance = db_instance
self._ensure_started_lock = asyncio.Lock()
self.dm_update_lock = asyncio.Lock()
self._metric_value = defaultdict(lambda: False)
self._track_connection_task = None
self.command_status = None
(self.relaybot_whitelisted,
self.whitelisted,
self.puppet_whitelisted,
@@ -104,8 +105,6 @@ class User(AbstractUser, BaseUser):
if tgid:
self.by_tgid[tgid] = self
self.log = self.log.getChild(self.mxid)
@property
def name(self) -> str:
return self.mxid
@@ -219,6 +218,21 @@ class User(AbstractUser, BaseUser):
connected = bool(self.client._sender._transport_connected
if self.client and self.client._sender else False)
self._track_metric(METRIC_CONNECTED, connected)
await self.push_bridge_state(ok=connected, ttl=3600 if connected else 240,
error="tg-not-connected" if not connected else None)
async def fill_bridge_state(self, state: BridgeState) -> None:
await super().fill_bridge_state(state)
state.remote_id = str(self.tgid)
state.remote_name = self.human_tg_id
async def get_bridge_state(self) -> BridgeState:
if not self.client:
return BridgeState(ok=False, error="logged-out")
elif not self.client._sender or not self.client._sender._transport_connected:
return BridgeState(ok=False, error="tg-not-connected")
else:
return BridgeState(ok=True)
async def stop(self) -> None:
await super().stop()
@@ -226,6 +240,7 @@ class User(AbstractUser, BaseUser):
self._track_connection_task.cancel()
self._track_connection_task = None
self._track_metric(METRIC_CONNECTED, False)
await self.push_bridge_state(ok=False, error="tg-not-connected")
async def post_login(self, info: TLUser = None, first_login: bool = False) -> None:
if config["metrics.enabled"] and not self._track_connection_task:
@@ -330,6 +345,7 @@ class User(AbstractUser, BaseUser):
self.delete()
await self.stop()
self._track_metric(METRIC_LOGGED_IN, False)
await self.push_bridge_state(ok=False, error="logged-out")
return True
def _search_local(self, query: str, max_results: int = 5, min_similarity: int = 45
+2 -2
View File
@@ -15,13 +15,13 @@ qrcode>=6,<7
moviepy>=1,<2
#/metrics
prometheus_client>=0.6,<0.11
prometheus_client>=0.6,<0.12
#/postgres
psycopg2-binary>=2,<3
#/e2be
asyncpg>=0.20,<0.23
asyncpg>=0.20,<0.24
python-olm>=3,<4
pycryptodome>=3,<4
unpaddedbase64>=1,<2
+1 -1
View File
@@ -5,6 +5,6 @@ python-magic>=0.4,<0.5
commonmark>=0.8,<0.10
aiohttp>=3,<4
yarl>=1,<2
mautrix>=0.9.1,<0.10
mautrix>=0.9.3,<0.10
telethon>=1.20,<1.22
telethon-session-sqlalchemy>=0.2.14,<0.3