Added pushbullet to summon, added in tasks/coroutines system, added in bbj integration

This commit is contained in:
aewens 2018-09-15 20:11:02 -04:00
parent e7424f690b
commit 746ed85333
9 changed files with 238 additions and 36 deletions

View File

@ -1,9 +1,8 @@
from actions.botlist import botlist
from actions.summon import summon
from actions.web import summon, whois
from actions.access import banish, pardon
from actions.control import puppet, nomad
from actions.stupid import hmm, hmmscore, hmmscoreboard
from actions.web import whois
actions = [
{

View File

@ -1,25 +0,0 @@
from subprocess import Popen, PIPE
from email.mime.text import MIMEText
def summon(self, name, source, response):
botnick = self.bot.botnick
author = self.bot.author
user, reason = response.split("!summon ")[1].split(" ", 1)
email = "{}@tilde.team"
message = MIMEText(" ".join([
"My bot, {}, received a summoning request for you".format(botnick),
"from {} in channel {} for reason: {}".format(name, source, reason)
]))
message["From"] = email.format(botnick)
message["To"] = email.format(user)
message["Subject"] = "You have been summoned!"
command = "/usr/sbin/sendmail -t -oi".split(" ")
p = Popen(command, stdin=PIPE, universal_newlines=True)
p.communicate(message.as_string())
confirmation = "{}: You have summoned {}".format(name, user)
self.bot.send_message(source, confirmation)

View File

@ -1,7 +1,79 @@
from subprocess import Popen, PIPE
from email.mime.text import MIMEText
from urllib.request import Request, urlopen
from urllib.parse import urlencode
from urllib.error import HTTPError
from json import loads
def get_iden(devices, device_name):
for device in devices:
if device.get("nickname", "") == device_name:
return device.get("iden", "")
def push_note(bot, title, body):
api_url = "https://api.pushbullet.com/v2"
extra_settings = bot.settings.get("extras", dict())
pb_settings = extra_settings.get("pushbullet", dict())
api_key = pb_settings.get("api", "")
device_name = pb_settings.get("device", "")
list_devices = Request("{}/devices".format(api_url))
list_devices.add_header("Access-Token", api_key)
try:
data = loads(urlopen(list_devices).read())
except HTTPError:
return
devices = data.get("devices", list())
iden = get_iden(devices, device_name)
params = {
"device_iden": iden,
"type": "note",
"title": title,
"body": body
}
post_params = urlencode(params).encode()
pushes = Request("{}/pushes".format(api_url), post_params)
pushes.add_header("Access-Token", api_key)
try:
response = loads(urlopen(pushes).read())
except HTTPError as e:
return
def summon(self, name, source, response):
botnick = self.bot.botnick
author = self.bot.author
user, reason = response.split("!summon ")[1].split(" ", 1)
email = "{}@tilde.team"
subject = "You have been summoned!"
text = " ".join([
"My bot, {}, received a summoning request for you".format(botnick),
"from {} in channel {} for reason: {}".format(name, source, reason)
])
message = MIMEText(text)
message["From"] = email.format(botnick)
message["To"] = email.format(user)
message["Subject"] = subject
command = "/usr/sbin/sendmail -t -oi".split(" ")
p = Popen(command, stdin=PIPE, universal_newlines=True)
p.communicate(message.as_string())
if user == author:
push_note(self.bot, subject, text)
confirmation = "{}: You have summoned {}".format(name, user)
self.bot.send_message(source, confirmation)
def whois(self, name, source, response):
botnick = self.bot.botnick
domain = response.split("!whois ")[1]

24
app.py
View File

@ -4,16 +4,17 @@ from os.path import dirname, realpath
from bot import Bot, Tasks, Responses
from actions import actions
from coroutines import coroutines
kingme = [
"#chaos"
]
debug = False
kingme = [] if debug else ["#chaos"]
channels = ["#bots", "#insane"]
# if not debug:
# channels.extend([])
bot = Bot("127.0.0.1", 6667, "BabiliBot|py", [
"#bots",
"#insane"
])
bot = Bot("127.0.0.1", 6667, "BabiliBot|py", channels)
responses = Responses(bot)
tasks = Tasks(bot)
for action in actions:
if "type" in action and "pattern" in action and "callback" in action:
@ -23,6 +24,14 @@ for action in actions:
action["callback"]
)
# for coro in coroutines:
# worker = coro["worker"]
# interval = coro["interval"]
# state = coro.get("state", None)
# coro_state = state if state is not None else (bot,)
# tasks.add_coroutine(worker, interval, coro_state)
tasks.coroutines = coroutines
def try_to_king_me(channel):
bot.send_message("ChanServ", "REGISTER {}", channel)
bot.send_message("ChanServ", "SET Successor {} {}", channel, bot.botnick)
@ -61,6 +70,7 @@ def handle_message(name, source, response):
print("::", bot.memories)
if __name__ == "__main__":
bot.tasks = tasks
bot.start(dirname(realpath(__file__)), {
"pm": handle_pm,
"mode": handle_mode,

View File

@ -14,6 +14,7 @@ class Bot:
self.settings = dict()
self.places = list()
self.tasks = None
self.author = ""
self.recv_size = 2048
@ -195,6 +196,10 @@ class Bot:
print("DEBUG: Joined")
if self.tasks is not None:
if getattr(self.tasks, "run", None) is not None:
self.tasks.run()
while self.running:
message = self.ircsock.recv(self.recv_size).decode()
message = message.strip(self.splitter)

View File

@ -1,3 +1,37 @@
import time
import sched
from threading import Thread
class Tasks:
def __init__(self):
pass
def __init__(self, bot):
self.bot = bot
self.scheduler = sched.scheduler(time.time, time.sleep)
self.thread = Thread(target=self.worker, args=(self,))
self.coroutines = list()
self.states = dict()
def periodic(self, scheduler, interval, action, index, state=dict()):
self.states[index] = action(state)
scheduler.enter(interval, 1, self.periodic, (
scheduler, interval, action, index, self.states[index]
))
def worker(self, tasks):
for c, coro in enumerate(tasks.coroutines):
interval = coro["interval"]
worker = coro["worker"]
state = coro.get("state", dict())
state["bot"] = tasks.bot
tasks.periodic(tasks.scheduler, interval, worker, c, state)
tasks.scheduler.run()
def add_coroutine(self, worker, interval, state=dict()):
self.coroutines.append({
"worker": worker,
"interval": interval,
"state": state
})
def run(self):
self.thread.daemon = True
self.thread.start()

19
coroutines/__init__.py Normal file
View File

@ -0,0 +1,19 @@
from coroutines.bbj import BBJ
# {
# "worker": test,
# "interval": 3
# }
# def test(bot):
# print("Testing {}".format(bot.botnick))
coroutines = [
{
"worker": lambda state: BBJ(state).start(),
"interval": 5,
"state": {
"source": "http://localhost:7099/api",
"channels": ["#insane"], #team
}
}
]

88
coroutines/bbj.py Normal file
View File

@ -0,0 +1,88 @@
from urllib.request import Request, urlopen
from urllib.parse import urlencode
from urllib.error import HTTPError
from datetime import datetime
from json import loads, dumps
from re import sub
class BBJ:
def __init__(self, state):
self.name = "bbj"
self.bot = state["bot"]
self.source = state["source"]
self.channels = state["channels"]
self.memory = state.get("memory", {
"initialized": False,
# "timestamp": datetime.now().timestamp(),
"known": dict()
})
def start(self):
if not self.memory["initialized"]:
self.memory["initialized"] = True
self.fetch(self.cache)
return self.run()
def run(self):
self.fetch(self.mirror)
return {
"bot": self.bot,
"source": self.source,
"channels": self.channels,
"memory": self.memory
}
def cache(self, item):
self.memory["known"][item["thread_id"]] = item["last_mod"]
def process_thread(self, thread_id, thread):
data = thread.get("data", dict())
title = data.get("title", "")
replies = data.get("reply_count", "")
messages = data.get("messages", "")
usermap = thread.get("usermap", dict())
reply = messages[replies]
author = reply.get("author", "")
username = usermap[author].get("user_name", "")
body = reply.get("body", "")
body = sub(r">>\d\n\n", r"", body)
body = sub(r"\n", r" ", body)
php = "https://bbj.tilde.team/index.php"
link = "{}?thread_id={}".format(php, thread_id)
for channel in self.channels:
response = "'{}' ({}) : {} <{}>".format(title, username, body, link)
message = "[{}] {}".format(self.name, response)
self.bot.send_message(channel, message)
def get_thread(self, thread_id, callback):
params = {
"thread_id": thread_id
}
post_params = str(dumps(params)).encode()
thread_load = Request("{}/thread_load".format(self.source), post_params)
thread_load.add_header("Content-Type", "application/json")
try:
response = callback(thread_id, loads(urlopen(thread_load).read()))
except HTTPError:
return
def mirror(self, item):
thread_id = item["thread_id"]
last_mod = self.memory["known"][thread_id]
if last_mod == item["last_mod"]:
return
self.memory["known"][thread_id] = item["last_mod"]
self.get_thread(thread_id, self.process_thread)
def fetch(self, callback):
thread_index = Request("{}/thread_index".format(self.source))
try:
response = loads(urlopen(thread_index).read())
threads = response.get("data", dict())
for thread in threads:
callback(thread)
except HTTPError:
return

0
coroutines/rss.py Normal file
View File