Created
          October 9, 2018 05:21 
        
      - 
      
- 
        Save jlu5/78f0504c4e38ad434e1742f9454c0ef2 to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or 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
    
  
  
    
  | From 68e7cdd057a5a3a0a7cf8d4acf01c7daf2a10ed1 Mon Sep 17 00:00:00 2001 | |
| From: James Lu <[email protected]> | |
| Date: Fri, 5 Oct 2018 23:39:04 -0700 | |
| Subject: [PATCH] [WIP] discord madness, pass 1 | |
| --- | |
| classes.py | 7 ++- | |
| protocols/discord.py | 136 +++++++++++++++++++++++++++++++++++++++++++ | |
| 2 files changed, 142 insertions(+), 1 deletion(-) | |
| create mode 100644 protocols/discord.py | |
| diff --git a/classes.py b/classes.py | |
| index 0ced7db..0f2a918 100644 | |
| --- a/classes.py | |
| +++ b/classes.py | |
| @@ -229,7 +229,10 @@ class PyLinkNetworkCore(structures.CamelCaseToSnakeCase): | |
| self.name = netname | |
| self.conf = conf.conf | |
| self.sid = None | |
| - self.serverdata = conf.conf['servers'][netname] | |
| + try: | |
| + self.serverdata = conf.conf['servers'][netname] | |
| + except KeyError: | |
| + self.serverdata = {} | |
| self.protoname = self.__class__.__module__.split('.')[-1] # Remove leading pylinkirc.protocols. | |
| self.proto = self.irc = self # Backwards compat | |
| @@ -258,6 +261,8 @@ class PyLinkNetworkCore(structures.CamelCaseToSnakeCase): | |
| self.was_successful = False | |
| + self.virtual_parent = None | |
| + | |
| self._init_vars() | |
| def log_setup(self): | |
| diff --git a/protocols/discord.py b/protocols/discord.py | |
| new file mode 100644 | |
| index 0000000..4a86019 | |
| --- /dev/null | |
| +++ b/protocols/discord.py | |
| @@ -0,0 +1,136 @@ | |
| +import discord | |
| +import asyncio | |
| +import time # for testing | |
| + | |
| +from pylinkirc import utils, conf | |
| +from pylinkirc.classes import * | |
| +from pylinkirc.log import log | |
| + | |
| +class DiscordServer(PyLinkNetworkCoreWithUtils): | |
| + def __init__(self, name, parent): | |
| + super().__init__(name) | |
| + self.virtual_parent = parent | |
| + | |
| + def _init_vars(self): | |
| + super()._init_vars() | |
| + self.casemapping = 'ascii' # TODO: investigate utf-8 support | |
| + self.cmodes = {'op': 'o', 'voice': 'v'} | |
| + | |
| +class PyLinkDiscordProtocol(PyLinkNetworkCoreWithUtils): | |
| + | |
| + def __init__(self, *args, **kwargs): | |
| + super().__init__(*args, **kwargs) | |
| + self._hooks_queue = queue.Queue() | |
| + self.client = discord.Client() | |
| + | |
| + events = ['on_ready'] | |
| + for fn_name in events: | |
| + wrapped_fn = self.client.event(getattr(self, fn_name)) | |
| + setattr(self, fn_name, wrapped_fn) | |
| + | |
| + self._children = {} | |
| + | |
| + def _process_hooks(self): | |
| + """Loop to process incoming hook data.""" | |
| + while not self._aborted.is_set(): | |
| + data = self._hooks_queue.get() | |
| + if data is None: | |
| + log.debug('(%s) Stopping queue thread due to getting None as item', self.name) | |
| + break | |
| + elif self not in world.networkobjects.values(): | |
| + log.debug('(%s) Stopping stale queue thread; no longer matches world.networkobjects', self.name) | |
| + break | |
| + | |
| + subserver, data = data | |
| + if subserver not in world.networkobjects: | |
| + log.error('(%s) Not queuing hook for subserver %r no longer in networks list.', | |
| + self.name, subserver) | |
| + elif subserver in self._children: | |
| + self._children[subserver].call_hooks(data) | |
| + | |
| + def _add_hook(self, subserver, data): | |
| + """ | |
| + Pushes a hook payload for the given subserver. | |
| + """ | |
| + if subserver not in self._children: | |
| + raise ValueError("Unknown subserver %s" % subserver) | |
| + self._hooks_queue.put_nowait(( | |
| + subserver, | |
| + [None, 'ENDBURST', {}] | |
| + )) | |
| + | |
| + def _create_child(self, name): | |
| + """ | |
| + Creates a virtual network object for a server with the given name. | |
| + """ | |
| + if name in world.networkobjects: | |
| + raise ValueError("Attempting to reintroduce network with name %r" % name) | |
| + child = DiscordServer(name, self) | |
| + world.networkobjects[name] = self._children[name] = child | |
| + return child | |
| + | |
| + def _remove_child(self, name): | |
| + """ | |
| + Removes a virtual network object with the given name. | |
| + """ | |
| + self._add_hook(name, [None, 'PYLINK_DISCONNECT', {}]) | |
| + del self._children[name] | |
| + del world.networkobjects[name] | |
| + | |
| + def connect(self): | |
| + self._aborted.clear() | |
| + if 'token' not in self.serverdata: | |
| + raise ProtocolError("No API token defined under server settings") | |
| + | |
| + self._queue_thread = threading.Thread(name="Queue thread for %s" % self.name, | |
| + target=self._process_hooks, daemon=True) | |
| + self._queue_thread.start() | |
| + | |
| + self.client.loop.run_until_complete( | |
| + self.client.start(self.serverdata['token']) | |
| + ) | |
| + | |
| + def disconnect(self): | |
| + self._aborted.set() | |
| + | |
| + log.debug('(%s) Killing hooks handler', self.name) | |
| + try: | |
| + # XXX: queue.Queue.queue isn't actually documented, so this is probably not reliable in the long run. | |
| + with self._hooks_queue.mutex: | |
| + self._hooks_queue.queue[0] = None | |
| + except IndexError: | |
| + self._hooks_queue.put(None) | |
| + | |
| + log.debug('(%s) Sending Discord logout', self.name) | |
| + | |
| + async def exception_to_shutdown(loop, context): | |
| + await self.client.logout() | |
| + | |
| + # Force a shutdown by overriding the exception handler | |
| + #self.client.loop.set_exception_handler(exception_to_shutdown) | |
| + #self.client.loop.call_exception_handler( | |
| + # {'message': 'disconnect() called from outside event loop'} | |
| + #) | |
| + #while self.client.loop.is_running(): | |
| + # time.sleep(0.5) | |
| + #self.client.loop.stop() | |
| + self.client.loop.run_until_complete(self.client.logout()) | |
| + | |
| + ''' | |
| + async def on_message(self, message): | |
| + log.debug('got message %s', message) | |
| + await self.client.send_message(message.channel, 'Hello World!') | |
| + ''' | |
| + | |
| + @asyncio.coroutine | |
| + async def on_ready(self): | |
| + for server in self.client.servers: | |
| + pylink_netobj = self._create_child(server.name) | |
| + for channel in server.channels: | |
| + if channel.type == discord.ChannelType.text: | |
| + pylink_netobj.channels[channel.name] = Channel(pylink_netobj, name=channel.name) | |
| + await self.client.send_message(channel, 'Hello World! It is currently %s' % time.ctime()) | |
| + | |
| + self._add_hook(server.name, [None, 'ENDBURST', {}]) | |
| + | |
| +Class = PyLinkDiscordProtocol | |
| -- | |
| 2.19.0 | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment