Sleep when idle and wake on activity.
authorCMDR furrycat <elite@furrycat.net>
Wed, 28 Sep 2016 14:59:58 +0000 (15:59 +0100)
committerCMDR furrycat <elite@furrycat.net>
Wed, 28 Sep 2016 14:59:58 +0000 (15:59 +0100)
bot.py

diff --git a/bot.py b/bot.py
index f144909..05b1c13 100755 (executable)
--- a/bot.py
+++ b/bot.py
@@ -13,6 +13,7 @@ import pexpect
 import random
 import re
 import sys
+import time
 from PIL import Image
 
 dryrun = os.getenv('DRYRUN') is not None
@@ -85,10 +86,52 @@ def wait_for_prompt(p):
   p.expect('EDI> ')
 
 @asyncio.coroutine
+def set_avatar(url):
+  if re.match(r'!https?:', url):
+    fd = open_url(url)
+  else:
+    fd = open(url, 'rb')
+  if fd is None:
+    log.debug('Failed to open URL {} for avatar'.format(url))
+    return False
+  try:
+    yield from client.edit_profile(avatar = fd.read())
+    fd.close()
+    return True
+  except:
+    fd.close()
+    raise
+    return False
+
+@asyncio.coroutine
+def set_idle(idle):
+  yield from client.change_status(idle = idle)
+
+@asyncio.coroutine
+def wake_up(force = False):
+  for server in client.servers:
+    if force or server.me.status != discord.Status.online:
+      log.info('Waking up...')
+      yield from set_avatar('avatar_online.png')
+      yield from set_idle(False)
+    awake_since = time.time()
+    break
+
+@asyncio.coroutine
+def zzz():
+  for server in client.servers:
+    if server.me.status != discord.Status.idle:
+      log.info('Sleeping...')
+      yield from set_avatar('avatar_idle.png')
+      yield from set_idle(True)
+    break
+
+@asyncio.coroutine
 def maybe_say(channel, text, probability = 0.2):
   if random.random() <= probability:
     yield from client.send_typing(channel)
     yield from client.send_message(channel, text)
+    yield from wake_up()
     return True
   else:
     log.debug("Didn't bother to say {}".format(text))
@@ -103,7 +146,7 @@ def say(channel, text):
 def say_expect(message, stdout):
   if stdout:
     log.debug(stdout)
-    yield from client.send_message(message.channel, '{}```{}```'.format('{} '.format(message.author.mention) if not message.channel.is_private else '', stdout))
+    yield from say(message.channel, '{}```{}```'.format('{} '.format(message.author.mention) if not message.channel.is_private else '', stdout))
   else:
     yield from say(message.channel, 'Sorry!')
 
@@ -353,7 +396,7 @@ def greet(channel, member):
     if dryrun:
       log.info('Not sending greeting {}'.format(message))
     else:
-      yield from client.send_message(channel, message)
+      yield from say(channel, message)
 
 @asyncio.coroutine
 def set_rss_permissions(feed):
@@ -362,7 +405,7 @@ def set_rss_permissions(feed):
     log.warning("Can't get channel {} for feed {}.".format(feed['channel'], feed['url']))
     return
   role = None
-  for server_role in channel.server.get_member(client.user.id).roles:
+  for server_role in channel.server.me.roles:
     if server_role.name == 'Robocat':
       role = server_role
       break
@@ -420,7 +463,7 @@ def do_rss(feed):
         log.info('Dryrun: Not posting to {}: {}'.format(channel, formatted))
       else:
         log.info('Posting to {}: {}'.format(channel, formatted))
-        message = yield from client.send_message(channel, formatted)
+        message = yield from say(channel, formatted)
         digest = hashlib.sha224(message.content.encode('utf-8')).hexdigest()
         digests.append(digest)
         log.debug('Posted RSS with digest {}'.format(digest))
@@ -435,6 +478,17 @@ def do_feeds(feeds):
       yield from do_rss(feed)
     yield from asyncio.sleep(rsstime)
 
+@asyncio.coroutine
+def maybe_sleep():
+  while True:
+    for server in client.servers:
+      if server.me.status != discord.Status.idle:
+        now = time.time()
+        if now - last_spoke >= idletime:
+          yield from zzz()
+      break
+    yield from asyncio.sleep(60)
+
 p = pexpect.spawnu('./edi.py')
 wait_for_prompt(p)
 
@@ -461,6 +515,9 @@ modules = {
   }
 }
 
+idletime = 7200
+
+last_spoke = time.time()
 client = discord.Client()
 
 @asyncio.coroutine
@@ -505,6 +562,7 @@ def should_greet_member_in(channel, member, role_name = 'Unassigned', minimum =
 def on_ready():
   print('Logged in as {}#{}'.format(client.user.name, client.user.id))
   print('Admins are: {}'.format(admins))
+  yield from wake_up(True)
   channels = yield from channels_to_greet()
   print('Greeting in {}'.format([channel.name for channel in channels]))
   for channel in channels:
@@ -518,7 +576,8 @@ def on_ready():
     log.debug('Maybe unassigning {}'.format(member.name))
     yield from set_unassigned(member)
   print('RSS feeds: {}'.format([feed['description'] for feed in feeds if 'description' in feed]))
-  yield from do_feeds(feeds)
+  asyncio.async(do_feeds(feeds))
+  asyncio.async(maybe_sleep())
 
 @client.event
 @asyncio.coroutine