-
Notifications
You must be signed in to change notification settings - Fork 11
/
plugin.py
147 lines (126 loc) · 5.08 KB
/
plugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
sentry_irc.models
~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2012 by Eduard Carreras, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
import socket
import re
import time
from random import randrange
from ssl import wrap_socket
from django import forms
from django.core.urlresolvers import reverse
from sentry.plugins.bases.notify import NotifyPlugin
from sentry.utils.http import absolute_uri
import sentry_irc
BASE_MAXIMUM_MESSAGE_LENGTH = 400
PING_RE = re.compile(r'^PING\s*:\s*(.*)$')
class IRCOptionsForm(forms.Form):
server = forms.CharField()
port = forms.IntegerField()
room = forms.CharField(help_text="You can add multiple rooms separated "
"by comma",
required=False)
without_join = forms.BooleanField(required=False)
user = forms.CharField(help_text="You can add multiple users to be "
"notified separated by comma",
required=False)
nick = forms.CharField()
password = forms.CharField(required=False)
ssl = forms.BooleanField(required=False)
def clean(self):
cleaned_data = super(IRCOptionsForm, self).clean()
room = cleaned_data.get('room', '')
user = cleaned_data.get('user', '')
if not any((user, room)):
msg = u"Must put either a room or an user"
for k in ('room', 'user'):
self._errors[k] = self.error_class([msg])
return cleaned_data
class IRCMessage(NotifyPlugin):
author = 'Eduard Carreras'
author_url = 'http://code.gisce.net/sentry-irc'
title = 'IRC'
conf_title = 'IRC'
conf_key = 'irc'
version = sentry_irc.VERSION
project_conf_form = IRCOptionsForm
# socket / read timeout
timeout = 15.0
def is_configured(self, project):
go = self.get_option
return (
all(go(k, project) for k in ('server', 'port', 'nick'))
and any(go(k, project) for k in ('room', 'user'))
)
def get_group_url(self, group):
return absolute_uri(reverse('sentry-group', args=[
group.team.slug,
group.project.slug,
group.id,
]))
def post_process(self, group, event, is_new, is_sample, **kwargs):
if not is_new or not self.is_configured(event.project):
return
link = self.get_group_url(group)
message = event.message.replace('\n', ' ').replace('\r', ' ')
message_format = '[%s] %s (%s)'
max_message_length = (
BASE_MAXIMUM_MESSAGE_LENGTH
- len(link)
- len(event.server_name)
- len(message_format.replace('%s', '')) # No of brackets/spaces
)
if len(message) > max_message_length:
message = message[0:max_message_length-3] + '...'
message = message_format % (event.server_name, message, link)
self.send_payload(event.project, message)
def send_payload(self, project, message):
server = self.get_option('server', project)
port = self.get_option('port', project)
nick = self.get_option('nick', project)
rooms = self.get_option('room', project) or ''
without_join = self.get_option('without_join', project)
users = self.get_option('user', project) or ''
rooms = [x.startswith('#') and x or '#%s' % x
for x in (x.strip() for x in rooms.split(','))]
users = [x.strip() for x in users.split(',')]
password = self.get_option('password', project)
ssl_c = self.get_option('ssl', project)
start = time.time()
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
irc.settimeout(self.timeout)
irc.connect((server, port))
if ssl_c:
ircsock = wrap_socket(irc)
else:
ircsock = irc
if password:
ircsock.send("PASS %s\n" % password)
ircsock.send("USER %s %s %s :Sentry IRC bot\n" % ((nick,) * 3))
ircsock.send("NICK %s\n" % nick)
while (time.time() - start) < self.timeout:
ircmsg = ircsock.recv(2048).strip('\n\r')
pong = PING_RE.findall(ircmsg)
if pong:
ircsock.send("PONG %s\n" % pong)
if re.findall(' 433 \* %s' % nick, ircmsg):
nick += '%s' % randrange(1000, 2000)
ircsock.send("NICK %s\n" % nick)
ircmsg = ircsock.recv(2048)
if re.findall(' 00[1-4] %s' % nick, ircmsg):
for room in rooms:
if not without_join:
ircsock.send("JOIN %s\n" % room)
ircsock.send("PRIVMSG %s :%s\n" % (room, message))
if not without_join:
ircsock.send("PART %s\n" % room)
for user in users:
ircsock.send("PRIVMSG %s :%s\n" % (user, message))
break
ircsock.send("QUIT\n")
# try to flush pending buffer
while (time.time() - start) < self.timeout and ircmsg:
ircmsg = ircsock.recv(2048)
irc.close()