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