|
@ -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.""" |
|
|
"""Run `wormhole send` on a local file path.""" |
|
|
|
|
|
command = ["wormhole", "send", fpath] |
|
|
|
|
|
process = await trio.open_process(command, stderr=PIPE) |
|
|
|
|
|
|
|
|
while True: |
|
|
self.drop_label.set_visible(False) |
|
|
output = ( |
|
|
self.drop_label.set_vexpand(False) |
|
|
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): |
|
|
self.drop_spinner.set_vexpand(True) |
|
|
"""Handler for receiving transfers.""" |
|
|
self.drop_spinner.set_visible(True) |
|
|
code = entry.get_text() |
|
|
self.drop_spinner.start() |
|
|
Thread(target=self.wormhole_recv, args=(self, code,)).start() |
|
|
|
|
|
|
|
|
|
|
|
def wormhole_send(self, widget, fpath): |
|
|
output = await process.stderr.receive_some() |
|
|
"""Run `wormhole send` on a local file path.""" |
|
|
code = output.decode().split()[-1] |
|
|
command = ["wormhole", "send", fpath] |
|
|
|
|
|
process = Popen(command, stderr=PIPE, stdout=PIPE) |
|
|
|
|
|
code = self.read_wormhole_send_code(process) |
|
|
|
|
|
|
|
|
|
|
|
# UI response |
|
|
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() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
def trio_run_with_gtk(): |
|
|
DropShip() |
|
|
"""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() |
|
|
gtk.main() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
trio_run_with_gtk() |
|
|