core.py 18 KB

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