# -*- coding: utf-8 -*- import errno import glob import os import re import sqlite3 import stat import time from functools import wraps from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop from tornado.log import app_log as logger from tornado.options import define, options from tornado.web import Application, RequestHandler, StaticFileHandler define('host', default='127.0.0.1', help='run on the given host', type=str) define('port', default=8001, help='run on the given port', type=int) options.parse_command_line() ROOT_PATH = '/home/work/minipai2' # Create Table SQL CREATE_TABLE_STMT = """ CREATE TABLE IF NOT EXISTS photoinfo ( id integer primary key, lensman varchar(20), session varchar(20), photo_id varchar(13), photo_name varchar(255), thumb_path varchar(255), origin_path varchar(255) );""" # Create Index SQL CREATE_INDEX1 = 'CREATE INDEX IF NOT EXISTS idx_lensman ON photoinfo (lensman);' CREATE_INDEX2 = 'CREATE INDEX IF NOT EXISTS idx_session ON photoinfo (session);' # Insert Record SQL INSERT_RECORD_STMT = 'INSERT INTO photoinfo VALUES (NULL, ?, ?, ?, ?, ?, ?);' # Delete Record SQL DELETE_RECORD_STMT = 'DELETE FROM photoinfo WHERE lensman = ? and session = ? and name = ?;' # Query Max(photo_id) SQL SELECT_MAX_PHOTO_ID_STMT = 'SELECT MAX(photo_id) FROM photoinfo WHERE lensman = ? and session = ?;' # Query Origin Path SQL SELECT_ORIGIN_PATH_STMT = 'SELECT origin_path FROM photoinfo WHERE lensman = ? and photo_id = ?;' conn = sqlite3.connect('minipai2.db') cur = conn.cursor() # Synchronous Off # cur.execute('PRAGMA synchronous = OFF') # Execute SQL cur.execute(CREATE_TABLE_STMT) cur.execute(CREATE_INDEX1) cur.execute(CREATE_INDEX2) conn.commit() # Logging Some Vars def logit(self, content, key='content'): uri = self.request.uri if hasattr(self, 'request') else self logger.info('uri=%s&%s=%s', uri, key, content) # Logging Request Arguments def log_request_arguments(func): @wraps(func) def returned_wrapper(self, *args, **kwargs): logit(self, self.request.arguments, key='arguments') return func(self, *args, **kwargs) return returned_wrapper # FILE OPERATE def silent_makdirs(path): try: os.makedirs(path) except OSError as e: if e.errno != errno.EEXIST: raise def silent_remove(path): try: os.remove(path) except OSError as e: if e.errno != errno.ENOENT: raise def get_session_root(lensman, session): return '{}/{}'.format(ROOT_PATH, session) def get_session_dir(lensman, session): session_root = get_session_root(lensman, session) return '{}/{}'.format(session_root, 'origin'), '{}/{}'.format(session_root, 'thumbnail') def create_session_dir(lensman, session): for path in get_session_dir(lensman, session): if os.path.exists(path): return False silent_makdirs(path) return True def get_last_timestamp(lensman, session): cur.execute(SELECT_MAX_PHOTO_ID_STMT, (lensman, session)) result = cur.fetchall() return int(result[0][0] or 0) def insert_session_file(files_): start_at = time.time() cur.executemany(INSERT_RECORD_STMT, files_) conn.commit() end_at = time.time() logit('/fetch_thumbnail', start_at, key='start_at') logit('/fetch_thumbnail', end_at, key='end_at') logit('/fetch_thumbnail', end_at - start_at, key='delta_time') def delete_session_file(lensman, session, name): cur.execute(DELETE_RECORD_STMT, (lensman, session, name)) conn.commit() def get_file_info(file_): photo_name = file_.split('/')[-1] photo_id = photo_name.split('.')[0] thumb_path = file_.replace('{}/'.format(ROOT_PATH), '') origin_path = thumb_path.replace('thumbnail', 'origin') return photo_id, photo_name, thumb_path, origin_path def is_file_valid(file_): if file_.endswith('.tmp'): # Whether 'xxx.tmp' or not return False if not re.match(r'.*\/\d+\.\w+', file_): # Whether 'xxx/digit.xxx' or not return False if not os.stat(file_).st_size: # Whether `file size zero` or not return False return True def get_glob_files(lensman, session): _, thumb = get_session_dir(lensman, session) return glob.iglob('{}/*'.format(thumb)) def get_all_files(lensman, session): # Glob Files files = get_glob_files(lensman, session) # Init Vars files_ = [] # Foreach Glob Files for file_ in files: logit('/session_end', file_, key='globfile') if is_file_valid(file_): photo_id, photo_name, thumb_path, origin_path = get_file_info(file_) # Insert When Photo_id Large Than Maxt files_.append((lensman, session, photo_id, photo_name, thumb_path, origin_path)) # If Having Files To Insert Into SQLite if files_: insert_session_file(files_) return files_ def get_new_files(lensman, session, maxid): # Glob Files files = get_glob_files(lensman, session) # Init Vars files_ = [] # Foreach Glob Files for file_ in files: logit('/fetch_thumbnail', file_, key='globfile') if is_file_valid(file_): photo_id, photo_name, thumb_path, _ = get_file_info(file_) # Return When Photo_id Large Than Maxid # Solve APP Doesn't Get Photo When Timeout if int(photo_id) > maxid: files_.append({ 'id': photo_id, 'name': photo_name, 'path': thumb_path, }) return files_ def get_origin_path_from_id(lensman, session, id_): cur.execute(SELECT_ORIGIN_PATH_STMT, (lensman, id_)) result = cur.fetchall() if not result: return '' origin_path = result[0][0] if not os.path.isfile('{}/{}'.format(ROOT_PATH, origin_path)): return '' return origin_path class HelloHandler(RequestHandler): def get(self): self.write('Hello Tornado') class SessionStartHandler(RequestHandler): @log_request_arguments def post(self): lensman = self.get_argument('lensman', '') session = self.get_argument('session', '') # Create Session Dir created = create_session_dir(lensman, session) # Change Mode to 0777 os.chmod(get_session_root(lensman, session), 0777) self.write({ 'status': 200, 'data': { 'created': created, } }) class SessionEndHandler(RequestHandler): @log_request_arguments def post(self): lensman = self.get_argument('lensman', '') session = self.get_argument('session', '') # Session Root session_root = get_session_root(lensman, session) # Whether Mode Has Changed if stat.S_IMODE(os.stat(session_root).st_mode) != 0700: # Insert Files Into SQLite get_all_files(lensman, session) # Change Mode to 0700 os.chmod(session_root, 0700) self.write({ 'status': 200, }) class FetchThumbnailHandler(RequestHandler): @log_request_arguments def post(self): lensman = self.get_argument('lensman', '') session = self.get_argument('session', '') maxid = int(self.get_argument('maxid', 0)) # New Files files = get_new_files(lensman, session, maxid) # logit(self, maxt, key='maxt') logit(self, files, key='files') self.write({ 'status': 200, 'data': { 'files': files, } }) class FetchOriginHandler(RequestHandler): @log_request_arguments def post(self): lensman = self.get_argument('lensman', '') session = self.get_argument('session', '') id_ = self.get_argument('id', '') path = get_origin_path_from_id(lensman, session, id_) self.write({ 'status': 200, 'data': { 'path': path, } }) class DeletePhotoHandler(RequestHandler): @log_request_arguments def post(self): lensman = self.get_argument('lensman', '') session = self.get_argument('session', '') id_ = self.get_argument('id', '') name = self.get_argument('name', '') path = self.get_argument('path', '') # Delete Record from Sqlite3 delete_session_file(lensman, session, id_) # Delete Photo from Disk origin, thumb = get_session_dir(lensman, session) # Delete Thumbnail silent_remove('{}/{}'.format(thumb, name)) # Delete Origin silent_remove('{}/{}'.format(origin, name)) self.write({ 'status': 200, }) class BoxInfoHandler(RequestHandler): def post(self): self.write({ 'status': 200, 'data': { 'no.': 'paiai000001', 'status': { 'code': '200', 'msg': u'正常', } } }) handlers = [ (r'/', HelloHandler), (r'/session_start', SessionStartHandler), (r'/session_end', SessionEndHandler), (r'/fetch_thumbnail', FetchThumbnailHandler), (r'/fetch_origin', FetchOriginHandler), (r'/delete_photo', DeletePhotoHandler), (r'/box_info', BoxInfoHandler), (r'/static/(.*)', StaticFileHandler, {'path': ROOT_PATH}), ] def main(): app = Application(handlers=handlers, default_host=options.host) server = HTTPServer(app) server.listen(options.port) IOLoop.current().start() if __name__ == '__main__': main()