1// Copyright (C) 2022 Huawei Device Co., Ltd. 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package main 15 16//遇到报错请在当前目录下执行这个命令: go mod download golang.org/x/text 17import ( 18 "bufio" 19 "bytes" 20 "crypto/rand" 21 "crypto/rsa" 22 "crypto/tls" 23 "crypto/x509" 24 "crypto/x509/pkix" 25 "encoding/json" 26 "encoding/pem" 27 "fmt" 28 "io" 29 "io/fs" 30 "log" 31 "math/big" 32 "mime" 33 "net" 34 "net/http" 35 "net/http/cookiejar" 36 "os" 37 "os/exec" 38 "path" 39 "path/filepath" 40 "regexp" 41 "runtime" 42 "strconv" 43 "strings" 44 "time" 45) 46 47const HttpPort = 9000 48 49var exPath string 50var serveInfo string 51 52// CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go 53// CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go 54func cors(fs http.Handler, version string) http.HandlerFunc { 55 return func(w http.ResponseWriter, r *http.Request) { 56 // return if you do not want the FileServer handle a specific request 57 r.Header.Add("Cross-Origin-Opener-Policy", "same-origin") 58 r.Header.Add("Cross-Origin-Embedder-Policy", "require-corp") 59 w.Header().Add("Cross-Origin-Opener-Policy", "same-origin") 60 w.Header().Add("Cross-Origin-Embedder-Policy", "require-corp") 61 w.Header().Set("Access-Control-Allow-Origin", "*") 62 w.Header().Set("Access-Control-Allow-Credentials", "true") 63 w.Header().Set("Access-Control-Allow-Headers", "x-requested-with, authorization, blade-auth") //* 64 w.Header().Set("Access-Control-Allow-Methods", "*") //* 65 w.Header().Set("Access-Control-Max-Age", "3600") 66 w.Header().Set("data-version", version) 67 w.Header().Set("Cache-Control", "no-cache") 68 w.Header().Set("Pragma", "no-cache") 69 fs.ServeHTTP(w, r) 70 } 71} 72 73func exist(path string) bool { 74 _, err := os.Stat(path) 75 if err != nil { 76 if os.IsExist(err) { 77 return true 78 } 79 return false 80 } 81 return true 82} 83func genSSL() { 84 if exist("cert/keyFile.key") || exist("cert/certFile.pem") { 85 fmt.Println("keyFile.key exists") 86 return 87 } 88 max := new(big.Int).Lsh(big.NewInt(1), 128) 89 serialNumber, _ := rand.Int(rand.Reader, max) 90 subject := pkix.Name{ 91 Organization: []string{"www.smartperf.com"}, 92 OrganizationalUnit: []string{"ITs"}, 93 CommonName: "www.smartperf.com", 94 } 95 certificate509 := x509.Certificate{ 96 SerialNumber: serialNumber, 97 Subject: subject, 98 NotBefore: time.Now(), 99 NotAfter: time.Now().AddDate(10, 0, 0), 100 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 101 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 102 IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, 103 } 104 chekDir("cert") 105 pk, _ := rsa.GenerateKey(rand.Reader, 1024) 106 derBytes, _ := x509.CreateCertificate(rand.Reader, &certificate509, &certificate509, &pk.PublicKey, pk) 107 certOut, _ := os.Create("cert/certFile.pem") 108 pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 109 certOut.Close() 110 keyOut, _ := os.Create("cert/keyFile.key") 111 pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}) 112 keyOut.Close() 113} 114func main() { 115 checkPort(HttpPort) 116 genSSL() 117 exPath = getCurrentAbPath() 118 fmt.Println(exPath) 119 go func() { 120 version := "" 121 readVersion, versionErr := os.ReadFile(exPath + "/version.txt") 122 if versionErr != nil { 123 version = "" 124 } else { 125 version = string(readVersion) 126 } 127 readReqServerConfig() 128 mux := http.NewServeMux() 129 mime.TypeByExtension(".js") 130 mime.AddExtensionType(".js", "application/javascript") 131 log.Println(mime.TypeByExtension(".js")) 132 mux.HandleFunc("/logger", consoleHandler) 133 mux.Handle("/application/upload/", http.StripPrefix("/application/upload/", http.FileServer(http.Dir(filepath.FromSlash(exPath+"/upload"))))) 134 mux.HandleFunc("/application/download-file", downloadHandler) 135 mux.HandleFunc("/application/serverInfo", serverInfo) 136 fs := http.FileServer(http.Dir(exPath + "/")) 137 mux.Handle("/application/", http.StripPrefix("/application/", cors(fs, version))) 138 go func() { 139 ser := &http.Server{ 140 Addr: fmt.Sprintf(":%d", HttpPort), 141 Handler: mux, 142 } 143 log.Println(fmt.Sprintf("HTTPS[%d]服务启动", HttpPort)) 144 err := ser.ListenAndServeTLS("cert/certFile.pem", "cert/keyFile.key") 145 CheckErr(err) 146 }() 147 go func() { 148 ser := &http.Server{ 149 Addr: fmt.Sprintf(":%d", HttpPort+1), 150 Handler: mux, 151 } 152 log.Println(fmt.Sprintf("HTTP[%d]服务启动", HttpPort)) 153 err := ser.ListenAndServe() 154 CheckErr(err) 155 }() 156 open(fmt.Sprintf("https://localhost:%d/application", HttpPort)) 157 }() 158 select {} 159} 160 161func getPidByPort(portNumber int) int { 162 resPid := -1 163 var out bytes.Buffer 164 cmdRes := exec.Command("cmd", "/c", fmt.Sprintf("netstat -ano -p tcp | findstr %d", portNumber)) 165 cmdRes.Stdout = &out 166 cmdRes.Run() 167 cmdResStr := out.String() 168 findStr := regexp.MustCompile(`\s\d+\s`).FindAllString(cmdResStr, -1) 169 if len(findStr) > 0 { 170 pid, err := strconv.Atoi(strings.TrimSpace(findStr[0])) 171 if err != nil { 172 resPid = -1 173 } else { 174 resPid = pid 175 } 176 } 177 return resPid 178} 179 180type LoggerReq struct { 181 FileName string `json:"fileName"` 182 FileSize string `json:"fileSize"` 183} 184 185func consoleHandler(w http.ResponseWriter, r *http.Request) { 186 chekDir(exPath + "/logger") 187 var now = time.Now() 188 var fileName = fmt.Sprintf("%d-%d-%d", now.Year(), now.Month(), now.Day()) 189 dst, err := os.OpenFile(exPath+"/logger/"+fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND|os.O_SYNC, 0666) 190 CheckErr(err) 191 contentType := r.Header["Content-Type"] 192 if len(contentType) > 0 { 193 contentTypeName := contentType[0] 194 if strings.HasPrefix(contentTypeName, "application/json") { 195 decoder := json.NewDecoder(r.Body) 196 var req LoggerReq 197 decoder.Decode(&req) 198 dst.WriteString(fmt.Sprintf("%s %s (%s M)\n", now.Format("2006-01-02 15:04:05"), req.FileName, req.FileSize)) 199 fmt.Fprintf(w, fmt.Sprintf("日志写入成功%s", exPath)) 200 } 201 } 202} 203 204func serverInfo(w http.ResponseWriter, r *http.Request) { 205 w.Header().Set("Access-Control-Allow-Origin", "*") 206 w.Header().Set("request_info", serveInfo) 207 w.WriteHeader(200) 208} 209 210func readReqServerConfig() string { 211 readServerConfig, serverConfigErr := os.ReadFile(exPath + "/server-config.txt") 212 if serverConfigErr != nil { 213 serveInfo = "" 214 } else { 215 serveInfo = string(readServerConfig) 216 } 217 return serveInfo 218} 219 220func mapToJson(m map[string]interface{}) (string, error) { 221 marshal, err := json.Marshal(m) 222 if err != nil { 223 return "", err 224 } 225 var str = string(marshal) 226 return str, nil 227} 228func jsonToMap(str string) (map[string]interface{}, error) { 229 var m = make(map[string]interface{}) 230 err := json.Unmarshal([]byte(str), &m) 231 if err != nil { 232 return nil, err 233 } 234 return m, nil 235} 236 237// MkDir 创建目录 238func MkDir(path string) { 239 dir := path[0:strings.LastIndex(path, string(os.PathSeparator))] //从文件路径获取目录 240 if _, err := os.Stat(dir); err != nil { //如果目录不存在,创建目录 241 os.MkdirAll(dir, os.ModePerm) 242 } 243} 244 245func resp(w *http.ResponseWriter) func(bool, int, string, map[string]interface{}) { 246 return func(success bool, code int, msg string, obj map[string]interface{}) { 247 toJson, err := mapToJson(map[string]interface{}{ 248 "success": success, 249 "code": code, 250 "msg": msg, 251 "data": obj, 252 }) 253 if err != nil { 254 errRes, _ := mapToJson(map[string]interface{}{ 255 "success": false, 256 "code": -1, 257 "msg": err.Error(), 258 }) 259 fmt.Fprintf(*w, errRes) 260 } else { 261 fmt.Fprintf(*w, toJson) 262 } 263 } 264} 265 266func get(url string) (*http.Response, error) { 267 jar, _ := cookiejar.New(nil) 268 c := &http.Client{ 269 Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, 270 CheckRedirect: nil, 271 Jar: jar, 272 Timeout: time.Duration(3600) * time.Second, 273 } 274 return c.Get(url) 275} 276 277func clearOverdueFile() { 278 MkDir(filepath.FromSlash(fmt.Sprintf("./upload/"))) 279 now := time.Now() 280 loc, err := time.LoadLocation("Asia/Shanghai") 281 if err != nil { 282 return 283 } 284 var checkDue = func(fileName string) bool { 285 f := getSuffixByUrl(fileName) 286 parseTime, err := time.ParseInLocation("20060102150405000", f.fileName, loc) 287 if err != nil { 288 return false 289 } 290 sub := now.Sub(parseTime) 291 if sub.Minutes() > 60 { //bigger than 60 min flag due 292 return true 293 } 294 return false 295 } 296 slash := filepath.FromSlash(fmt.Sprintf("./upload/")) 297 filepath.WalkDir(slash, func(path string, d fs.DirEntry, err error) error { 298 if checkDue(d.Name()) { 299 fmt.Println(now, "delete->", path, d.Name(), err) 300 os.Remove(path) 301 } 302 return nil 303 }) 304} 305func getSuffixByUrl(u string) struct { 306 fileName string 307 suffix string 308} { 309 lastIndex := strings.LastIndex(u, "/") 310 var f string 311 if lastIndex != -1 { 312 f = u[lastIndex:] 313 } else { 314 f = u 315 } 316 index := strings.LastIndex(f, ".") 317 if index != -1 { 318 return struct { 319 fileName string 320 suffix string 321 }{ 322 f[0:index], 323 f[index:], 324 } 325 } else { 326 return struct { 327 fileName string 328 suffix string 329 }{ 330 f, 331 "", 332 } 333 } 334} 335 336func downloadHandler(w http.ResponseWriter, r *http.Request) { 337 w.Header().Set("content-type", "text/json") 338 clearOverdueFile() 339 contentType := r.Header["Content-Type"] 340 if len(contentType) > 0 { 341 contentTypeName := contentType[0] 342 if strings.HasPrefix(contentTypeName, "application/x-www-form-urlencoded") { 343 url := r.PostFormValue("url") 344 res, err := get(url) 345 if err != nil { 346 resp(&w)(false, -1, err.Error(), nil) 347 return 348 } 349 pth := filepath.FromSlash(fmt.Sprintf("/upload/%s%s", time.Now().Format("20060102150405000"), getSuffixByUrl(url).suffix)) 350 MkDir("." + pth) 351 create, err := os.Create("." + pth) 352 if err != nil { 353 resp(&w)(false, -1, err.Error(), nil) 354 return 355 } 356 written, err := io.Copy(create, res.Body) 357 if err != nil { 358 resp(&w)(false, -1, err.Error(), nil) 359 return 360 } 361 fmt.Println(url, written) 362 pth = "/application" + pth 363 resp(&w)(true, 0, "success", map[string]interface{}{ 364 "url": pth, 365 "size": written, 366 }) 367 return 368 } 369 } 370 resp(&w)(false, -1, "请求方式错误", nil) 371} 372 373func SplitLines(s string) []string { 374 var lines []string 375 sc := bufio.NewScanner(strings.NewReader(s)) 376 for sc.Scan() { 377 lines = append(lines, sc.Text()) 378 } 379 return lines 380} 381 382func readFileFirstLine(path string) string { 383 file, err := os.Open(path) 384 if err != nil { 385 return "" 386 } 387 defer file.Close() 388 389 readFile := bufio.NewReader(file) 390 line, readErr := readFile.ReadString('\n') 391 if readErr != nil || io.EOF == err { 392 return "" 393 } 394 return line 395} 396 397func PathExists(path string) (bool, error) { 398 _, err := os.Stat(path) 399 if err == nil { 400 return true, nil 401 } 402 if os.IsNotExist(err) { 403 return false, nil 404 } 405 return false, err 406} 407 408func chekDir(path string) { 409 _, err := os.Stat(path) 410 if err != nil { 411 err := os.Mkdir(path, os.ModePerm) 412 if err != nil { 413 fmt.Printf("mkdir failed![%v]\n", err) 414 } else { 415 fmt.Printf("mkdir success!\n") 416 } 417 } 418} 419func CheckErr(err error) { 420 if err != nil { 421 log.Panicln(err) 422 } 423} 424 425func open(url string) error { 426 if isWindows() { 427 return openUrlWindows(url) 428 } else if isDarwin() { 429 return openUrlDarwin(url) 430 } else { 431 return openUrlOther(url) 432 } 433} 434 435func openUrlWindows(url string) error { 436 cmd := "cmd" 437 args := []string{"/c", "start", url} 438 return exec.Command(cmd, args...).Start() 439} 440func openUrlDarwin(url string) error { 441 var cmd = "open" 442 var args = []string{url} 443 return exec.Command(cmd, args...).Start() 444} 445func openUrlOther(url string) error { 446 var cmd = "xdg-open" 447 var args = []string{url} 448 return exec.Command(cmd, args...).Start() 449} 450 451func isWindows() bool { 452 return runtime.GOOS == "windows" 453} 454func isDarwin() bool { 455 return runtime.GOOS == "darwin" 456} 457 458func getCurrentAbPath() string { 459 dir := getExecutePath() 460 tmpDir, _ := filepath.EvalSymlinks(os.TempDir()) 461 if strings.Contains(dir, tmpDir) { 462 return getCallerPath() 463 } 464 return dir 465} 466 467func getCallerPath() string { 468 var pth string 469 _, fName, _, ok := runtime.Caller(0) 470 if ok { 471 pth = path.Dir(fName) 472 } 473 return pth 474} 475func getExecutePath() string { 476 pth, err := os.Executable() 477 if err != nil { 478 log.Fatal(err) 479 } 480 res, _ := filepath.EvalSymlinks(filepath.Dir(pth)) 481 return res 482} 483 484func checkPort(port int) { 485 if isWindows() { 486 pid := getPidByPort(port) 487 if pid != -1 { 488 res := exec.Command("cmd", "/c", fmt.Sprintf("taskkill /F /PID %d /T", pid)) 489 res.Run() 490 } 491 } 492} 493