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