• 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		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