core.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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. json_obj = json_decode(self.request.body)
  160. with open("style.yaml", 'w') as output:
  161. output.write(yaml.safe_dump(json_obj, encoding='utf-8',
  162. allow_unicode=True, default_flow_style=False))
  163. response = {"success": "Data entry inserted."}
  164. class StatusHandler(tornado.web.RequestHandler):
  165. def get(self):
  166. print "In status mode."
  167. with open("style.yaml", 'r') as stream:
  168. try:
  169. style_data = yaml.load(stream)
  170. except yaml.YAMLError as exc:
  171. print(exc)
  172. with open("varname.yaml", 'r') as vstream:
  173. try:
  174. varname_data = yaml.load(vstream)
  175. except yaml.YAMLError as exc:
  176. print(exc)
  177. data = {
  178. "style": style_data,
  179. "varname": varname_data
  180. }
  181. if "background" in config:
  182. data["background"] = config["background"]
  183. if "title" in config:
  184. data["title"] = config["title"]
  185. else:
  186. data["title"] = "BORA"
  187. if "server" in config:
  188. data["server"] = config["server"]
  189. else:
  190. data["server"] = "http://katrin.kit.edu/adei-katrin/"
  191. self.render('status.html', data=data)
  192. class UpdateHandler(tornado.web.RequestHandler):
  193. def get(self):
  194. print "Update Sensor Definition"
  195. new_data = {}
  196. rt.stop()
  197. with open("varname.yaml", 'r') as stream:
  198. try:
  199. cache_data = yaml.load(stream)
  200. except yaml.YAMLError as exc:
  201. print(exc)
  202. if config["type"] != "adei":
  203. print("Error: Wrong handler.")
  204. return
  205. for item in cache_data:
  206. tmp_data = cache_data[item]
  207. tmp_str = []
  208. tmp_store = []
  209. for adei_unit in tmp_data.split("&"):
  210. lhs, rhs = adei_unit.split("=")
  211. if lhs == "db_mask":
  212. tmp_str.append("db_mask=all")
  213. continue
  214. elif lhs == "db_server":
  215. db_server = rhs
  216. tmp_str.append(adei_unit)
  217. tmp_store.append(adei_unit)
  218. tmp_str.append("window=-1")
  219. query = "&".join(tmp_str)
  220. dest = config['server'] + config['script']
  221. url = dest + "?" + query
  222. data = requests.get(url, auth=(config['username'],
  223. config['password']))
  224. cr = data.content
  225. cr = cr.split(",")
  226. match_token = item
  227. if db_server != "lara" and db_server != "hiu":
  228. # parameter name stored in ADEI with '-IST_Val' suffix
  229. if "MOD" in item:
  230. match_token = item + "-MODUS_Val"
  231. elif "GRA" in item:
  232. match_token = item + "-GRAD_Val"
  233. elif "RPO" in item:
  234. match_token = item + "-ZUST_Val"
  235. elif "VYS" in item:
  236. match_token = item + "-ZUST_Val"
  237. elif "MSS" in item:
  238. match_token = item + "_Val"
  239. else:
  240. match_token = item + "-IST_Val"
  241. db_mask = None
  242. for i, iter_item in enumerate(cr):
  243. if match_token == iter_item.strip():
  244. db_mask = i - 1
  245. if db_mask is None:
  246. continue
  247. tmp_store.append("db_mask="+str(db_mask))
  248. new_data[item] = "&".join(tmp_store)
  249. with open("varname.yaml", 'w') as output:
  250. output.write(yaml.dump(new_data, default_flow_style=False))
  251. response = {"success": "Data entry inserted."}
  252. rt.start()
  253. class AdeiKatrinHandler(tornado.web.RequestHandler):
  254. def get(self, **params):
  255. sensor_name = str(params["sensor_name"])
  256. """
  257. {'db_group': u'320_KRY_Kryo_4K_CurLead',
  258. 'db_name': u'ControlSystem_CPS',
  259. 'sensor_name': u'320-RTP-8-1103',
  260. 'db_server': u'cscps',
  261. 'control_group': u'320_KRY_Kryo_3K'}
  262. """
  263. if config["type"] != "adei":
  264. print("Error: Wrong handler.")
  265. return
  266. dest = config['server'] + config['script']
  267. query_cmds = []
  268. query_cmds.append("db_server="+str(params['db_server']))
  269. query_cmds.append("db_name="+str(params['db_name']))
  270. query_cmds.append("db_group="+str(params['db_group']))
  271. query_cmds.append("db_mask=all")
  272. query_cmds.append("window=-1")
  273. query = "&".join(query_cmds)
  274. url = dest + "?" + query
  275. # get the db_masks
  276. # store the query command in varname
  277. data = requests.get(url, auth=(config['username'], config['password']))
  278. cr = data.content
  279. cr = cr.splitlines()
  280. cr = ",".join(cr)
  281. cr = cr.split(",")
  282. # handling the inconsistency on naming convention
  283. match_token = params['sensor_name']
  284. if (params["db_server"] != "lara" and params["db_server"] != "hiu" and
  285. params["db_server"] != "safety-first"):
  286. # parameter name stored in ADEI with '-IST_Val' suffix
  287. if "MOD" in params['sensor_name']:
  288. match_token = params['sensor_name'] + "-MODUS_Val"
  289. elif "GRA" in params['sensor_name']:
  290. match_token = params['sensor_name'] + "-GRAD_Val"
  291. elif "RPO" in params['sensor_name']:
  292. match_token = params['sensor_name'] + "-ZUST_Val"
  293. elif "VYS" in params['sensor_name']:
  294. match_token = params['sensor_name'] + "-ZUST_Val"
  295. elif "HVS" in params['sensor_name']:
  296. match_token = params['sensor_name'] + "-ZUST_Val"
  297. elif "VAO" in params['sensor_name']:
  298. match_token = params['sensor_name'] + "-ZUST_Val"
  299. elif "MSS" in params['sensor_name']:
  300. match_token = params['sensor_name'] + "_Val"
  301. else:
  302. match_token = params['sensor_name'] + "-IST_Val"
  303. db_mask = None
  304. for i, item in enumerate(cr):
  305. if "[" and "]" in item.strip():
  306. lhs = re.match(r"[^[]*\[([^]]*)\]", item.strip()).groups()[0]
  307. if lhs == params['sensor_name']:
  308. db_mask = i - 1
  309. else:
  310. if item.strip() == match_token:
  311. db_mask = i - 1
  312. if db_mask is None:
  313. response = {"Error": "Cannot find variable on ADEI server."}
  314. self.write(response)
  315. return
  316. query_cmds = []
  317. query_cmds.append("db_server="+str(params['db_server']))
  318. query_cmds.append("db_name="+str(params['db_name']))
  319. query_cmds.append("db_group="+str(params['db_group']))
  320. query_cmds.append("db_mask="+str(db_mask))
  321. query = "&".join(query_cmds)
  322. # column name available
  323. # store in yaml file
  324. with open("varname.yaml", 'r') as stream:
  325. try:
  326. cache_data = yaml.load(stream)
  327. except yaml.YAMLError as exc:
  328. print(exc)
  329. if cache_data is None:
  330. cache_data = {}
  331. cache_data[sensor_name] = query
  332. else:
  333. if sensor_name not in cache_data:
  334. cache_data[sensor_name] = query
  335. else:
  336. response = {"Error":
  337. "Variable already available in varname file."}
  338. self.write(response)
  339. return
  340. with open("varname.yaml", 'w') as output:
  341. output.write(yaml.dump(cache_data, default_flow_style=False))
  342. response = {"success": "Data entry inserted."}
  343. self.write(response)
  344. class GetDataHandler(tornado.web.RequestHandler):
  345. def get(self):
  346. with open("cache.yaml", 'r') as stream:
  347. try:
  348. cache_data = yaml.load(stream)
  349. except yaml.YAMLError as exc:
  350. print(exc)
  351. if cache_data is None:
  352. cache_data = {}
  353. self.write(cache_data)
  354. class AuthLoginHandler(BaseHandler):
  355. def get(self):
  356. try:
  357. errormessage = self.get_argument("error")
  358. except:
  359. errormessage = ""
  360. print errormessage
  361. self.render("login.html", errormessage=errormessage)
  362. def check_permission(self, password, username):
  363. if (username == config["username"] and
  364. password == config["pw_designer"]):
  365. return True
  366. return False
  367. def post(self):
  368. username = self.get_argument("username", "")
  369. password = self.get_argument("password", "")
  370. auth = self.check_permission(password, username)
  371. if auth:
  372. self.set_current_user(username)
  373. print "In designer mode."
  374. with open("cache.yaml", 'r') as stream:
  375. try:
  376. cache_data = yaml.load(stream)
  377. except yaml.YAMLError as exc:
  378. print(exc)
  379. with open("style.yaml", 'r') as stream:
  380. try:
  381. style_data = yaml.load(stream)
  382. except yaml.YAMLError as exc:
  383. print(exc)
  384. if style_data:
  385. index_data = list(set(cache_data) | set(style_data))
  386. else:
  387. index_data = cache_data
  388. data = {
  389. "cache": cache_data,
  390. "style": style_data,
  391. "index": index_data,
  392. }
  393. if "background" in config:
  394. data["background"] = config["background"]
  395. self.render('designer.html', data=data)
  396. else:
  397. error_msg = (u"?error=" +
  398. url_escape("Login incorrect"))
  399. self.redirect(u"/auth/login/" + error_msg)
  400. def set_current_user(self, user):
  401. if user:
  402. self.set_secure_cookie("user", tornado.escape.json_encode(user))
  403. else:
  404. self.clear_cookie("user")
  405. print "Running..."
  406. rt = RepeatedTimer(int(config["polling"]), fetchDataADEI)
  407. application = tornado.web.Application([
  408. (r"/auth/login/?", AuthLoginHandler),
  409. (r"/"+config['title'].lower()+"/version/?", VersionHandler),
  410. (r"/"+config['title'].lower()+"/list/?", ListHandler),
  411. (r"/"+config['title'].lower()+"/start/?", StartHandler),
  412. (r"/"+config['title'].lower()+"/backup/?", BackupHandler),
  413. (r"/"+config['title'].lower()+"/stop/?", StopHandler),
  414. (r"/"+config['title'].lower()+"/designer/?", DesignerHandler),
  415. (r"/"+config['title'].lower()+"/status/?", StatusHandler),
  416. (r"/"+config['title'].lower()+"/save/?", SaveHandler),
  417. (r"/"+config['title'].lower()+"/update/?", UpdateHandler),
  418. (r"/"+config['title'].lower()+"/getdata/?", GetDataHandler),
  419. (r"/"+config['title'].lower()+"/timer/(?P<duration>[^\/]+)/?",
  420. SetTimerHandler),
  421. (r"/"+config['title'].lower()+"/add/(?P<db_server>[^\/]+)/?"
  422. "(?P<db_name>[^\/]+)/?(?P<db_group>[^\/]+)/?(?P<sensor_name>[^\/]+)?",
  423. AdeiKatrinHandler)
  424. ], debug=True, static_path=os.path.join(root, 'static'),
  425. js_path=os.path.join(root, 'js'), login_url="/auth/login",
  426. cookie_secret='L8LwECiNRxq2N0N2eGxx9MZlrpmuMEimlydNX/vt1LM=')
  427. if __name__ == "__main__":
  428. application.listen(int(config["port"]))
  429. tornado.autoreload.start()
  430. tornado.ioloop.IOLoop.instance().start()