123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- import ctypes
- import logging
- import os
- import shutil
- import site
- import sys
- import pythoncom
- import pywintypes
- import win32com.client
- from flask import Flask, jsonify, request, current_app
- from flask_cors import CORS
- from win10toast import ToastNotifier
- from core.wps_handle import is_file_open_in_wps, bring_wps_window_to_front
- from tools.check import detect_oss_file_changes, detect_local_file_changes
- from tools.config import get_config, file_type_map
- from tools.file_manager import get_file_md5
- from tools.logger_handle import logger
- from tools.oss_client import oss_handle
- from tools.serve_client import ServerClient
- toaster = ToastNotifier()
- app = Flask(__name__)
- class InterceptHandler(logging.Handler):
- def emit(self, record):
- # 将标准日志记录转为 loguru
- try:
- level = logger.level(record.levelname).name
- except ValueError:
- level = record.levelno
- logger.opt(depth=6, exception=record.exc_info).log(level, record.getMessage())
- logging.basicConfig(handlers=[InterceptHandler()], level=logging.INFO)
- for name in ("flask", "werkzeug", "watchdog"):
- logging.getLogger(name).handlers = [InterceptHandler()]
- logging.getLogger(name).propagate = False
- CORS(app)
- @logger.catch()
- def open_file_by_wps(file_path):
- ext = file_path.split(".")[-1]
- shutil.rmtree(win32com.client.gencache.GetGeneratePath())
- if ext not in file_type_map:
- return jsonify({'code': 3001, 'msg': '不支持该类型的文件'})
- if not os.path.exists(file_path):
- return jsonify({'code': 3006, 'msg': '文件不存在'})
- pythoncom.CoInitialize()
- try:
- if ext in ['csv', 'xlsx', 'xls']:
- # wps = win32com.client.gencache.EnsureDispatch(file_type_map['xlsx'][0])
- wps = win32com.client.Dispatch(file_type_map[ext][0])
- wps.Visible = True
- getattr(wps, file_type_map[ext][1]).Open(os.path.abspath(file_path))
- else:
- wps = win32com.client.Dispatch(file_type_map[ext][0])
- wps.Visible = True
- getattr(wps, file_type_map[ext][1]).open(os.path.abspath(file_path))
- except pywintypes.com_error as e:
- logger.exception(e)
- bring_wps_window_to_front(file_path)
- pythoncom.CoUninitialize()
- return jsonify({'code': 1000, 'msg': '操作完成'})
- @logger.catch()
- @app.route('/download_and_open_file', methods=['POST'])
- def download_and_open_with_wps():
- '''
- 1000: 操作完成
- 2001: 检测到文档正在被编辑,无法下载
- 2002: 检测到远程文件已经更新本地文件也发生改动,终止操作
- 3001: 不支持该类型的文件
- 3002: 下载文件失败
- :return:
- '''
- file_id = request.get_json()['file_id']
- # 判断是否为exe模式执行
- file_info = app.config['serve_client'].get_file_info(file_id)
- if not file_info:
- return jsonify({'code': 3006, 'msg': '文件不存在'})
- local_file = os.path.join(current_app.config['work_path'], file_info['filePath'].replace('/', '_'))
- # 判断本地是否存在已下载的同名文件
- if not os.path.exists(local_file) or not os.path.exists(local_file + '.metadata.json'):
- app.config['serve_client'].download_file(file_info,
- current_app.config['work_path'])
- return open_file_by_wps(local_file)
- # 判断本地文件是否被打开
- if is_file_open_in_wps(local_file):
- bring_wps_window_to_front(local_file)
- return jsonify({'code': 1000, 'msg': '检测到文件已被打开'})
- # 判断本地文件和线上文件是否一致
- local_file_metadata = oss_handle.load_metadata(local_file)
- if local_file_metadata['update_time'] == file_info['updateTime']:
- return open_file_by_wps(local_file)
- if local_file_metadata['md5'] == app.config['serve_client'].get_file_md5(local_file):
- app.config['serve_client'].download_file(file_info, current_app.config['work_path'])
- return open_file_by_wps(local_file)
- return jsonify({'code': 2002, 'msg': '检测到远程文件已经更新本地文件也发生改动,终止操作'})
- @logger.catch()
- @app.route('/upload_local_file', methods=['POST'])
- def upload_local_file():
- file_name = request.get_json()['file_name']
- if is_file_open_in_wps(os.path.join(current_app.config['work_path'], file_name)):
- return jsonify({'code': 3004, 'msg': '操作失败,文件已被打开无法操作'})
- metadata = app.config['serve_client'].load_metadata(os.path.join(current_app.config['work_path'], file_name))
- code = app.config['serve_client'].upload_file(os.path.join(current_app.config['work_path'], file_name))
- if not code:
- return jsonify({'code': 3003, 'msg': '操作失败,上传文件失败'})
- try:
- os.remove(os.path.join(current_app.config['work_path'], file_name))
- os.remove(os.path.join(current_app.config['work_path'], file_name + '.metadata'))
- file_info = app.config['serve_client'].get_file_info(metadata['file_id'])
- if not file_info:
- return jsonify({'code': 3006, 'msg': '文件不存在'})
- app.config['serve_client'].download_file(file_info, current_app.config['work_path'])
- except Exception as e:
- logger.exception(e)
- return jsonify({'code': 1000, 'msg': '文件上传成功,本地文件清除失败'})
- return jsonify({'code': 1000, 'msg': '操作成功'})
- @logger.catch()
- @app.route('/update_local_file', methods=['POST'])
- def update_local_file():
- file_name = request.get_json()['file_name']
- if is_file_open_in_wps(os.path.join(current_app.config['work_path'], file_name)):
- return jsonify({'code': 3004, 'msg': '操作失败,文件已被打开无法操作'})
- try:
- metadata = oss_handle.load_metadata(os.path.join(current_app.config['work_path'], file_name))
- os.remove(os.path.join(current_app.config['work_path'], file_name))
- os.remove(os.path.join(current_app.config['work_path'], file_name + '.metadata'))
- except Exception as e:
- logger.exception(e)
- return jsonify({'code': 3005, 'msg': '操作失败,无权限操作本地文件'})
- try:
- file_info = app.config['serve_client'].get_file_info(metadata['file_id'])
- if not app.config['serve_client'].download_file(file_info, current_app.config['work_path']):
- return jsonify({'code': 3005, 'msg': '文件下载失败'})
- except Exception as e:
- logger.exception(e)
- return jsonify({'code': 3005, 'msg': '文件下载失败'})
- return jsonify({'code': 1000, 'msg': '操作成功'})
- @logger.catch()
- @app.route('/file_state_list', methods=['GET'])
- def file_state_list():
- '''
- state : 0 正常, 1: 云端有更新 2: 本地有变动且无冲突可以上传 3: 本地文件和云端文件有冲突
- :return:
- '''
- file_info_list = []
- for file_name in os.listdir(current_app.config['work_path']):
- suffer = file_name.split('.')[-1]
- if suffer not in file_type_map:
- continue
- if not os.path.exists(os.path.join(current_app.config['work_path'], file_name + '.metadata')):
- continue
- metadata = oss_handle.load_metadata(os.path.join(current_app.config['work_path'], file_name))
- file_info = {
- 'file_name': file_name,
- 'show_name': metadata['file_name'],
- 'cloud_update_time': metadata['update_time'],
- 'source_md5': metadata['md5'],
- 'state': 0
- }
- cloud_file_info = current_app.config['serve_client'].get_file_info(metadata['file_id'])
- if cloud_file_info == 2:
- file_info['state'] = 4
- file_info_list.append(file_info)
- continue
- if not cloud_file_info:
- file_info_list.append(file_info)
- continue
- if cloud_file_info['updateTime'] != metadata['update_time']:
- file_info['state'] = 1
- try:
- file_md5 = get_file_md5(os.path.join(current_app.config['work_path'], file_name))
- if file_md5 != metadata['md5']:
- if file_info['state'] == 1:
- file_info['state'] = 3
- else:
- file_info['state'] = 2
- except Exception as e:
- logger.exception(e)
- file_info_list.append(file_info)
- return jsonify({'code': 1000, 'msg': '操作成功', 'data': file_info_list})
- @logger.catch()
- @app.route('/remove_file', methods=['POST'])
- def remove_file():
- file_name = request.get_json()['file_name']
- file_path = os.path.join(current_app.config['work_path'], file_name)
- if not os.path.exists(file_path):
- return jsonify({'code': '3006', 'msg': '文件不存在'})
- try:
- os.remove(file_path)
- os.remove(f'{file_path}.metadata')
- except Exception as e:
- logger.exception(e)
- return jsonify({'code': 3005, 'msg': '操作失败,无权限操作本地文件'})
- return jsonify({'code': 1000, 'msg': '操作成功'})
- @logger.catch()
- @app.route('/open_file', methods=['POST'])
- def open_file():
- file_name = request.get_json()['file_name']
- file_path = os.path.join(current_app.config['work_path'], file_name)
- if not os.path.exists(file_path):
- return jsonify({'code': '3006', 'msg': '文件不存在'})
- if is_file_open_in_wps(file_path):
- bring_wps_window_to_front(file_path)
- return jsonify({'code': 1000, 'msg': '检测到文件已被打开'})
- return open_file_by_wps(file_path)
- def start_flask(serve_client, work_path):
- app.config['serve_client'] = serve_client
- app.config['work_path'] = work_path
- # app.logger.handlers.clear()
- # app.logger.addHandler(InterceptHandler())
- app.run(host='0.0.0.0', port=5855)
|