1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (C) 2023 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import http 17import json 18from datetime import datetime 19from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer 20import ssl 21import os 22from urllib.parse import urlparse 23import urllib.request 24import subprocess 25import re 26import platform 27import webbrowser 28 29PORT = 9000 30CERT_FILE = './cert/certFile.pem' 31KEY_FILE = './cert/keyFile.key' 32version = 'v1.0.0' 33serveInfo = '' 34 35 36def is_windows(): 37 return platform.system() == 'Windows' 38 39 40def is_darwin(): 41 return platform.system() == 'Darwin' 42 43 44def is_linux(): 45 return platform.system() == 'Linux' 46 47 48def openWeb(url): 49 webbrowser.open(url) 50 51 52def get_pid_by_port(port_number): 53 res_pid = -1 54 cmd_res = subprocess.run(f"netstat -ano -p tcp | findstr {port_number}", capture_output=True, text=True, 55 shell=True) 56 cmd_res_str = cmd_res.stdout 57 find_str = re.findall(r'\s(\d+)\s', cmd_res_str) 58 if len(find_str) > 0: 59 try: 60 res_pid = int(find_str[0]) 61 except ValueError: 62 res_pid = -1 63 return res_pid 64 65 66def check_port(port): 67 if is_windows(): 68 pid = get_pid_by_port(port) 69 if pid != -1: 70 subprocess.run(f"taskkill /F /PID {pid} /T", shell=True) 71 72 73class SpRequestHandler(http.server.BaseHTTPRequestHandler): 74 global version 75 global serveInfo 76 77 def log_message(self, format, *args): 78 return 79 80 def do_GET(self): 81 parse_result = urlparse(self.path) 82 if parse_result.path == '/application/serverInfo': 83 self.serverInfo_handler() 84 elif parse_result.path.startswith('/application'): 85 self.application_handler(parse_result) 86 else: 87 self.send_error(404, 'Not found') 88 89 def do_POST(self): 90 parse_result = urlparse(self.path) 91 if parse_result.path.startswith('/logger'): 92 self.console_handler() 93 elif parse_result.path.startswith('/upload'): 94 print(f'upload') 95 96 elif parse_result.path.startswith('/download-file'): 97 print(f'download-file') 98 self.download_handler() 99 100 def download_handler(self): 101 self.clear_overdue_file() 102 content_type = self.headers.get("Content-Type") 103 if content_type and content_type.startswith("application/x-www-form-urlencoded"): 104 url = self.post_form_value("url") 105 try: 106 req = urllib.request.Request(url) 107 response = urllib.request.urlopen(req) 108 content = response.read().decode("utf-8") 109 except Exception as e: 110 self.send_response(200) 111 response = {"success": False, "code": -1, "message": str(e), "data": None} 112 self.wfile.write(bytes(json.dumps(response), "utf-8")) 113 return 114 suffixStr = os.path.splitext(url.split("/")[-1])[1] 115 file_name = f"upload/{datetime.now().strftime('%Y%m%d%H%M%S%f')}{suffixStr}" 116 os.makedirs(os.path.dirname(file_name), exist_ok=True) 117 try: 118 with open(file_name, "wb") as f: 119 f.write(content) 120 written = f.tell() 121 except Exception as e: 122 self.send_response(200) 123 response = {"success": False, "code": -1, "message": str(e), "data": None} 124 self.wfile.write(bytes(json.dumps(response), "utf-8")) 125 return 126 self.send_response(200) 127 response = {"success": True, "code": 0, "message": "success", "data": {"url": file_name, "size": written}} 128 self.wfile.write(bytes(json.dumps(response), "utf-8")) 129 return 130 131 def post_form_value(self, key): 132 content_length = int(self.headers.get("Content-Length", 0)) 133 post_data = self.rfile.read(content_length).decode("utf-8") 134 for param in post_data.split("&"): 135 param_key, param_value = param.split("=") 136 if param_key == key: 137 return param_value 138 return "" 139 140 def clear_overdue_file(self): 141 path = "./upload/" 142 upload_dir = os.path.dirname(os.path.normpath(path)) 143 if not os.path.exists(upload_dir): 144 os.makedirs(upload_dir) 145 now = datetime.now() 146 for root, dirs, files in os.walk(path): 147 for file_name in files: 148 file_path = os.path.join(root, file_name) 149 if self.check_due(file_name): 150 print(f"{now} delete -> {file_path}") 151 os.remove(file_path) 152 153 def check_due(self, file_name): 154 now = datetime.now() 155 datetime_str = os.path.splitext(os.path.basename(file_name))[0] 156 fileDate = datetime.strptime(datetime_str, "%Y%m%d%H%M%S%f") 157 return (now - fileDate).total_seconds() > 3600 158 159 def console_handler(self): 160 self.check_dir('./logger') 161 nowDate = datetime.now() 162 now = nowDate.strftime("%Y-%m-%d") 163 fileName = f"{now}.txt" 164 with open("./logger/" + fileName, "a") as dst: 165 content_type = self.headers.get("Content-Type") 166 if content_type and content_type.startswith("application/json"): 167 content_length = int(self.headers.get("Content-Length", 0)) 168 req_data = self.rfile.read(content_length) 169 req = json.loads(req_data) 170 now = datetime.now() 171 formatted_date = now.strftime("%Y-%m-%d %H:%M:%S") 172 dst.write(f"{formatted_date} {req['fileName']} ({req['fileSize']} M)\n") 173 self.send_response(200) 174 self.send_header("Content-type", "text/html") 175 self.end_headers() 176 self.wfile.write(bytes(f"日志写入成功", "utf-8")) 177 178 def check_dir(self, dir_path): 179 if not os.path.exists(dir_path): 180 os.makedirs(dir_path) 181 182 def application_handler(self, parse_result): 183 file_path = parse_result.path[12:] 184 file_extension = os.path.splitext(file_path)[1] 185 if file_path == '/' or file_path == '': 186 file_path = './index.html' 187 file_extension = '.html' 188 else: 189 file_path = '.' + file_path 190 try: 191 with open(file_path, 'rb') as file: 192 content = file.read() 193 self.send_response(200) 194 self.send_header('Content-type', get_content_type(file_extension)) 195 self.send_header("Cross-Origin-Opener-Policy", "same-origin") 196 self.send_header("Cross-Origin-Embedder-Policy", "require-corp") 197 self.send_header("Access-Control-Allow-Origin", "*") 198 self.send_header("Access-Control-Allow-Credentials", "true") 199 self.send_header("Access-Control-Allow-Headers", "x-requested-with, authorization, blade-auth") 200 self.send_header("Access-Control-Allow-Methods", "*") 201 self.send_header("Access-Control-Max-Age", "3600") 202 self.send_header("data-version", version) 203 self.end_headers() 204 self.wfile.write(content) 205 except FileNotFoundError: 206 self.send_error(404, 'File not found') 207 208 def serverInfo_handler(self): 209 self.send_response(200) 210 self.send_header("Access-Control-Allow-Origin", "*") 211 self.send_header("request_info", serveInfo) 212 self.end_headers() 213 214 215def read_text(read_file_path): 216 try: 217 with open(read_file_path, 'r') as file: 218 content = file.read() 219 return content 220 except IOError: 221 return None 222 223 224def get_content_type(file_extension): 225 if file_extension == '.js': 226 return 'application/javascript' 227 if file_extension == '.wasm': 228 return 'application/wasm' 229 if file_extension == '.json': 230 return 'application/json' 231 if file_extension == '.html': 232 return 'text/html' 233 if file_extension == '.svg': 234 return 'image/svg+xml' 235 return 'text/plain' 236 237 238def gen_ssl(cert_file, key_file): 239 serial_number = 123456789 240 organization = "www.smartperf.com" 241 organizational_unit = "ITs" 242 common_name = "www.smartperf.com" 243 validity_days = 3650 244 subprocess.run(["openssl", "genpkey", "-algorithm", "RSA", "-out", key_file]) 245 csr_file = "cert/cert.csr" 246 subprocess.run(["openssl", "req", "-new", "-key", key_file, "-out", csr_file, "-subj", 247 "/O={}/OU={}/CN={}".format(organization, organizational_unit, common_name)]) 248 subprocess.run(["openssl", "x509", "-req", "-days", str(validity_days), "-in", csr_file, "-signkey", 249 key_file, "-out", cert_file, "-set_serial", str(serial_number)]) 250 251 252class SpServer: 253 def __init__(self, server_address, cert_file_path, keyfile_path): 254 global version 255 global serveInfo 256 version = read_text('version.txt') 257 serveInfo = read_text('server-config.txt') 258 self.server_address = server_address 259 self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) 260 self.context.load_cert_chain(cert_file_path, keyfile_path) 261 self.httpd = ThreadingHTTPServer(server_address, SpRequestHandler) 262 self.httpd.socket = self.context.wrap_socket(self.httpd.socket, True) 263 264 def start(self): 265 print(f'HTTPS[{PORT}] SmartPerf Server Start') 266 if is_windows(): 267 openWeb("https://127.0.0.1:9000/application/") 268 self.httpd.serve_forever() 269 270 271def main(): 272 check_port(PORT) 273 if not os.path.exists(CERT_FILE) or not os.path.exists(KEY_FILE): 274 if is_linux(): 275 if not os.path.exists('./cert'): 276 os.makedirs('./cert') 277 gen_ssl(CERT_FILE, KEY_FILE) 278 server_address = ('', PORT) 279 server = SpServer(server_address, CERT_FILE, KEY_FILE) 280 server.start() 281 282 283if __name__ == '__main__': 284 main() 285