mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-13 06:35:24 +03:00
Implement webpush from server
This commit is contained in:
parent
5398a661ff
commit
f946690520
@ -38,4 +38,5 @@ google-generativeai == 0.6.*
|
||||
ollama == 0.2.*
|
||||
openai == 1.30.*
|
||||
# push notifications
|
||||
py-vapid == 1.9.*
|
||||
py-vapid == 1.9.*
|
||||
pywebpush == 2.0.*
|
||||
@ -41,13 +41,13 @@ def get_vapid_pub_key():
|
||||
def register_notifications():
|
||||
username = request.headers.get("remote-user", type=str) or "admin"
|
||||
json: dict[str, any] = request.get_json(silent=True) or {}
|
||||
token = json["token"]
|
||||
sub = json.get("sub")
|
||||
|
||||
if not token:
|
||||
return jsonify({"success": False, "message": "Token must be provided."}), 400
|
||||
if not sub:
|
||||
return jsonify({"success": False, "message": "Subscription must be provided."}), 400
|
||||
|
||||
try:
|
||||
User.update(notification_tokens=User.notification_tokens.append(token)).where(
|
||||
User.update(notification_tokens=User.notification_tokens.append(sub)).where(
|
||||
User.username == username
|
||||
).execute()
|
||||
return make_response(
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
"""Handle sending notifications for Frigate via Firebase."""
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Callable
|
||||
|
||||
from py_vapid import Vapid01
|
||||
from pywebpush import WebPusher
|
||||
|
||||
from frigate.comms.dispatcher import Communicator
|
||||
from frigate.config import FrigateConfig
|
||||
@ -20,17 +22,17 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
||||
|
||||
def __init__(self, config: FrigateConfig) -> None:
|
||||
self.config = config
|
||||
self.claim = None
|
||||
self.claim_headers = None
|
||||
self.web_pushers: list[WebPusher] = []
|
||||
|
||||
# Pull keys from PEM or generate if they do not exist
|
||||
self.key = Vapid01.from_file(os.path.join(CONFIG_DIR, "notifications.pem"))
|
||||
|
||||
self.tokens = []
|
||||
self.invalid_tokens = []
|
||||
self.vapid = Vapid01.from_file(os.path.join(CONFIG_DIR, "notifications.pem"))
|
||||
|
||||
users: list[User] = User.select(User.notification_tokens).dicts().iterator()
|
||||
|
||||
for user in users:
|
||||
self.tokens.extend(user["notification_tokens"])
|
||||
for sub in user["notification_tokens"]:
|
||||
self.web_pushers.append(WebPusher(sub))
|
||||
|
||||
def subscribe(self, receiver: Callable) -> None:
|
||||
"""Wrapper for allowing dispatcher to subscribe."""
|
||||
@ -42,6 +44,20 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
||||
self.send_message(json.loads(payload))
|
||||
|
||||
def send_message(self, payload: dict[str, any]) -> None:
|
||||
# check for valid claim or create new one
|
||||
now = datetime.datetime.now().timestamp()
|
||||
if self.claim is None or self.claim["exp"] < now:
|
||||
# create new claim
|
||||
self.claim = {
|
||||
"sub": "mailto:test@example.com",
|
||||
"aud": "https://fcm.googleapis.com",
|
||||
"exp": (
|
||||
datetime.datetime.now() + datetime.timedelta(hours=1)
|
||||
).timestamp(),
|
||||
}
|
||||
self.claim_headers = self.vapid.sign(self.claim)
|
||||
logger.info(f"Updated claim with new headers {self.claim_headers}")
|
||||
|
||||
# Only notify for alerts
|
||||
if payload["after"]["severity"] != "alert":
|
||||
return
|
||||
@ -72,5 +88,17 @@ class WebPushClient(Communicator): # type: ignore[misc]
|
||||
direct_url = f"{self.config.notifications.base_url}/review?id={reviewId}"
|
||||
image = f'{self.config.notifications.base_url}{payload["after"]["thumb_path"].replace("/media/frigate", "")}'
|
||||
|
||||
for pusher in self.web_pushers:
|
||||
pusher.send(
|
||||
headers=self.claim_headers,
|
||||
ttl=0,
|
||||
data=json.dumps({
|
||||
"title": title,
|
||||
"message": message,
|
||||
"direct_url": direct_url,
|
||||
"image": image,
|
||||
}),
|
||||
)
|
||||
|
||||
def stop(self) -> None:
|
||||
pass
|
||||
|
||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "frigate",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@ -70,7 +70,10 @@ export default function NotificationView() {
|
||||
// TODO make the notifications button show enable / disable depending on current state
|
||||
}
|
||||
<Button
|
||||
disabled={notificationsSubscribed == undefined}
|
||||
disabled={
|
||||
notificationsSubscribed == undefined ||
|
||||
publicKey == undefined
|
||||
}
|
||||
onClick={() => {
|
||||
Notification.requestPermission().then((permission) => {
|
||||
console.log("notification permissions are ", permission);
|
||||
@ -79,7 +82,10 @@ export default function NotificationView() {
|
||||
.register(NOTIFICATION_SERVICE_WORKER)
|
||||
.then((registration) => {
|
||||
registration.pushManager
|
||||
.subscribe()
|
||||
.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: publicKey,
|
||||
})
|
||||
.then((pushSubscription) => {
|
||||
console.log(pushSubscription.endpoint);
|
||||
axios.post("notifications/register", {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user