Announcements in database.
authorCMDR furrycat <elite@furrycat.net>
Mon, 3 Oct 2016 21:12:43 +0000 (22:12 +0100)
committerCMDR furrycat <elite@furrycat.net>
Mon, 3 Oct 2016 21:12:43 +0000 (22:12 +0100)
bot.py
db.py

diff --git a/bot.py b/bot.py
index c043443..ebf8762 100755 (executable)
--- a/bot.py
+++ b/bot.py
@@ -62,9 +62,6 @@ bots = {
     ],
     'greetings': [
       { 'channel': 222685317885329408, 'message': 'Welcome to Delta Squadron, take a look at #delta_rules and make yourself at home in the public lobby. If interested in joining please PM a member of the High Command or Council for assistance', 'voice': 222103336483028993, 'sound': 'meow.wav' }
-    ],
-    'orders': [
-      { 'channel': 222071904029114371, 'message': '**\\* DELTA SQUADRON GENERAL ORDERS \\***\n\\* 30 SEPT 3302 \\*\nNon-combat missions - TOMANI\nSave all Delta bounties until Sunday evening and then hand in at Tomani\n**\\* END TRANSMISSION \\***', 'seconds': 43200 }
     ]
   },
   # catbot beta
@@ -76,9 +73,6 @@ bots = {
     ],
     'greetings': [
       { 'channel': 225217541922881538, 'message': 'Welcome to Catbot', 'voice': 231296897938227201, 'sound': 'meow.wav' }
-    ],
-    'orders': [
-      { 'channel': 231374099765657600, 'message': '**\\* DELTA SQUADRON GENERAL ORDERS \\***\n\\* 30 SEPT 3302 \\*\nNon-combat missions - TOMANI\nSave all Delta bounties until Sunday evening and then hand in at Tomani\n**\\* END TRANSMISSION \\***', 'seconds': 43200 }
     ]
   }
 }
@@ -601,19 +595,59 @@ def give_order(order, digest = None):
     pass
 
 @asyncio.coroutine
-def do_orders():
+def announce(announcement):
+  channel = client.get_channel(str(announcement['channel_id']))
+  if channel is None:
+    log.warning("Can't get channel for announcement {}".format(announcement['message']))
+    return
+
+  # @everyone mention mangles the digest
+  text = announcement['message']
+  mention = announcement['mention']
+  if mention:
+    if mention in ['everyone', 'here']:
+      text = '@{}\n{}'.format(mention, text)
+    else:
+      text = '<@{}>\n{}'.format(mention, text)
+
+  cutoff = datetime.datetime.utcnow() - datetime.timedelta(0, announcement['interval'])
+  logs = yield from client.logs_from(channel, after = cutoff)
+  digest = announcement['digest']
+  for message in logs:
+    raw = re.sub(r'^(<?@\S+\s)+', '', message.content).strip()
+    if hashlib.sha224(raw.encode('utf-8')).hexdigest() == digest:
+      log.debug('Saw previously posted announcement with digest {}'.format(digest))
+      return
+
+  try:
+    if dryrun:
+      log.info('Dryrun: Not posting to {}: {}'.format(channel, text))
+    else:
+      log.info('Posting to {}: {}'.format(channel, text))
+      message = yield from say(channel, text)
+      digest = hashlib.sha224(message.content.encode('utf-8')).hexdigest()
+      db.set_announcement(client, announcement['id'], digest)
+      if announcement['voice_id']:
+        filename = announcement['sound']
+        if not filename:
+          filename = 'meow.wav'
+        yield from play_sound(client.get_channel(str(announcement['voice_id'])), filename)
+  except:
+    pass
+
+@asyncio.coroutine
+def do_announcements():
   while True:
     waittime = None
-    given = {}
     now = time.time()
-    for order in get_bot_variable('orders', []):
-      if waittime is None or waittime > order['seconds']:
-        waittime = order['seconds']
-      digest = hashlib.sha224(order['message'].encode('utf-8')).hexdigest()
-      when = given[digest] if digest in given else None
-      if when is None or when < now - order['seconds']:
-        yield from give_order(order, digest)
-        given[digest] = now
+    for announcement in db.get_announcements(client):
+      if waittime is None or waittime > announcement['interval']:
+        waittime = announcement['interval']
+      yield from announce(announcement)
+    if waittime is None:
+      waittime = 60
+    elif waittime > 300:
+      waittime = 300
     yield from asyncio.sleep(waittime)
 
 @asyncio.coroutine
@@ -757,7 +791,6 @@ def play_greeting(greeting):
     return
   yield from play_sound(client.get_channel(str(greeting['voice'])), greeting['sound'])
 
-
 @client.event
 @asyncio.coroutine
 def on_ready():
@@ -793,8 +826,7 @@ def on_ready():
     yield from set_unassigned(member)
   log.info('RSS feeds: {}'.format([feed['description'] for feed in feeds if 'description' in feed]))
   asyncio.async(do_feeds())
-  log.info('Orders in {}'.format([channel.name for channel in filter(None, [client.get_channel(str(order['channel'])) for order in orders])]))
-  asyncio.async(do_orders())
+  asyncio.async(do_announcements())
   asyncio.async(maybe_sleep())
 
 def mentioned_in(message, explicit = True):
diff --git a/db.py b/db.py
index 7796a0d..35cc871 100644 (file)
--- a/db.py
+++ b/db.py
@@ -25,6 +25,7 @@ class DBConnection(object):
 
   def create_tables(self):
     cursor = self.query('create table if not exists state (id char(36) not null, bot_id varchar(32) not null, avatar varchar(128), idle boolean not null default false, last_spoke datetime)')
+    cursor = self.query('create table if not exists announcements (id char(36) not null, bot_id varchar(32) not null, server_id varchar(32) not null, member_id varchar(32) not null, channel_id varchar(32) not null, voice_id varchar(32), sound varchar(128), mention varchar(32) not null, start_date datetime, end_date datetime, interval int, last_spoke datetime, message text, digest char(56))')
     self.dbh.commit()
 
   def close(self):
@@ -56,3 +57,14 @@ class DBConnection(object):
       cursor = self.query('insert into state (id, bot_id) values (?, ?)', [self.uuid(), client.user.id])
       cursor = self.query(sql, params)
     self.dbh.commit()
+
+  def get_announcements(self, client):
+    now = self.now()
+    cursor = self.query('select id, server_id, channel_id, voice_id, sound, mention, start_date, end_date, interval, last_spoke, message, digest from announcements where (start_date is null or start_date <= ?) and (end_date is null or end_date > ?) and (last_spoke is null or last_spoke < ? - interval) and bot_id=?', [now, now, now, client.user.id])
+    for row in cursor.fetchall():
+      yield dict(row)
+
+  def set_announcement(self, client, id, digest):
+    now = self.now()
+    cursor = self.query('update announcements set last_spoke=?, digest=? where id=?', [now, digest, id])
+    self.dbh.commit()