Use trio guest mode

This commit is contained in:
Luke Murphy 2020-09-15 12:38:38 +02:00
parent 0e8f211807
commit 9975ff8163
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
2 changed files with 54 additions and 52 deletions

View File

@ -3,10 +3,10 @@
import logging import logging
import os import os
from signal import SIGINT, SIGTERM from signal import SIGINT, SIGTERM
from subprocess import PIPE, Popen, TimeoutExpired from subprocess import PIPE
from threading import Thread
import gi import gi
import trio
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0") gi.require_version("Gdk", "3.0")
@ -25,13 +25,14 @@ AUTO_CLIP_COPY_SIZE = -1
class DropShip: class DropShip:
"""Drag it, drop it, ship it.""" """Drag it, drop it, ship it."""
def __init__(self): def __init__(self, nursery):
"""Object initialisation.""" """Object initialisation."""
self.GLADE_FILE = "dropship.glade" self.GLADE_FILE = "dropship.glade"
self.CSS_FILE = "dropship.css" self.CSS_FILE = "dropship.css"
self.DOWNLOAD_DIR = os.path.expanduser("~") self.DOWNLOAD_DIR = os.path.expanduser("~")
self.clipboard = gtk.Clipboard.get(gdk.SELECTION_CLIPBOARD) self.clipboard = gtk.Clipboard.get(gdk.SELECTION_CLIPBOARD)
self.nursery = nursery
self.init_glade() self.init_glade()
self.init_css() self.init_css()
@ -98,78 +99,78 @@ class DropShip:
self.files_to_send = files self.files_to_send = files
if len(files) == 1: if len(files) == 1:
fpath = files[0].replace("file://", "") fpath = files[0].replace("file://", "")
Thread(target=self.wormhole_send, args=(self, fpath,)).start() self.nursery.start_soon(self.wormhole_send, fpath)
self.update_send_ui()
else: else:
log.info("Multiple file sending coming soon ™") log.info("Multiple file sending coming soon ™")
def update_send_ui(self): def on_recv(self, entry):
"""Manage UI response after adding files.""" """Handler for receiving transfers."""
self.drop_label.set_visible(False) self.nursery.start_soon(self.wormhole_recv, entry.get_text())
self.drop_label.set_vexpand(False)
self.drop_spinner.set_vexpand(True)
self.drop_spinner.set_visible(True)
self.drop_spinner.start()
def add_files(self, widget, event): def add_files(self, widget, event):
"""Handler for adding files with system interface""" """Handler for adding files with system interface"""
response = self.file_chooser.run() response = self.file_chooser.run()
if response == gtk.ResponseType.OK: if response == gtk.ResponseType.OK:
fpath = self.file_chooser.get_filenames()[0] fpath = self.file_chooser.get_filenames()[0]
Thread(target=self.wormhole_send, args=(self, fpath,)).start() self.nursery.start_soon(self.wormhole_send, fpath)
self.update_send_ui()
self.file_chooser.hide() self.file_chooser.hide()
def read_wormhole_send_code(self, process): async def wormhole_send(self, fpath):
"""Read wormhole send code from command-line output."""
while True:
output = (
process.stderr.readline()
) # (rra) Why is it printing to stderr tho?
if output == "" and process.poll() is not None:
print(output)
return # (rra) We need some exception handling here
if output:
log.info(output)
if output.startswith(b"Wormhole code is: "):
code_line = output.decode("utf-8")
return code_line.split()[-1]
def on_recv(self, entry):
"""Handler for receiving transfers."""
code = entry.get_text()
Thread(target=self.wormhole_recv, args=(self, code,)).start()
def wormhole_send(self, widget, fpath):
"""Run `wormhole send` on a local file path.""" """Run `wormhole send` on a local file path."""
command = ["wormhole", "send", fpath] command = ["wormhole", "send", fpath]
process = Popen(command, stderr=PIPE, stdout=PIPE) process = await trio.open_process(command, stderr=PIPE)
code = self.read_wormhole_send_code(process)
# UI response self.drop_label.set_visible(False)
self.drop_label.set_vexpand(False)
self.drop_spinner.set_vexpand(True)
self.drop_spinner.set_visible(True)
self.drop_spinner.start()
output = await process.stderr.receive_some()
code = output.decode().split()[-1]
self.drop_label.set_text(code)
self.drop_label.set_visible(True) self.drop_label.set_visible(True)
self.drop_label.set_selectable(True) self.drop_label.set_selectable(True)
self.drop_label.set_text(code)
self.drop_label.set_vexpand(True)
self.drop_spinner.stop() self.drop_spinner.stop()
self.drop_spinner.set_vexpand(False) self.drop_spinner.set_vexpand(False)
self.drop_spinner.set_visible(False) self.drop_spinner.set_visible(False)
self.clipboard.set_text(code, AUTO_CLIP_COPY_SIZE) await process.wait()
def wormhole_recv(self, widget, code): async def wormhole_recv(self, code):
"""Run `wormhole receive` with a pending transfer code.""" """Run `wormhole receive` with a pending transfer code."""
command = ["wormhole", "receive", "--accept-file", code] command = ["wormhole", "receive", "--accept-file", code]
process = Popen(command, stderr=PIPE) await trio.run_process(command, stderr=PIPE)
process.communicate()
def trio_run_with_gtk():
"""Run Trio and Gtk together."""
async def trio_main():
"""Trio main loop."""
async with trio.open_nursery() as nursery:
DropShip(nursery=nursery)
while True:
await trio.sleep(1) # Note(decentral1se): replace this hack
def done_callback(outcome):
glib.idle_add(gtk.main_quit)
def glib_schedule(function):
glib.idle_add(function)
trio.lowlevel.start_guest_run(
trio_main,
run_sync_soon_threadsafe=glib_schedule,
done_callback=done_callback,
host_uses_signal_set_wakeup_fd=True,
)
gtk.main()
if __name__ == "__main__": if __name__ == "__main__":
DropShip() trio_run_with_gtk()
gtk.main()

View File

@ -1,3 +1,4 @@
PyGObject==3.36.1 PyGObject==3.36.1
PyInstaller==3.6 PyInstaller==3.6
magic-wormhole==0.12.0 magic-wormhole==0.12.0
trio==0.16.0