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 dst = open("./logger/" + fileName, "a") 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 237def gen_ssl(cert_file, key_file): 238 serial_number = 123456789 239 organization = "www.smartperf.com" 240 organizational_unit = "ITs" 241 common_name = "www.smartperf.com" 242 validity_days = 3650 243 subprocess.run(["openssl", "genpkey", "-algorithm", "RSA", "-out", key_file]) 244 csr_file = "cert/cert.csr" 245 subprocess.run(["openssl", "req", "-new", "-key", key_file, "-out", csr_file, "-subj", 246 "/O={}/OU={}/CN={}".format(organization, organizational_unit, common_name)]) 247 subprocess.run(["openssl", "x509", "-req", "-days", str(validity_days), "-in", csr_file, "-signkey", 248 key_file, "-out", cert_file, "-set_serial", str(serial_number)]) 249 250class SpServer: 251 def __init__(self, server_address, cert_file_path, keyfile_path): 252 global version 253 global serveInfo 254 version = read_text('version.txt') 255 serveInfo = read_text('server-config.txt') 256 self.server_address = server_address 257 self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) 258 self.context.load_cert_chain(cert_file_path, keyfile_path) 259 self.httpd = ThreadingHTTPServer(server_address, SpRequestHandler) 260 self.httpd.socket = self.context.wrap_socket(self.httpd.socket, True) 261 262 def start(self): 263 print(f'HTTPS[{PORT}] SmartPerf Server Start') 264 if is_windows(): 265 openWeb("https://127.0.0.1:9000/application/") 266 self.httpd.serve_forever() 267 268 269def main(): 270 check_port(PORT) 271 if not os.path.exists(CERT_FILE) or not os.path.exists(KEY_FILE): 272 if is_linux(): 273 if not os.path.exists('./cert'): 274 os.makedirs('./cert') 275 gen_ssl(CERT_FILE, KEY_FILE) 276 server_address = ('', PORT) 277 server = SpServer(server_address, CERT_FILE, KEY_FILE) 278 server.start() 279 280 281if __name__ == '__main__': 282 main() 283