dbus notification, client side threads and more that i dont have strength to remember

This commit is contained in:
Djalim Simaila 2023-03-23 01:39:25 +01:00
parent 4447468b77
commit 2bfc30a49a
3 changed files with 286 additions and 45 deletions

View File

@ -1,49 +1,85 @@
import pyperclip """
import socketio This script is a daemon that, on event, send and sync the clipboard with a
import reauests distant one
import os """
import threading
import time
import sys import sys
import subprocess import json
import pyperclip
import requests
import socketio
import zc.lockfile import zc.lockfile
# standard Python import notification as notif
# to put in a conf file # to put in a conf file
ip = 'simailadjalim.fr' ip = 'localhost'
port = "9564" port = "9564"
hostname = "WarMachine" hostname = "WarMachine"
username = "neotaku67" username = "neotaku67"
password = "un bon mot de passe de prefererance mais en sah tant qu'il est hashe ca passe" password = "un bon mot de passe de prefererance mais en sah tant qu'il est hashe ca passe"
sign = "[AllSync] "
"""
This script is a daemon that, on event, send and sync the clipboard with a distant one
"""
ip = f"http://{ip}:{port}/" ip = f"http://{ip}:{port}"
sio = socketio.Client() sio = socketio.Client()
sio.connect(ip) sio.connect(ip)
print("[Debug] Connected to Server .w.") print("[Debug] Connected to Server .w.")
auth = requests.post(f"{ip}/user",
data={"username": username, "password": password},
timeout=10000)
if auth.status_code != 200:
print("invalid credentials")
sys.exit()
token = json.loads(auth.content.decode())['token']
notify_stop_event = threading.Event()
# clipboard_stop_event = threading.Event()
def send_notification():
notif.start_monitoring()
while not notify_stop_event.is_set():
while not notif.notification_queue.empty():
notification = notif.notification_queue.get()
if notification.title.find(sign) == -1:
continue
requests.put(f"{ip}/notification",
data={"token": token,
"title": notification.title,
"content": notification.content,
"deviceName": hostname},
timeout=5000)
time.sleep(1)
notification_thread = threading.Thread(target=send_notification)
# clipboard_thread = threading.Thread(target=)
def sendSystemNotification(title:str,content:str):
"""
Une fonction pour 1. rendre le truc plus secure et
eviter que thomas face des rce sur mon pc .w. lmao
"""
subprocess.run(["notify-send",title,content])
@sio.event @sio.event
def NotificationUpdate(data): def NotificationUpdate(data):
content = data["content"] if data["device_name"] == hostname:
clipCmd = f'echo {content} | xclip' return
print(f"[ClipEvent] received data from ") response = requests.get(f"{ip}/notification/-1?token={token}",
os.system(clipCmd) timeout=2000)
response = json.loads(response.content.decode())["notifications"]
notification = notif.Notification(title=sign+response["title"],
content=response["content"])
notification.show()
print("[NotificationEvent] received data")
@sio.event @sio.event
def ClipboardUpdate(data): def ClipboardUpdate(data):
title, content = data["title"], data["content"] if data["device_name"] == hostname:
command = f'notify-send "{title}" "{content}"' return
print(command) clipboard = requests.get(f"{ip}/clipboard/-1?token={token}",
os.system(command) timeout=2000)
clipboard = json.loads(clipboard.content.decode())
clipboard = clipboard["clipboard"]
pyperclip.copy(clipboard)
print("[ClipboardEvent] received data")
sio.wait()
if __name__ == "__main__":
notification_thread.start()
sio.wait()

159
notification.py Normal file
View File

@ -0,0 +1,159 @@
#!/usr/bin/env python3
import dbus
import time
import queue
import threading
from gi.repository import GLib
import dbus
from dbus.mainloop.glib import DBusGMainLoop
class Notification:
"""
Reprensent a notification
:param name str:
This is the optional name of the application sending the notification.
This should be the application's formal name, rather than some sort of
ID. An example would be "FredApp E-Mail Client," rather than
"fredapp-email-client."
:param notification_id int:
An optional ID of an existing notification that this notification is
intended to replace.
:param notification_icon str:
The notification icon.(not yet fully understood, use at your own risks)
:param title str:
This is a single line overview of the notification. For instance, "You
have mail" or "A friend has come online". It should generally not be
longer than 40 characters, though this is not a requirement, and server
implementations should word wrap if necessary.
:param content str:
This is a multi-line body of text. Each line is a paragraph, server
implementations are free to word wrap them as they see fit.
The body mayfrom gi.repository import GLib
import dbus
from dbus.mainloop.glib import DBusGMainLoop
functionality may not be implemented by the notification
server, conforming clients should check if it is available before using
it (see the GetCapabilities message in Protocol). An implementation is
free to ignore any requested by the client. As an example one possible
rendering of actions would be as buttons in the notification popup.
Actions are sent over as a list of pairs. Each even element in the list
(starting at index 0) represents the identifier for the action. Each
odd element in the list is the localized string that will be displayed
to the user. The default action (usually invoked by clicking the
notification) should have a key named "default". The name can be
anything, though implementations are free not to display it.
:param hints dict:
Hints are a way to provide extra data to a notification server that the
server may be able to make use of. See
https://specifications.freedesktop.org/notification-spec/notification-\
spec-latest.html#hints for a list of available hints.
:param timeout int:
The timeout time in milliseconds since the display of the notification
at which the notification should automatically close. If -1,
the notification's expiration time is dependent on the notification
server's settings, and may vary for the type of notification.
If 0, the notification never expires.
"""
def __init__(self,
name: str = "",
notification_id: int = 0,
notification_icon: str = "",
title: str = "",
content: str = "",
actions: list = None,
hints: dict = None,
timeout: int = -1
) -> None:
self.name = name
self.notification_id = notification_id
self.notification_icon = notification_icon
self.title = title
self.content = content
self.actions = actions if actions is not None else []
self.hints = hints if hints is not None else {"urgency": 1}
self.timeout = timeout
def __str__(self) -> str:
return f"""{80*"_"}
Notification :
name = {self.name}
notification_id = {self.notification_id}sleep
notification_icon = {self.notification_icon}
title = {self.title}
content = {self.content}
actions = {self.actions}
hints = {self.hints}
timeout = {self.timeout}
{80*"_"}"""
def show(self):
"""
Display the notification by sending notification event
to the dbus interface
"""
obj = dbus.Interface(dbus.SessionBus()
.get_object("org.freedesktop.Notifications",
"/org/freedesktop/Notifications"),
"org.freedesktop.Notifications")
obj.Notify(self.name,
self.notification_id,
self.notification_icon,
self.title,
self.content,
self.actions,
self.hints,
self.timeout)
notification_queue = queue.Queue()
def log_notification(bus, message):
keys = ["app_name", "replaces_id", "app_icon", "summary",
"body", "actions", "hints", "expire_timeout"]
args = message.get_args_list()
if len(args) == 8:
notif = dict([(keys[i], args[i]) for i in range(8)])
notif = Notification(args[0],
args[1],
args[2],
args[3],
args[4],
list(args[5]),
dict(args[6]),
args[7],)
notification_queue.put(notif)
stop_event = threading.Event()
def monitor_notifications():
loop = DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
session_bus.add_match_string(
"type='method_call',interface='org.freedesktop.Notifications'\
,member='Notify',eavesdrop=true")
session_bus.add_message_filter(log_notification)
while not stop_event.is_set():
GLib.MainLoop().run()
thread = threading.Thread(target=monitor_notifications)
thread.daemon = True
def start_monitoring():
thread.start()
def stop_monitoring():
stop_event.set()
if __name__ == "__main__":
n = Notification(title="test",content="je suis le test")
n.show()

View File

@ -116,7 +116,10 @@ def add_notification():
notification) notification)
con.commit() con.commit()
con.close() con.close()
socketio.emit("NotificationUpdate", broadcast=True) socketio.emit("NotificationUpdate",
data={"device_name": device_name},
broadcast=True)
return {"status": "ok"}, 200 return {"status": "ok"}, 200
except: except:
return {"status": "error"}, 500 return {"status": "error"}, 500
@ -132,9 +135,46 @@ def get_notifications():
token = request.values.get("token") token = request.values.get("token")
con = sqlite3.connect("database.db") con = sqlite3.connect("database.db")
cur = con.cursor() cur = con.cursor()
notifications = cur.execute("SELECT title,content FROM NOTIFICATION WHERE \ notifications = cur.execute("SELECT title,content \
token=?", (token, )).fetchall() FROM NOTIFICATION \
return {"status": "ok", "notifications": notifications}, 200 WHERE token=?",
(token, )).fetchall()
data = {"status": "ok"}
data["notifications"] = []
for notification in notifications:
data["notifications"].append({"title": notification[0],"content": notification[1]})
return data, 200
@app.route("/notification/<notifid>", methods=['GET'])
def get_notification_by_id(notifid):
"""
Le but de cet app se resume a cette fonction, elle recoit une requete
http et renvoie via le websocket le contenu de la requette a tout les
client.
"""
notifid = int(notifid)
token = request.values.get("token")
con = sqlite3.connect("database.db")
cur = con.cursor()
if notifid == -1:
notifications = cur.execute("SELECT title,content \
FROM NOTIFICATION \
WHERE token=?\
ORDER BY id DESC \
LIMIT 1",
(token,)).fetchone()
else:
notifications = cur.execute("SELECT title,content \
FROM NOTIFICATION \
WHERE token=? AND id=?",
(token, notifid)).fetchone()
return {"status": "ok",
"notifications": {"title": notifications[0],
"content": notifications[1]
}
}, 200
############################################################################### ###############################################################################
@ -159,7 +199,9 @@ def add_clipboard():
cur.execute("INSERT INTO CLIPBOARD VALUES (null,?,?,?,?)", clipboard) cur.execute("INSERT INTO CLIPBOARD VALUES (null,?,?,?,?)", clipboard)
con.commit() con.commit()
con.close() con.close()
socketio.emit("ClipboardUpdate", broadcast=True) socketio.emit("ClipboardUpdate",
data={"device_name": device_name},
broadcast=True)
return {"status": "ok"}, 200 return {"status": "ok"}, 200
except: except:
return {"status": "error"}, 500 return {"status": "error"}, 500
@ -175,10 +217,14 @@ def get_clipboard():
token = request.values.get("token") token = request.values.get("token")
con = sqlite3.connect("database.db") con = sqlite3.connect("database.db")
cur = con.cursor() cur = con.cursor()
clipboard = cur.execute("SELECT content, id FROM CLIPBOARD WHERE \ clipboard = cur.execute("SELECT content \
token=?", (token, )).fetchall() FROM CLIPBOARD \
WHERE token=?",
(token, )).fetchall()
return {"status": "ok", "clipboard": clipboard}, 200 return {"status": "ok", "clipboard": clipboard}, 200
@app.route("/clipboard/<clipid>", methods=['GET']) @app.route("/clipboard/<clipid>", methods=['GET'])
def get_clipboard_by_id(clipid): def get_clipboard_by_id(clipid):
""" """
@ -191,19 +237,19 @@ def get_clipboard_by_id(clipid):
con = sqlite3.connect("database.db") con = sqlite3.connect("database.db")
cur = con.cursor() cur = con.cursor()
if clipid == -1: if clipid == -1:
clipboard = cur.execute("SELECT content,id \ clipboard = cur.execute("SELECT content \
FROM CLIPBOARD \ FROM CLIPBOARD \
WHERE token=? \ WHERE token=? \
ORDER BY id DESC \ ORDER BY id DESC \
LIMIT 1", LIMIT 1",
(token,)).fetchall() (token,)).fetchone()
else: else:
clipboard = cur.execute("SELECT content,id FROM CLIPBOARD WHERE \ clipboard = cur.execute("SELECT content \
token=? AND\ FROM CLIPBOARD \
id=?", token=? AND id=?",
(token, clipid)).fetchone() (token, clipid)).fetchone()
return {"status": "ok", "clipboard": clipboard}, 200 return {"status": "ok", "clipboard": clipboard[0]}, 200
if __name__ == '__main__': if __name__ == '__main__':