Skip to content

Instantly share code, notes, and snippets.

@atdt
Last active August 29, 2015 14:09
Show Gist options
  • Save atdt/8dc4a4a280c2bf1aafb1 to your computer and use it in GitHub Desktop.
Save atdt/8dc4a4a280c2bf1aafb1 to your computer and use it in GitHub Desktop.
Running external commands with irclib
# -*- coding: utf-8 -*-
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.proc = subprocess.Popen(
command, stdout=subprocess.PIPE, 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 += self.proc.stdout.read()
if status is not None:
event = irclib.Event('external_command_exit', self.proc, '',
[status, self.buffer])
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