• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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