You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
7.4 KiB
240 lines
7.4 KiB
#! /usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# S.D.G
|
|
|
|
"""
|
|
:mod:`lugito.connectors.irc`
|
|
======================================
|
|
|
|
Define an irc connector class
|
|
|
|
.. currentmodule:: lugito.connectors.irc
|
|
"""
|
|
|
|
# Imports
|
|
import ssl
|
|
import http
|
|
import socket
|
|
import logging
|
|
import threading
|
|
import phabricator
|
|
from time import sleep
|
|
|
|
|
|
class IRCConnector(object):
|
|
|
|
def __init__(self, log_level=logging.DEBUG):
|
|
|
|
# IRC info
|
|
# Read the configuration out of the .arcconfig file
|
|
self.host = phabricator.ARCRC['irc']['host']
|
|
self.port = int(phabricator.ARCRC['irc']['port'])
|
|
self.username = phabricator.ARCRC['irc']['username']
|
|
self.password = phabricator.ARCRC['irc']['password']
|
|
self.channel = phabricator.ARCRC['irc']['channel']
|
|
|
|
# Phabricator info
|
|
self.phab = phabricator.Phabricator()
|
|
self.phab_host = phabricator.ARCRC['config']['default'].replace(
|
|
'api/', '')
|
|
|
|
self.logger = logging.getLogger('lugito.connector.IRCConnector')
|
|
|
|
# Add log level
|
|
ch = logging.StreamHandler()
|
|
|
|
formatter = logging.Formatter(
|
|
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
ch.setFormatter(formatter)
|
|
|
|
self.logger.addHandler(ch)
|
|
self.logger.setLevel(log_level)
|
|
|
|
|
|
def _send_raw(self, message):
|
|
"""Low level send"""
|
|
|
|
self.conn.send(message.encode('utf-8'))
|
|
|
|
|
|
def _socket_conn(self):
|
|
self.conn = ssl.wrap_socket(
|
|
socket.socket(socket.AF_INET, socket.SOCK_STREAM))
|
|
self.conn.connect((self.host, self.port))
|
|
|
|
|
|
def connect(self):
|
|
"""Connect"""
|
|
|
|
self._socket_conn()
|
|
|
|
setup = False
|
|
usersuffix = 0
|
|
self.logger.info("Connecting to IRC.")
|
|
|
|
while not setup:
|
|
response = self.conn.recv(512).decode("utf-8")
|
|
self.logger.debug(response)
|
|
|
|
if "No Ident response" in response:
|
|
self._send_raw("NICK {}\r\n".format(self.username))
|
|
self._send_raw("USER {} * * :{}\r\n".format(
|
|
self.username, self.username))
|
|
self._send_raw("PRIVMSG nickserv :identify {} {}\r\n".format(
|
|
self.username, self.password))
|
|
|
|
if "You are now identified" in response:
|
|
sleep(5)
|
|
self._send_raw("JOIN {}\r\n".format(self.channel))
|
|
|
|
if "477" in response:
|
|
sleep(5)
|
|
self._send_raw("JOIN {}\r\n".format(self.channel))
|
|
|
|
if "433" in response:
|
|
usersuffix = usersuffix + 1
|
|
self.username = self.username + str(usersuffix)
|
|
self._send_raw("NICK {}\r\n".format(self.username))
|
|
self._send_raw("USER {} * * :{}\r\n".format(
|
|
self.username, self.username))
|
|
|
|
if "PING" in response:
|
|
self._send_raw("PONG :{}\r\n".format(response.split(":")[1]))
|
|
|
|
if "366" in response:
|
|
setup = True
|
|
|
|
self.logger.info("Successfully connected to the IRC server.")
|
|
|
|
def send_notice(self, message):
|
|
self._send_raw("NOTICE {} :{}\r\n".format(self.channel, message))
|
|
|
|
def send(self, objectstr, who, body, link):
|
|
"""Send a formatted message"""
|
|
|
|
# e.g. [T31: Better IRC integration]
|
|
message = "\x033[\x03\x0313" + objectstr + "\x03\x033]\x03 "
|
|
# e.g. tsimonq2 (Simon Quigley)
|
|
message = message + "\x0315" + who + "\x03 "
|
|
# e.g. commented on the task:
|
|
message = message + body + ": "
|
|
# e.g. https://phab.lubuntu.me/T40#779
|
|
message = message + "\x032" + link + "\x03"
|
|
# Make sure we can debug this if it goes haywire
|
|
self.logger.debug(message)
|
|
# Sleep for a fifth of a second, so when we have a bunch of messages we have a buffer
|
|
sleep(0.2)
|
|
# Aaaaand, send it off!
|
|
self.send_notice(message)
|
|
|
|
def gettaskinfo(self, task):
|
|
|
|
sendmessage = ""
|
|
|
|
# Strip out anchor link
|
|
# This will prevent invalid task / diff references
|
|
anchor = None
|
|
if '#' in task:
|
|
task, anchor = task.split('#')
|
|
|
|
try:
|
|
# We only need the task number.
|
|
if len(task.split("T")) > 1:
|
|
taskinfo = self.phab.maniphest.info(
|
|
task_id=int(task.split("T")[1]))
|
|
|
|
# or the diff number
|
|
elif len(task.split("D")) > 1:
|
|
taskinfo = self.phab.differential.query(
|
|
ids=[int(task.split("D")[1])])[0]
|
|
taskinfo['priorityColor'] = None
|
|
|
|
sendmessage += "\x033[\x03"
|
|
|
|
# The color of the priority text should correspond to its value.
|
|
color = taskinfo["priorityColor"]
|
|
if color == "violet":
|
|
sendmessage += "\x036Needs Triage"
|
|
elif color == "pink":
|
|
sendmessage += "\x035Unbreak Now!"
|
|
elif color == "red":
|
|
sendmessage += "\x034High"
|
|
elif color == "orange":
|
|
sendmessage += "\x037Medium"
|
|
elif color == "yellow":
|
|
sendmessage += "\x038Low"
|
|
elif color == "sky":
|
|
sendmessage += "\x037Wishlist"
|
|
|
|
# Put the task status in the message.
|
|
if color is not None:
|
|
sendmessage += ", "
|
|
|
|
sendmessage += taskinfo["statusName"] + "\x03\x033]\x03 "
|
|
|
|
# Put the title in there as well.
|
|
sendmessage += taskinfo["title"].strip() + ": "
|
|
|
|
# And the link.
|
|
sendmessage += "\x032" + taskinfo["uri"]
|
|
|
|
# Add the anchor back if it was present
|
|
if anchor is not None:
|
|
sendmessage += '#{}'.format(anchor)
|
|
|
|
sendmessage += '\x03'
|
|
|
|
# Send it off!
|
|
self.send_notice(sendmessage)
|
|
|
|
# If someone wrote something like "Tblah", obviously that's not right.
|
|
except ValueError:
|
|
self.send_notice("\x034Error: " + task.strip() + "is an invalid task reference.\x03")
|
|
return None
|
|
|
|
|
|
def bot(self, message, msgtype):
|
|
|
|
if msgtype == "info":
|
|
message = message.split(" :" + self.username + ": info")[1]
|
|
|
|
for item in message.split():
|
|
if item.startswith("T") or item.startwith("D"):
|
|
self.gettaskinfo(item.strip())
|
|
|
|
elif msgtype == "link":
|
|
|
|
for item in message.split(self.phab_host):
|
|
if (item.split()[0].strip().startswith("T")) or \
|
|
(item.split()[0].strip().startswith("D")):
|
|
|
|
self.gettaskinfo(item.split()[0].strip())
|
|
|
|
else:
|
|
self.sendnotice("\x034Error: unknown command.\x03")
|
|
return None
|
|
|
|
|
|
def listen(self):
|
|
|
|
while True:
|
|
ircmsg = self.conn.recv(512)
|
|
|
|
if len(ircmsg) == 0:
|
|
# logger.warn is deprecated, use .warning.
|
|
self.logger.warning("Connection lost, reconnecting!")
|
|
self.connect()
|
|
continue
|
|
|
|
ircmsg = ircmsg.decode("UTF-8").strip('\n\r')
|
|
self.logger.debug(ircmsg)
|
|
|
|
if ircmsg.find("PING :") != -1:
|
|
self.conn.send(bytes("PONG :pingis\n", "UTF-8"))
|
|
|
|
elif ircmsg.find(" :" + self.username + ": info") != -1:
|
|
self.bot(ircmsg, "info")
|
|
|
|
elif ircmsg.find("{}".format(self.phab_host)) != -1:
|
|
self.bot(ircmsg, "link")
|