core.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. import os
  2. import sys
  3. import yaml
  4. import requests
  5. import shutil
  6. from datetime import date
  7. import csv
  8. import urllib2
  9. import re
  10. import datetime
  11. from shutil import copyfile
  12. from time import gmtime, strftime
  13. import time
  14. import calendar
  15. import tornado.escape
  16. import tornado.ioloop
  17. import tornado.web
  18. import tornado.autoreload
  19. from tornado.escape import json_decode
  20. from tornado.escape import json_encode
  21. from threading import Timer
  22. import collections
  23. root = os.path.dirname(__file__)
  24. with open("config.yaml", 'r') as stream:
  25. try:
  26. #print(yaml.load(stream))
  27. config = yaml.load(stream)
  28. except yaml.YAMLError as exc:
  29. print(exc)
  30. if config == None:
  31. print("Error: Empty configuration file.")
  32. sys.exit(1)
  33. class RepeatedTimer(object):
  34. def __init__(self, interval, function, *args, **kwargs):
  35. self._timer = None
  36. self.interval = interval
  37. self.function = function
  38. self.args = args
  39. self.kwargs = kwargs
  40. self.is_running = False
  41. self.start()
  42. def _run(self):
  43. self.is_running = False
  44. self.start()
  45. self.function(*self.args, **self.kwargs)
  46. def start(self):
  47. if not self.is_running:
  48. self._timer = Timer(self.interval, self._run)
  49. self._timer.start()
  50. self.is_running = True
  51. def stop(self):
  52. self._timer.cancel()
  53. self.is_running = False
  54. def setInterval(self, interval):
  55. self.interval = interval
  56. months = {
  57. 'Jan' : 1,
  58. 'Feb' : 2,
  59. 'Mar' : 3,
  60. 'Apr' : 4,
  61. 'May' : 5,
  62. 'Jun' : 6,
  63. 'Jul' : 7,
  64. 'Aug' : 8,
  65. 'Sep' : 9,
  66. 'Oct' : 10,
  67. 'Nov' : 11,
  68. 'Dec' : 12
  69. }
  70. def fetchDataADEI():
  71. with open("varname.yaml", 'r') as stream:
  72. try:
  73. #print(yaml.load(stream))
  74. varname = yaml.load(stream)
  75. except yaml.YAMLError as exc:
  76. print(exc)
  77. if varname == None:
  78. print("Error: Empty varname file.")
  79. return
  80. cache_data = {}
  81. curtime = int(time.time())
  82. #time_range = str((curtime-3600)) + "-" + str(curtime)
  83. #time_range = str((curtime-1800)) + "-" + str(curtime)
  84. time_range = "-1"
  85. for param in varname:
  86. #print param
  87. dest = config['server'] + config['script']
  88. #url = dest + "?" + varname[param] + "&window=-1"
  89. url = dest + "?" + varname[param] + "&window=" + time_range
  90. #print url
  91. #print config['username'], config['password']
  92. data = requests.get(url,
  93. auth=(config['username'],
  94. config['password'])).content
  95. #tmp_data = data.content
  96. #print data
  97. # Date/Time, p_string2
  98. # 11-Aug-17 14:49:32.446682, 0.495
  99. lines = data.splitlines()
  100. if len(lines) < 2:
  101. print "No data:"
  102. print "URL: " + url
  103. print "\n"
  104. continue
  105. tmp_data = lines[-1]
  106. last_value = tmp_data.split(",")[-1].strip()
  107. first_value = tmp_data.split(",")[-2].strip()
  108. try:
  109. #print last_value
  110. test_x = float(last_value)
  111. except ValueError:
  112. last_value = ""
  113. #print last_value
  114. try:
  115. time_buffer = first_value.split("-")
  116. time_buffer[1] = str(months[time_buffer[1]])
  117. first_value = "-".join(time_buffer)
  118. first_ts = calendar.timegm(datetime.datetime.strptime(first_value, "%d-%m-%y %H:%M:%S.%f").timetuple())
  119. cache_data[param] = {'timestamp': first_ts, 'value': last_value}
  120. #current_timestamp = strftime("%Y-%m-%d %H:%M:%S", gmtime())
  121. current_timestamp = strftime("%Y-%m-%d %H:%M:%S")
  122. cache_data['time'] = {"value": current_timestamp}
  123. except:
  124. print "Problem parsing data:"
  125. print "URL: " + url
  126. print "Data: " + first_value
  127. print "\n"
  128. with open("/tmp/.tmp.yaml", 'w') as stream_tmp:
  129. stream_tmp.write(yaml.dump(cache_data, default_flow_style=False))
  130. src_file = "/tmp/.tmp.yaml"
  131. dst_file = "/tmp/cache.yaml"
  132. shutil.copy(src_file, dst_file)
  133. print "Start torrenting..."
  134. # it auto-starts, no need of rt.start()
  135. print "Debugging..."
  136. # TODO: Turn off for debug
  137. rt = RepeatedTimer(int(config["polling"]), fetchDataADEI)
  138. class BaseHandler(tornado.web.RequestHandler):
  139. def get_current(self):
  140. return self.get_secure_cookie("user")
  141. class ListHandler(tornado.web.RequestHandler):
  142. def get(self):
  143. with open("/tmp/cache.yaml", 'r') as stream:
  144. try:
  145. #print(yaml.load(stream))
  146. response = yaml.load(stream)
  147. except yaml.YAMLError as exc:
  148. print(exc)
  149. if response == None:
  150. response = {"error": "No data entry."}
  151. print response
  152. self.write(response)
  153. class StartHandler(tornado.web.RequestHandler):
  154. def get(self):
  155. print "Start fetchData"
  156. rt.start()
  157. class StopHandler(tornado.web.RequestHandler):
  158. def get(self):
  159. print "Stop fetchData"
  160. rt.stop()
  161. class SetTimerHandler(tornado.web.RequestHandler):
  162. def get(self, duration):
  163. print "Set interval"
  164. rt.setInterval(float(duration))
  165. class DesignerHandler(tornado.web.RequestHandler):
  166. @tornado.web.authenticated
  167. def get(self):
  168. print "In designer mode."
  169. with open("/tmp/cache.yaml", 'r') as stream:
  170. try:
  171. #print(yaml.load(stream))
  172. cache_data = yaml.load(stream)
  173. except yaml.YAMLError as exc:
  174. print(exc)
  175. if cache_data == None:
  176. print("Error: Empty cache data file.")
  177. return
  178. with open("style.yaml", 'r') as stream:
  179. try:
  180. #print(yaml.load(stream))
  181. style_data = yaml.load(stream)
  182. except yaml.YAMLError as exc:
  183. print(exc)
  184. data = {
  185. "cache": cache_data,
  186. "style": style_data
  187. }
  188. self.render('designer.html', data=data)
  189. class VersionHandler(tornado.web.RequestHandler):
  190. def get(self):
  191. response = {'version': '0.0.1',
  192. 'last_build': date.today().isoformat()}
  193. self.write(response)
  194. class BackupHandler(tornado.web.RequestHandler):
  195. def post(self):
  196. backup_dst = os.getcwd() + "/backup/"
  197. fname = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
  198. os.makedirs(backup_dst + fname)
  199. copyfile(os.getcwd() + "/varname.yaml", backup_dst + fname + "/varname.yaml")
  200. copyfile(os.getcwd() + "/style.yaml", backup_dst + fname + "/style.yaml")
  201. #self.write(json.dumps(response))
  202. class SaveHandler(tornado.web.RequestHandler):
  203. def post(self):
  204. print self.request.body
  205. json_obj = json_decode(self.request.body)
  206. print('Post data received')
  207. with open("style.yaml", 'w') as output:
  208. output.write(yaml.safe_dump(json_obj, encoding='utf-8', allow_unicode=True, default_flow_style=False))
  209. response = {"success": "Data entry inserted."}
  210. #self.write(json.dumps(response))
  211. class StatusHandler(tornado.web.RequestHandler):
  212. def get(self):
  213. print "In status mode."
  214. with open("style.yaml", 'r') as stream:
  215. try:
  216. #print(yaml.load(stream))
  217. style_data = yaml.load(stream)
  218. except yaml.YAMLError as exc:
  219. print(exc)
  220. #if style_data == None:
  221. # print("Error: Empty style data file.")
  222. # return
  223. with open("varname.yaml", 'r') as vstream:
  224. try:
  225. #print(yaml.load(stream))
  226. varname_data = yaml.load(vstream)
  227. except yaml.YAMLError as exc:
  228. print(exc)
  229. #if varname_data == None:
  230. # print("Error: Empty varname data file.")
  231. # return
  232. data = {
  233. #"style": style_data,
  234. "varname": varname_data
  235. }
  236. #if "background" in config:
  237. # data["background"] = config["background"]
  238. if "title" in config:
  239. data["title"] = config["title"]
  240. else:
  241. data["title"] = "BORA"
  242. self.render('index.html', data=data)
  243. class AdeiKatrinHandler(tornado.web.RequestHandler):
  244. def get(self, **params):
  245. #print params
  246. sensor_name = str(params["sensor_name"])
  247. """
  248. {'db_group': u'320_KRY_Kryo_4K_CurLead',
  249. 'db_name': u'ControlSystem_CPS',
  250. 'sensor_name': u'320-RTP-8-1103',
  251. 'db_server': u'cscps',
  252. 'control_group': u'320_KRY_Kryo_3K'}
  253. """
  254. if config["type"] != "adei":
  255. print("Error: Wrong handler.")
  256. return
  257. dest = config['server'] + config['script']
  258. query_cmds = []
  259. query_cmds.append("db_server="+str(params['db_server']))
  260. query_cmds.append("db_name="+str(params['db_name']))
  261. query_cmds.append("db_group="+str(params['db_group']))
  262. query_cmds.append("db_mask=all")
  263. query_cmds.append("window=-1")
  264. query = "&".join(query_cmds)
  265. url = dest + "?" + query
  266. #print url
  267. # get the db_masks
  268. # store the query command in varname
  269. data = requests.get(url, auth=(config['username'], config['password']))
  270. cr = data.content
  271. cr = cr.split(",")
  272. #print cr, len(cr)
  273. # handling the inconsistency on naming convention
  274. match_token = params['sensor_name']
  275. if params["db_server"] != "lara":
  276. # parameter name stored in ADEI with '-IST_Val' suffix
  277. if "MOD" in params['sensor_name']:
  278. match_token = params['sensor_name'] + "-MODUS_Val"
  279. elif "GRA" in params['sensor_name']:
  280. match_token = params['sensor_name'] + "-GRAD_Val"
  281. elif "RPO" in params['sensor_name']:
  282. match_token = params['sensor_name'] + "-ZUST_Val"
  283. elif "VYS" in params['sensor_name']:
  284. match_token = params['sensor_name'] + "-ZUST_Val"
  285. else:
  286. match_token = params['sensor_name'] + "-IST_Val"
  287. db_mask = None
  288. for i, item in enumerate(cr):
  289. if "[" and "]" in item.strip():
  290. lhs = re.match(r"[^[]*\[([^]]*)\]", item.strip()).groups()[0]
  291. if lhs == params['sensor_name']:
  292. db_mask = i - 1
  293. else:
  294. if item.strip() == match_token:
  295. db_mask = i - 1
  296. if db_mask == None:
  297. response = {"Error": "Cannot find variable on ADEI server."}
  298. self.write(response)
  299. return
  300. query_cmds = []
  301. query_cmds.append("db_server="+str(params['db_server']))
  302. query_cmds.append("db_name="+str(params['db_name']))
  303. query_cmds.append("db_group="+str(params['db_group']))
  304. query_cmds.append("db_mask="+str(db_mask))
  305. query = "&".join(query_cmds)
  306. # column name available
  307. # store in yaml file
  308. with open("varname.yaml", 'r') as stream:
  309. try:
  310. #print(yaml.load(stream))
  311. cache_data = yaml.load(stream)
  312. except yaml.YAMLError as exc:
  313. print(exc)
  314. if cache_data == None:
  315. cache_data = {}
  316. cache_data[sensor_name] = query
  317. else:
  318. if sensor_name not in cache_data:
  319. cache_data[sensor_name] = query
  320. else:
  321. response = {"Error": "Variable already available in varname file."}
  322. self.write(response)
  323. return
  324. with open("varname.yaml", 'w') as output:
  325. output.write(yaml.dump(cache_data, default_flow_style=False))
  326. response = {"success": "Data entry inserted."}
  327. #print match_token, db_mask
  328. self.write(response)
  329. class GetDataHandler(tornado.web.RequestHandler):
  330. def get(self):
  331. cache_data = None
  332. with open("/tmp/cache.yaml", 'r') as stream:
  333. try:
  334. #print(yaml.load(stream))
  335. cache_data = yaml.load(stream)
  336. except yaml.YAMLError as exc:
  337. print(exc)
  338. #print("GetData:")
  339. if cache_data == None:
  340. cache_data = {}
  341. #print cache_data
  342. self.write(cache_data)
  343. class AuthLoginHandler(BaseHandler):
  344. def get(self):
  345. try:
  346. errormessage = self.get_argument("error")
  347. except:
  348. errormessage = ""
  349. print errormessage
  350. self.render("login.html", errormessage = errormessage)
  351. def check_permission(self, password, username):
  352. if username == config["username"] and password == config["pw_designer"]:
  353. return True
  354. return False
  355. def post(self):
  356. username = self.get_argument("username", "")
  357. password = self.get_argument("password", "")
  358. auth = self.check_permission(password, username)
  359. if auth:
  360. self.set_current_user(username)
  361. print "In designer mode."
  362. with open("/tmp/cache.yaml", 'r') as stream:
  363. try:
  364. #print(yaml.load(stream))
  365. cache_data = yaml.load(stream)
  366. except yaml.YAMLError as exc:
  367. print(exc)
  368. #if cache_data == None:
  369. # print("Error: Empty cache data file.")
  370. # return
  371. with open("style.yaml", 'r') as stream:
  372. try:
  373. #print(yaml.load(stream))
  374. style_data = yaml.load(stream)
  375. except yaml.YAMLError as exc:
  376. print(exc)
  377. if style_data:
  378. index_data = list(set(cache_data) | set(style_data))
  379. else:
  380. index_data = cache_data
  381. print index_data
  382. data = {
  383. "cache": cache_data,
  384. "style": style_data,
  385. "index": index_data,
  386. }
  387. if "background" in config:
  388. data["background"] = config["background"]
  389. self.render('designer.html', data=data)
  390. else:
  391. error_msg = u"?error=" + tornado.escape.url_escape("Login incorrect")
  392. self.redirect(u"/auth/login/" + error_msg)
  393. def set_current_user(self, user):
  394. if user:
  395. self.set_secure_cookie("user", tornado.escape.json_encode(user))
  396. else:
  397. self.clear_cookie("user")
  398. application = tornado.web.Application([
  399. (r"/auth/login/?", AuthLoginHandler),
  400. (r"/version/?", VersionHandler),
  401. (r"/list/?", ListHandler),
  402. (r"/start/?", StartHandler),
  403. (r"/backup/?", BackupHandler),
  404. (r"/stop/?", StopHandler),
  405. (r"/designer/?", DesignerHandler),
  406. (r"/", StatusHandler),
  407. (r"/status/?", StatusHandler),
  408. (r"/save/?", SaveHandler),
  409. (r"/getdata/?", GetDataHandler),
  410. (r"/timer/(?P<duration>[^\/]+)/?", SetTimerHandler),
  411. (r"/add/(?P<db_server>[^\/]+)/?(?P<db_name>[^\/]+)/?(?P<db_group>[^\/]+)/?(?P<sensor_name>[^\/]+)?", AdeiKatrinHandler)
  412. ], debug=True, static_path=os.path.join(root, 'static'), js_path=os.path.join(root, 'js'), login_url="/auth/login", cookie_secret='L8LwECiNRxq2N0N2eGxx9MZlrpmuMEimlydNX/vt1LM=')
  413. if __name__ == "__main__":
  414. application.listen(int(config["port"]))
  415. tornado.autoreload.start()
  416. #tornado.autoreload.watch('myfile')
  417. tornado.ioloop.IOLoop.instance().start()