Added pushbullet to summon, added in tasks/coroutines system, added in bbj integration
This commit is contained in:
parent
e7424f690b
commit
746ed85333
|
@ -1,9 +1,8 @@
|
||||||
from actions.botlist import botlist
|
from actions.botlist import botlist
|
||||||
from actions.summon import summon
|
from actions.web import summon, whois
|
||||||
from actions.access import banish, pardon
|
from actions.access import banish, pardon
|
||||||
from actions.control import puppet, nomad
|
from actions.control import puppet, nomad
|
||||||
from actions.stupid import hmm, hmmscore, hmmscoreboard
|
from actions.stupid import hmm, hmmscore, hmmscoreboard
|
||||||
from actions.web import whois
|
|
||||||
|
|
||||||
actions = [
|
actions = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
|
|
@ -1,7 +1,79 @@
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
from urllib.parse import urlencode
|
||||||
from urllib.error import HTTPError
|
from urllib.error import HTTPError
|
||||||
from json import loads
|
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):
|
def whois(self, name, source, response):
|
||||||
botnick = self.bot.botnick
|
botnick = self.bot.botnick
|
||||||
domain = response.split("!whois ")[1]
|
domain = response.split("!whois ")[1]
|
||||||
|
|
24
app.py
24
app.py
|
@ -4,16 +4,17 @@ from os.path import dirname, realpath
|
||||||
|
|
||||||
from bot import Bot, Tasks, Responses
|
from bot import Bot, Tasks, Responses
|
||||||
from actions import actions
|
from actions import actions
|
||||||
|
from coroutines import coroutines
|
||||||
|
|
||||||
kingme = [
|
debug = False
|
||||||
"#chaos"
|
kingme = [] if debug else ["#chaos"]
|
||||||
]
|
channels = ["#bots", "#insane"]
|
||||||
|
# if not debug:
|
||||||
|
# channels.extend([])
|
||||||
|
|
||||||
bot = Bot("127.0.0.1", 6667, "BabiliBot|py", [
|
bot = Bot("127.0.0.1", 6667, "BabiliBot|py", channels)
|
||||||
"#bots",
|
|
||||||
"#insane"
|
|
||||||
])
|
|
||||||
responses = Responses(bot)
|
responses = Responses(bot)
|
||||||
|
tasks = Tasks(bot)
|
||||||
|
|
||||||
for action in actions:
|
for action in actions:
|
||||||
if "type" in action and "pattern" in action and "callback" in action:
|
if "type" in action and "pattern" in action and "callback" in action:
|
||||||
|
@ -23,6 +24,14 @@ for action in actions:
|
||||||
action["callback"]
|
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):
|
def try_to_king_me(channel):
|
||||||
bot.send_message("ChanServ", "REGISTER {}", channel)
|
bot.send_message("ChanServ", "REGISTER {}", channel)
|
||||||
bot.send_message("ChanServ", "SET Successor {} {}", channel, bot.botnick)
|
bot.send_message("ChanServ", "SET Successor {} {}", channel, bot.botnick)
|
||||||
|
@ -61,6 +70,7 @@ def handle_message(name, source, response):
|
||||||
print("::", bot.memories)
|
print("::", bot.memories)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
bot.tasks = tasks
|
||||||
bot.start(dirname(realpath(__file__)), {
|
bot.start(dirname(realpath(__file__)), {
|
||||||
"pm": handle_pm,
|
"pm": handle_pm,
|
||||||
"mode": handle_mode,
|
"mode": handle_mode,
|
||||||
|
|
|
@ -14,6 +14,7 @@ class Bot:
|
||||||
|
|
||||||
self.settings = dict()
|
self.settings = dict()
|
||||||
self.places = list()
|
self.places = list()
|
||||||
|
self.tasks = None
|
||||||
self.author = ""
|
self.author = ""
|
||||||
|
|
||||||
self.recv_size = 2048
|
self.recv_size = 2048
|
||||||
|
@ -195,6 +196,10 @@ class Bot:
|
||||||
|
|
||||||
print("DEBUG: Joined")
|
print("DEBUG: Joined")
|
||||||
|
|
||||||
|
if self.tasks is not None:
|
||||||
|
if getattr(self.tasks, "run", None) is not None:
|
||||||
|
self.tasks.run()
|
||||||
|
|
||||||
while self.running:
|
while self.running:
|
||||||
message = self.ircsock.recv(self.recv_size).decode()
|
message = self.ircsock.recv(self.recv_size).decode()
|
||||||
message = message.strip(self.splitter)
|
message = message.strip(self.splitter)
|
||||||
|
|
38
bot/tasks.py
38
bot/tasks.py
|
@ -1,3 +1,37 @@
|
||||||
|
import time
|
||||||
|
import sched
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
class Tasks:
|
class Tasks:
|
||||||
def __init__(self):
|
def __init__(self, bot):
|
||||||
pass
|
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()
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -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
|
Loading…
Reference in New Issue