-
-
Save mzmcbride/90467c8e95eafd0b346c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import os | |
import subprocess | |
import irclib | |
class ExternalCommand(irclib.Connection): | |
"""Represents an external command invocation made via irclib. | |
Sample usage | |
------------ | |
class Bot(ircbot.SingleServerIRCBot): | |
def on_welcome(self, connection, event): | |
ExternalCommand(self.ircobj, ['/bin/ls', '-a'], timeout=10) | |
def on_external_command_exit(self, connection, event): | |
self.connection.privmsg(self.chans, | |
'Exit status: %s; Output: %s' % (exit_status, command_output)) | |
def on_external_command_timeout(self, connection, event): | |
self.connection.privmsg(self.chans, 'Command timed out.') | |
""" | |
def __init__(self, irclibobj, command, shell=False, timeout=None): | |
""" | |
Constructor. | |
Parameters | |
---------- | |
irclibobj: irclib.IRC object. | |
command: command line as a list, e.g. ['/bin/ls', '-l']. | |
shell: passed to subprocess.Popen constructor. | |
timeout: if set, kill command after this many seconds. | |
""" | |
self.buffer = '' | |
self.irclibobj = irclibobj | |
self.irclibobj.connections.append(self) | |
self.command = command | |
self.proc = subprocess.Popen( | |
command, | |
stdin=subprocess.PIPE, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.STDOUT, | |
shell=shell | |
) | |
if timeout is not None: | |
self.execute_delayed(timeout, self.process_timeout) | |
def _get_socket(self): | |
"""Called by IRC.process_once() to get the file object to poll.""" | |
return self.proc.stdout | |
def process_data(self): | |
"""Read data from processes's stdout. Check if process terminated. | |
If it has, fire `external_command_exit` event.""" | |
status = self.proc.poll() | |
self.buffer += os.read(self.proc.stdout.fileno(), 1048576) | |
if status is not None: | |
event = irclib.Event('external_command_exit', self.proc, '', | |
[status, self.buffer, self.command]) | |
self.irclibobj._handle_event(self, event) | |
self.irclibobj._remove_connection(self) | |
def process_timeout(self): | |
"""If the external command has not yet terminated, kill it and fire | |
`external_command_timeout` event.""" | |
if self.proc.poll() is not None: | |
# No need to enforce timeout b/c process has already terminated. | |
return | |
self.proc.kill() | |
event = irclib.Event('external_command_timeout', self.proc, '') | |
self.irclibobj._handle_event(self, event) | |
self.irclibobj._remove_connection(self) | |
def disconnect(self): | |
"""Kill the external command's process and disenroll its stdout from | |
irclib's select().""" | |
self.proc.kill() | |
self.irclibobj._remove_connection(self) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment