dbus notification, client side threads and more that i dont have strength to remember
This commit is contained in:
parent
4447468b77
commit
2bfc30a49a
92
client.py
92
client.py
@ -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
159
notification.py
Normal 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()
|
80
serveur.py
80
serveur.py
@ -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__':
|
||||||
|
Loading…
Reference in New Issue
Block a user