core.py 17 KB

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