core.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. # -*- coding: utf-8 -*-
  2. """
  3. demeter
  4. name:core.py
  5. author:rabin
  6. """
  7. import time
  8. import os
  9. import signal
  10. import re
  11. import sys
  12. import json
  13. import subprocess
  14. import importlib
  15. #import fire
  16. from watchdog.observers import Observer
  17. from watchdog.events import FileSystemEventHandler
  18. class Demeter(object):
  19. path = ''
  20. root = ''
  21. config = {}
  22. option = {}
  23. web = ''
  24. request = False
  25. route = []
  26. logger = False
  27. dog = False
  28. def __new__(self, *args, **kwargs):
  29. sys.exit()
  30. def __init__(self):
  31. pass
  32. @staticmethod
  33. def checkPy3():
  34. if sys.version > '3':
  35. state = True
  36. else:
  37. state = False
  38. return state
  39. @classmethod
  40. def getConfig(self):
  41. state = self.checkPy3()
  42. if state:
  43. import configparser
  44. return configparser.ConfigParser()
  45. else:
  46. import ConfigParser
  47. return ConfigParser.ConfigParser()
  48. @staticmethod
  49. def isset(v):
  50. try :
  51. type (eval(v))
  52. except :
  53. return 0
  54. else :
  55. return 1
  56. @classmethod
  57. def initConfig(self):
  58. self.path = File.path()
  59. self.root = File.cur_path()
  60. if self.config == {}:
  61. filename = self.path + 'conf/'+self.getConfigName()+'.conf'
  62. if File.exists(filename):
  63. config = self.getConfig()
  64. config.read(filename)
  65. for item in config.sections():
  66. self.config[item] = self.readConfig(config, item)
  67. return True
  68. else:
  69. Demeter.echo(filename + ' is not exists')
  70. sys.exit()
  71. @classmethod
  72. def getConfigName(self):
  73. name = 'dev'
  74. if 'DEMETER_CONF' in os.environ:
  75. name = os.environ['DEMETER_CONF']
  76. param = {}
  77. param['config'] = 'c'
  78. self.getopt(param)
  79. if 'config' in self.option and self.option['config']:
  80. name = self.option['config']
  81. return name
  82. @staticmethod
  83. def readConfig(config, type):
  84. value = config.options(type)
  85. result = {}
  86. for item in value:
  87. result[item] = config.get(type, item)
  88. return result
  89. @classmethod
  90. def getopt(self, param = {}):
  91. import getopt
  92. param['help'] = 'h'
  93. shortopts = ''
  94. longopts = []
  95. check = []
  96. for k,v in param.items():
  97. if k == 'help':
  98. shortopts = shortopts + v
  99. else:
  100. shortopts = shortopts + v + ':'
  101. longopts.append(k)
  102. try:
  103. options, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
  104. for name, value in options:
  105. for k,v in param.items():
  106. if name in ('-' + v, '--' + k):
  107. if k == 'help':
  108. self.usage()
  109. else:
  110. self.option[k] = value
  111. except getopt.GetoptError:
  112. #self.usage()
  113. return
  114. @classmethod
  115. def usage(self, name = 'usage'):
  116. file = self.path + name
  117. if not File.exists(file):
  118. file = self.root + name
  119. self.echo(File.read(file))
  120. sys.exit()
  121. @classmethod
  122. def temp(self, key='', name='', value=''):
  123. temp = Demeter.path + 'conf/temp.conf'
  124. if File.exists(temp):
  125. config = self.getConfig()
  126. config.read(temp)
  127. if key and name:
  128. config.set(key, name, value)
  129. config.write(open(temp, 'w'))
  130. else:
  131. result = {}
  132. for item in config.sections():
  133. result[item] = self.readConfig(config, item)
  134. return result
  135. @classmethod
  136. def echo(self, args):
  137. import pprint
  138. pprint.pprint(args)
  139. @classmethod
  140. def record(self, key, value):
  141. # 记录日志
  142. # self.log(key, value)
  143. service = self.service('record')
  144. service.push(key, value)
  145. @classmethod
  146. def service(self, name, parent = ''):
  147. self.initConfig()
  148. path = 'service.'
  149. if name == 'common':
  150. path = 'demeter.'
  151. name = 'service'
  152. if parent:
  153. path = path + parent + '.'
  154. service = self.getClass(name, path)
  155. return service()
  156. @classmethod
  157. def adminModel(self, table):
  158. self.initConfig()
  159. config = ('manage_admin', 'manage_log', 'manage_role')
  160. if table in config:
  161. return self.getClass(table, 'demeter.admin.model.')
  162. return False
  163. @classmethod
  164. def model(self, table, name='rdb'):
  165. self.initConfig()
  166. name = self.config['db'][name]
  167. config = self.config[name]
  168. obj = self.getObject('db', 'demeter.')
  169. db = getattr(obj, name.capitalize())
  170. connect = db(config).get()
  171. model = self.adminModel(table)
  172. if not model:
  173. model = self.getClass(table, 'model.')
  174. return model(name, connect, config)
  175. @classmethod
  176. def getMethod(self, module):
  177. import inspect
  178. return inspect.getmembers(module, callable)
  179. @classmethod
  180. def getPackage(self, package):
  181. import pkgutil
  182. for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__ + '.', onerror=lambda x: None):
  183. yield modname
  184. @staticmethod
  185. def getObject(name, path = ''):
  186. return importlib.import_module(path + name)
  187. """
  188. @classmethod
  189. def getObject(self, name, path = ''):
  190. module = __import__(path + name)
  191. return getattr(module, name)
  192. """
  193. @classmethod
  194. def getClass(self, name, path=''):
  195. obj = self.getObject(name, path)
  196. return getattr(obj, name.capitalize())
  197. @staticmethod
  198. def bool(value, type = 'db'):
  199. if type == 'mysql':
  200. value = value == str(True)
  201. if value == True:
  202. return '1'
  203. else:
  204. return '2'
  205. else:
  206. return value == str(True)
  207. @classmethod
  208. def runtime(self, path, file, content=''):
  209. path = self.path + 'runtime/' + path + '/'
  210. File.mkdir(path)
  211. file = path + file
  212. if File.exists(file):
  213. return False
  214. else:
  215. File.write(file, content)
  216. return True
  217. @classmethod
  218. def webInit(self, name):
  219. self.initConfig()
  220. self.web = name
  221. self.webPath = self.path + self.web + '/'
  222. if self.web == 'admin':
  223. self.webPath = self.root + self.web + '/'
  224. self.getObject('main', name + '.')
  225. @classmethod
  226. def md5(self, value, salt=False):
  227. import hashlib
  228. if salt:
  229. if salt == True:
  230. salt = self.rand()
  231. value = value + salt
  232. return hashlib.md5(value.encode("utf-8")).hexdigest() + '_' + salt
  233. else:
  234. return hashlib.md5(value.encode("utf-8")).hexdigest()
  235. @classmethod
  236. def sha1(self, value, salt=False):
  237. import hashlib
  238. if salt:
  239. if salt == True:
  240. salt = self.rand()
  241. value = value + salt
  242. return hashlib.sha1(value.encode("utf-8")).hexdigest() + '_' + salt
  243. else:
  244. return hashlib.sha1(value.encode("utf-8")).hexdigest()
  245. @classmethod
  246. def rand(self, length = 4):
  247. module = self.getObject('random')
  248. rand = getattr(module, 'randint')
  249. salt = ''
  250. chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
  251. len_chars = len(chars) - 1
  252. for i in range(length):
  253. salt += chars[rand(0, len_chars)]
  254. return salt
  255. @classmethod
  256. def hash(self):
  257. return self.md5(str(time.clock()))
  258. @classmethod
  259. def uuid(self, value):
  260. import uuid
  261. return str(uuid.uuid5(uuid.uuid1(), value))
  262. @staticmethod
  263. def hour(value):
  264. if value < 10:
  265. return '0' + str(value)
  266. return value
  267. @staticmethod
  268. def time():
  269. return int(time.time())
  270. @staticmethod
  271. def mktime(value, string='%Y-%m-%d %H:%M:%S'):
  272. if ' ' in string and ' ' not in value:
  273. value = value + ' 00:00:00'
  274. return int(time.mktime(time.strptime(value,string)))
  275. @classmethod
  276. def date(self, value, string='%Y-%m-%d %H:%M:%S'):
  277. module = self.getObject('datetime')
  278. datetime = getattr(module, 'datetime')
  279. fromtimestamp = getattr(datetime, 'fromtimestamp')
  280. return str(fromtimestamp(value).strftime(string))
  281. @staticmethod
  282. def isJson(value):
  283. result = False
  284. try:
  285. result = json.loads(value)
  286. except ValueError:
  287. return result
  288. return result
  289. @staticmethod
  290. def host(value):
  291. import urllib
  292. protocol, s1 = urllib.splittype(value)
  293. value, s2 = urllib.splithost(s1)
  294. value, port = urllib.splitport(value)
  295. return value
  296. @staticmethod
  297. def compressUuid(value):
  298. row = value.replace('-', '')
  299. code = ''
  300. hash = [x for x in "0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
  301. for i in xrange(10):
  302. enbin = "%012d" % int(bin(int(row[i * 3] + row[i * 3 + 1] + row[i * 3 + 2], 16))[2:], 10)
  303. code += (hash[int(enbin[0:6], 2)] + hash[int(enbin[6:12], 2)])
  304. return code
  305. @staticmethod
  306. def checkMobile(request):
  307. if 'Demeter-Mobile' in request.headers:
  308. return True
  309. userAgent = request.headers['User-Agent']
  310. # userAgent = env.get('HTTP_USER_AGENT')
  311. _long_matches = r'googlebot-mobile|android|avantgo|blackberry|blazer|elaine|hiptop|ip(hone|od)|kindle|midp|mmp|mobile|o2|opera mini|palm( os)?|pda|plucker|pocket|psp|smartphone|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce; (iemobile|ppc)|xiino|maemo|fennec'
  312. _long_matches = re.compile(_long_matches, re.IGNORECASE)
  313. _short_matches = r'1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-'
  314. _short_matches = re.compile(_short_matches, re.IGNORECASE)
  315. if _long_matches.search(userAgent) != None:
  316. return True
  317. user_agent = userAgent[0:4]
  318. if _short_matches.search(user_agent) != None:
  319. return True
  320. return False
  321. @staticmethod
  322. def exp(exp, value):
  323. if exp:
  324. exp = exp.replace('{n}', value)
  325. value = str(eval(exp))
  326. return value
  327. @classmethod
  328. def curl(self, url = '', param={}, method = 'get'):
  329. import requests
  330. if method == 'get':
  331. req = requests.get(url, params=param)
  332. else:
  333. req = requests.post(url, params=param)
  334. result = req.text
  335. return result
  336. @classmethod
  337. def out(self, msg='', data={}, code=0, callback='', function=''):
  338. if data:
  339. if 'page' in data and data['page']['total'] <= 0:
  340. del data['page']
  341. if 'update' in data and not data['update']:
  342. del data['update']
  343. if 'search' in data and not data['search']:
  344. del data['search']
  345. result = ''
  346. send = {}
  347. send['status'] = 1
  348. send['msg'] = msg
  349. send['data'] = data
  350. send['code'] = code
  351. if not send['data']:
  352. send['status'] = 2
  353. result = json.dumps(send)
  354. if callback:
  355. result = callback + '(' + result + ')'
  356. elif function:
  357. result = '<script>parent.' + function + '(' + result + ')' + '</script>';
  358. return result
  359. @classmethod
  360. def error(self, string):
  361. if self.request:
  362. self.request.out(string)
  363. else:
  364. self.echo(string)
  365. #os._exit(0)
  366. @classmethod
  367. def redis(self):
  368. self.initConfig()
  369. import redis
  370. config = self.config['redis']
  371. pool = redis.ConnectionPool(host=config['host'], password=config['password'], port=int(config['port']))
  372. return redis.Redis(connection_pool=pool)
  373. class Log(object):
  374. @staticmethod
  375. def init(name):
  376. if Demeter.logger:
  377. return Demeter.logger
  378. import logging
  379. from logging.handlers import RotatingFileHandler
  380. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  381. Demeter.logger = logging.getLogger(name)
  382. Demeter.logger.setLevel(logging.INFO)
  383. path = File.path() + 'runtime/log/'
  384. File.mkdir(path)
  385. file_handler = RotatingFileHandler(os.path.join(path, 'vecan.log'), maxBytes=1024*1024,backupCount=5)
  386. file_handler.setLevel(level=logging.DEBUG)
  387. file_handler.setFormatter(formatter)
  388. Demeter.logger.addHandler(file_handler)
  389. return Demeter.logger
  390. class WatchDog(object):
  391. @staticmethod
  392. def init(path = [], reloads = [], recursive = False):
  393. if Demeter.dog:
  394. return Demeter.dog
  395. event_handler = WatchDogHandle(reloads)
  396. Demeter.dog = Observer()
  397. base = File.path()
  398. if not path:
  399. path = ['conf/',]
  400. for item in path:
  401. Demeter.dog.schedule(event_handler, base + item, recursive=recursive)
  402. Demeter.dog.start()
  403. return Demeter.dog
  404. class WatchDogHandle(FileSystemEventHandler):
  405. @classmethod
  406. def __init__(self, reloads = False):
  407. FileSystemEventHandler.__init__(self)
  408. self.reloads = reloads
  409. @classmethod
  410. def on_modified(self, event):
  411. if not event.is_directory and '.' in event.src_path:
  412. if self.reloads:
  413. for item in self.reloads:
  414. item.reload()
  415. elif Demeter.web:
  416. Demeter.webInit(Demeter.web)
  417. else:
  418. Demeter.echo('modify ' + event.src_path)
  419. class File(object):
  420. @staticmethod
  421. def write(file, content):
  422. handle = open(file, 'w')
  423. handle.write(content)
  424. handle.close()
  425. Shell.popen('chmod +x ' + file)
  426. @staticmethod
  427. def read(path, name = ''):
  428. handle = open(path + name, 'r')
  429. content = handle.read()
  430. handle.close()
  431. return content
  432. @staticmethod
  433. def readContent(path, name = ''):
  434. content = ''
  435. handle = open(path + name, 'r')
  436. while True:
  437. line = handle.readline()
  438. if line:
  439. line = line.rstrip("\n")
  440. content = content + line
  441. else:
  442. break
  443. handle.close()
  444. return content
  445. @staticmethod
  446. def cur_path():
  447. return os.path.split(os.path.realpath(__file__))[0] + '/'
  448. @staticmethod
  449. def getFiles(path):
  450. return os.listdir(path)
  451. @staticmethod
  452. def path():
  453. return os.sys.path[0] + '/'
  454. @staticmethod
  455. def exists(name):
  456. return os.path.exists(name)
  457. @staticmethod
  458. def rename(old, new):
  459. return os.rename(old, new)
  460. @staticmethod
  461. def remove(file):
  462. return os.remove(file)
  463. @staticmethod
  464. def mkdir(path):
  465. if File.exists(path) == False:
  466. os.mkdir(path)
  467. return path
  468. @staticmethod
  469. def mkdirs(path):
  470. if File.exists(path) == False:
  471. os.makedirs(path)
  472. return path
  473. @staticmethod
  474. def ext(path):
  475. return os.path.splitext(path)[1]
  476. class Shell(object):
  477. @staticmethod
  478. def popen(command, sub=False, bg=False, timeout=0):
  479. string = command
  480. if bg == True:
  481. command = command + ' 1>/dev/null 2>&1 &'
  482. if timeout > 0:
  483. proc = subprocess.Popen(command,bufsize=0,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True, close_fds=True, preexec_fn = os.setsid)
  484. poll_seconds = .250
  485. deadline = time.time() + timeout
  486. while time.time() < deadline and proc.poll() == None:
  487. time.sleep(poll_seconds)
  488. if proc.poll() == None:
  489. os.killpg(proc.pid, signal.SIGTERM)
  490. return 'timeout'
  491. stdout,stderr = proc.communicate()
  492. return stdout
  493. elif sub == False:
  494. process = os.popen(command)
  495. output = process.read()
  496. process.close()
  497. return output
  498. else:
  499. popen = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
  500. output = ''
  501. Demeter.echo(string)
  502. while True:
  503. output = popen.stdout.readline()
  504. Demeter.echo(output)
  505. if popen.poll() is not None:
  506. break
  507. return output
  508. class Check(object):
  509. @staticmethod
  510. def match(rule, value):
  511. if not rule.match(value):
  512. return False
  513. return True
  514. @staticmethod
  515. def mobile(value):
  516. rule = re.compile(r'1\d{10}')
  517. return Check.match(rule, value)
  518. @staticmethod
  519. def number(value):
  520. try:
  521. int(value)
  522. return True
  523. except ValueError:
  524. return False
  525. @staticmethod
  526. def numberFloat(value):
  527. try:
  528. float(value)
  529. return True
  530. except ValueError:
  531. return False