Created
July 22, 2013 13:33
-
-
Save piotrmaslanka/6053838 to your computer and use it in GitHub Desktop.
A sample service for eunike. Accepts messages via HTTP POST request. Provides statistical info upon GET requests.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=UTF-8 | |
from __future__ import division | |
import json, sys, os.path | |
import datetime | |
import sqlite3 | |
import BaseHTTPServer, cgi | |
import time | |
import hashlib | |
PRESENTPATH = u'''<!DOCTYPE html> | |
<html> | |
<head><title>Raport SMS</title> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<style type="text/css"> | |
* { font-family: Helvetica, arial, freesans, clean, sans-serif; } | |
h1 { color: lightblue; margin-bottom: 0; } | |
.lb { margin-right: 20px; float: left; } | |
h2 { color: lightblue; } | |
.prefooter { clear: both; } | |
.footer { font-size: 0.8em; margin-top: 20px; } | |
a { color: black; } | |
</style></head><body> | |
<h1>Bramka SMS</h1> | |
<div class="lb"> | |
<h2>Liczniki</h2> | |
<em>w ciągu ostatnich... </em><br> | |
Tygodnia: %(s_week)s <br> | |
48 godzin %(s_yesterday)s <br> | |
24 godzin: %(s_today)s <br> | |
12 godzin: %(s_12hrs)s <br> | |
5 godzin: %(s_5hrs)s <br> | |
1 godziny: %(s_hour)s <br> | |
15 minut: %(s_15mins)s <br><br> | |
TOTAL: %(s_total)s <br> | |
<a href="/statistics/">Statystyki</a><br> | |
</div> | |
<div class="lb"> | |
<h2>Stan bramki</h2> | |
Status: %(fail_status)s <br><br> | |
Resetów modułu: %(gate_hard_resets)s <br> | |
Błędów RS232: %(gate_soft_resets)s <br> | |
<em>powyższe są z ostatnich 24 godzin</em> <br><br> | |
Przeciętna prędkość wysyłki SMS: %(avg_sms_speed)s <br> | |
<em>z ostatnich 20 SMS-ów</em> <br> | |
</div> | |
<div class="prefooter"></div> | |
<div class="footer">powered by <a href="https://github.com/henrietta/eunike">eunike</a></div> | |
</body></html>''' | |
STATSPATH = u'''<!DOCTYPE html> | |
<html> | |
<head><title>Statystyki SMS</title> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<style type="text/css"> | |
* { font-family: Helvetica, arial, freesans, clean, sans-serif; } | |
h1 { color: lightblue; margin-bottom: 0; } | |
.lb { margin-right: 20px; float: left; } | |
h2 { color: lightblue; } | |
.prefooter { clear: both; } | |
.footer { font-size: 0.8em; margin-top: 20px; } | |
.footer a { color: black; } | |
</style></head><body> | |
<h1>Bramka SMS</h1> | |
<div class="lb"> | |
<h2>Procentowe udziały</h2> | |
%(gen_particles)s | |
</div> | |
<div class="prefooter"></div> | |
<div class="footer">powered by <a href="https://github.com/henrietta/eunike">eunike</a></div> | |
</body></html> | |
''' | |
# Load configuration | |
with open(sys.argv[1], 'rb') as json_config: | |
cnf = json.load(json_config) | |
json_at = cnf['instrumentation']['save_json_to'] | |
sql_at = cnf['osm']['path'] | |
class ReqHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |
def log_request(self, *args, **kwargs): | |
pass | |
def _do_POST(self): | |
self.query_string = self.rfile.read( \ | |
int(self.headers['Content-Length'])) | |
self.args = dict(cgi.parse_qsl(self.query_string)) | |
target = self.args['nr'] | |
content = self.args['sms'] | |
hsh = self.args['hash'] | |
PASSWORD = 'SOME PASSWORD' | |
hhsh = hashlib.sha1(target + content + PASSWORD).hexdigest() | |
if hhsh != hsh: | |
self.send_error(403, 'Invalid password') | |
return | |
condict = { | |
'content': content, | |
'target': target, | |
'msgclass': 'sms' | |
} | |
try: | |
condict['tag'] = self.args['tag'] | |
except KeyError: | |
pass | |
genname = os.path.join(cnf['oams'][0]['directory'], str(time.time())) | |
with open(genname, 'wb') as x: | |
json.dump(condict, x) | |
os.rename(genname, genname+'.msg') | |
self.send_response(200) | |
self.send_header('Content-Type', 'application/json') | |
self.end_headers() | |
self.wfile.write('{"status": "ok"}') | |
def do_POST(self): | |
try: | |
self._do_POST() | |
except: | |
raise | |
self.send_error(500, 'Try again later') | |
def do_GET(self): | |
try: | |
if 'statistics' in self.path: | |
k = self._handle_statistics() | |
else: | |
k = self._handle_root() | |
except Exception as e: | |
self.send_error(500, 'Try again later') | |
else: | |
self.send_response(200) | |
self.send_header('Content-Type', 'text/html') | |
self.end_headers() | |
self.wfile.write(k.encode('utf8')) | |
def inq(self, qu, atr): | |
self.sqc.execute(qu, atr) | |
f = self.sqc.fetchall()[0][0] | |
return f | |
def _handle_statistics(self): | |
# SQLite | |
try: | |
self.sq = sqlite3.connect(sql_at) | |
self.sqc = self.sq.cursor() | |
self.sqc.execute('SELECT tag, COUNT(*) FROM sent GROUP BY tag') | |
data = self.sqc.fetchall() | |
finally: | |
self.sqc.close() | |
self.sq.close() | |
total = sum([x[1] for x in data]) | |
td = [u'%s: %.2f%%<br>' % (tag if tag != None else '<em>Nieoznaczony</em>', | |
100*count/total) \ | |
for tag, count in data] | |
return STATSPATH % { | |
'gen_particles': u' '.join(td) | |
} | |
def _handle_root(self): | |
def cx(d): | |
"""Convert datetime to format understood by sqlite""" | |
return time.mktime(d.timetuple()) | |
def sent_last_hours(hrs): | |
return self.inq('SELECT COUNT(rowid) FROM sent WHERE sent_on > ?', ( | |
cx(datetime.datetime.now() - datetime.timedelta(0, 3600*hrs)), )) | |
with open(json_at, 'rb') as jin: | |
instr = json.load(jin) | |
# calculate average sms speed | |
smss = instr['x-sms1']['send_time'] | |
del smss['value'] | |
try: | |
avg = sum(smss.values()) / len(smss.values()) | |
avg = '%.2f s' % avg | |
except: | |
avg = 'N/A' | |
# fail status? | |
fail_status = '<span style="color: green;">OK</span>' \ | |
if not instr['x-sms1']['is_failed'] else \ | |
'<span style="color: red;">AWARIA</span>' | |
# SQLite | |
self.sq = sqlite3.connect(sql_at) | |
self.sqc = self.sq.cursor() | |
try: | |
return PRESENTPATH % { | |
's_total': self.inq('SELECT COUNT(rowid) FROM sent', ()), | |
's_today': sent_last_hours(12), | |
's_yesterday': sent_last_hours(48), | |
's_week': sent_last_hours(12*7), | |
's_5hrs': sent_last_hours(5), | |
's_12hrs': sent_last_hours(12), | |
's_15mins': sent_last_hours(0.25), | |
's_hour': sent_last_hours(1), | |
'gate_hard_resets': instr['x-sms1']['hard_resets'], | |
'gate_soft_resets': instr['x-sms1']['soft_resets'], | |
'avg_sms_speed': avg, | |
'fail_status': fail_status | |
} | |
finally: | |
self.sqc.close() | |
self.sq.close() | |
if len(sys.argv) != 4: | |
print 'How to invoke:' | |
print 'run.py EUNIKE_CONFIG_FILE HTTP_IP HTTP_PORT' | |
sys.exit() | |
sys.stdout = open('/dev/null', 'w') | |
sys.stderr = open('/dev/null', 'w') | |
BaseHTTPServer.HTTPServer((sys.argv[2], int(sys.argv[3])), ReqHandler).serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment