[Console] Refactor main to use async instead of callbacks

Use the new maybe_coroutine decorator to replace callbacks with inline
async/await for cleaner code.
This commit is contained in:
Calum Lind 2023-02-24 23:45:53 +00:00
parent 6c924e6128
commit 253eb2240b
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
1 changed files with 67 additions and 106 deletions

View File

@ -18,8 +18,7 @@ from twisted.internet import defer, error, reactor
import deluge.common
import deluge.component as component
from deluge.configmanager import ConfigManager
from deluge.decorators import overrides
from deluge.error import DelugeError
from deluge.decorators import maybe_coroutine, overrides
from deluge.ui.client import client
from deluge.ui.console.modes.addtorrents import AddTorrents
from deluge.ui.console.modes.basemode import TermResizeHandler
@ -160,82 +159,54 @@ deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent"
wrapper(self.run)
def quit(self):
@maybe_coroutine
async def quit(self):
if client.connected():
await client.disconnect()
def on_disconnect(result):
reactor.stop()
try:
reactor.stop()
except error.ReactorNotRunning:
pass
return client.disconnect().addCallback(on_disconnect)
else:
try:
reactor.stop()
except error.ReactorNotRunning:
pass
def exec_args(self, options):
@maybe_coroutine
async def exec_args(self, options):
"""Execute console commands from command line."""
from deluge.ui.console.cmdline.command import Commander
commander = Commander(self._commands)
def on_connect(result):
def on_components_started(result):
def on_started(result):
def do_command(result, cmd):
return commander.do_command(cmd)
def exec_command(result, cmd):
return commander.exec_command(cmd)
d = defer.succeed(None)
for command in options.parsed_cmds:
if command.command in ('quit', 'exit'):
break
d.addCallback(exec_command, command)
d.addCallback(do_command, 'quit')
return d
# We need to wait for the rpcs in start() to finish before processing
# any of the commands.
self.started_deferred.addCallback(on_started)
return self.started_deferred
d = self.start_console()
d.addCallback(on_components_started)
return d
def on_connect_fail(reason):
if reason.check(DelugeError):
rm = reason.getErrorMessage()
try:
if not self.interactive and options.parsed_cmds[0].command == 'connect':
await commander.exec_command(options.parsed_cmds.pop(0))
else:
rm = reason.value.message
daemon_options = (
options.daemon_addr,
options.daemon_port,
options.daemon_user,
options.daemon_pass,
)
log.info(
'Connect: host=%s, port=%s, username=%s',
*daemon_options[0:3],
)
await client.connect(*daemon_options)
except Exception as reason:
print(
'Could not connect to daemon: %s:%s\n %s'
% (options.daemon_addr, options.daemon_port, rm)
% (options.daemon_addr, options.daemon_port, reason)
)
commander.do_command('quit')
d = None
if not self.interactive and options.parsed_cmds[0].command == 'connect':
d = commander.exec_command(options.parsed_cmds.pop(0))
else:
log.info(
'connect: host=%s, port=%s, username=%s, password=%s',
options.daemon_addr,
options.daemon_port,
options.daemon_user,
options.daemon_pass,
)
d = client.connect(
options.daemon_addr,
options.daemon_port,
options.daemon_user,
options.daemon_pass,
)
d.addCallback(on_connect)
d.addErrback(on_connect_fail)
return d
await self.start_console()
# Wait for RPCs in start() to finish before processing commands.
await self.started_deferred
for cmd in options.parsed_cmds:
if cmd.command in ('quit', 'exit'):
break
await commander.exec_command(cmd)
commander.do_command('quit')
def run(self, stdscr):
"""This method is called by the curses.wrapper to start the mainloop and screen.
@ -353,61 +324,51 @@ deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent"
def is_active_mode(self, mode):
return mode == self.active_mode
def start_components(self):
def on_started(result):
component.pause(
[
'TorrentList',
'EventView',
'AddTorrents',
'TorrentDetail',
'Preferences',
]
)
@maybe_coroutine
async def start_components(self):
if not self.interactive:
return await component.start(['SessionProxy', 'ConsoleUI', 'CoreConfig'])
if self.interactive:
d = component.start().addCallback(on_started)
else:
d = component.start(['SessionProxy', 'ConsoleUI', 'CoreConfig'])
return d
await component.start()
component.pause(
[
'TorrentList',
'EventView',
'AddTorrents',
'TorrentDetail',
'Preferences',
]
)
def start_console(self):
# Maintain a list of (torrent_id, name) for use in tab completion
@maybe_coroutine
async def start_console(self):
self.started_deferred = defer.Deferred()
if not self.initialized:
self.initialized = True
d = self.start_components()
if self.initialized:
await component.stop(['SessionProxy'])
await component.start(['SessionProxy'])
else:
self.initialized = True
await self.start_components()
def on_stopped(result):
return component.start(['SessionProxy'])
@maybe_coroutine
async def start(self):
result = await client.core.get_session_state()
# Maintain a list of (torrent_id, name) for use in tab completion
self.torrents = []
self.events = []
d = component.stop(['SessionProxy']).addCallback(on_stopped)
return d
torrents = await client.core.get_torrents_status({'id': result}, ['name'])
for torrent_id, status in torrents.items():
self.torrents.append((torrent_id, status['name']))
def start(self):
def on_session_state(result):
self.torrents = []
self.events = []
def on_torrents_status(torrents):
for torrent_id, status in torrents.items():
self.torrents.append((torrent_id, status['name']))
self.started_deferred.callback(True)
client.core.get_torrents_status({'id': result}, ['name']).addCallback(
on_torrents_status
)
d = client.core.get_session_state().addCallback(on_session_state)
self.started_deferred.callback(True)
# Register event handlers to keep the torrent list up-to-date
client.register_event_handler('TorrentAddedEvent', self.on_torrent_added_event)
client.register_event_handler(
'TorrentRemovedEvent', self.on_torrent_removed_event
)
return d
def on_torrent_added_event(self, event, from_state=False):
def on_torrent_status(status):