package core import ( "bytes" "encoding/json" "fmt" "github.com/wailsapp/wails/v2/pkg/runtime" "io" "log" "net" "net/http" "net/url" "os" "os/exec" "path/filepath" sysRuntime "runtime" "strings" ) type respData map[string]interface{} type ResponseData struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data"` } type HttpServer struct{} func initHttpServer() *HttpServer { if httpServerOnce == nil { httpServerOnce = &HttpServer{} } return httpServerOnce } func (h *HttpServer) run() { listener, err := net.Listen("tcp", globalConfig.Host+":"+globalConfig.Port) if err != nil { globalLogger.Err(err) log.Fatalf("Service cannot start: %v", err) } fmt.Println("Service started, listening http://" + globalConfig.Host + ":" + globalConfig.Port) if err1 := http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Host == "127.0.0.1:"+globalConfig.Port && strings.Contains(r.URL.Path, "/cert") { w.Header().Set("Content-Type", "application/x-x509-ca-data") w.Header().Set("Content-Disposition", "attachment;filename=res-downloader-public.crt") w.Header().Set("Content-Transfer-Encoding", "binary") w.Header().Set("Content-Length", fmt.Sprintf("%d", len(appOnce.PublicCrt))) w.WriteHeader(http.StatusOK) _, err = io.Copy(w, io.NopCloser(bytes.NewReader(appOnce.PublicCrt))) } else { proxyOnce.Proxy.ServeHTTP(w, r) // 代理 } })); err1 != nil { globalLogger.Err(err1) fmt.Printf("Service startup exception: %v", err1) } } func (h *HttpServer) preview(w http.ResponseWriter, r *http.Request) { realURL := r.URL.Query().Get("url") if realURL == "" { http.Error(w, "Missing 'url' parameter", http.StatusBadRequest) return } realURL, _ = url.QueryUnescape(realURL) parsedURL, err := url.Parse(realURL) if err != nil { http.Error(w, "Invalid URL", http.StatusBadRequest) return } request, err := http.NewRequest("GET", parsedURL.String(), nil) if err != nil { http.Error(w, "Failed to fetch the resource", http.StatusInternalServerError) return } if rangeHeader := r.Header.Get("Range"); rangeHeader != "" { request.Header.Set("Range", rangeHeader) } //request.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36") //request.Header.Set("Referer", parsedURL.Scheme+"://"+parsedURL.Host+"/") resp, err := http.DefaultClient.Do(request) if err != nil { http.Error(w, "Failed to fetch the resource", http.StatusInternalServerError) return } defer resp.Body.Close() w.Header().Set("Content-Type", resp.Header.Get("Content-Type")) w.WriteHeader(resp.StatusCode) if contentRange := resp.Header.Get("Content-Range"); contentRange != "" { w.Header().Set("Content-Range", contentRange) } _, err = io.Copy(w, resp.Body) if err != nil { http.Error(w, "Failed to serve the resource", http.StatusInternalServerError) } return } func (h *HttpServer) send(t string, data interface{}) { jsonData, err := json.Marshal(map[string]interface{}{ "type": t, "data": data, }) if err != nil { fmt.Println("Error converting map to JSON:", err) return } runtime.EventsEmit(appOnce.ctx, "event", string(jsonData)) } func (h *HttpServer) writeJson(w http.ResponseWriter, data ResponseData) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) err := json.NewEncoder(w).Encode(data) if err != nil { globalLogger.Err(err) } } func (h *HttpServer) error(w http.ResponseWriter, args ...interface{}) { message := "ok" var data interface{} if len(args) > 0 { message = args[0].(string) } if len(args) > 1 { data = args[1] } h.writeJson(w, ResponseData{ Code: 0, Message: message, Data: data, }) } func (h *HttpServer) success(w http.ResponseWriter, args ...interface{}) { message := "ok" var data interface{} if len(args) > 0 { data = args[0] } if len(args) > 1 { message = args[1].(string) } h.writeJson(w, ResponseData{ Code: 1, Message: message, Data: data, }) } func (h *HttpServer) openDirectoryDialog(w http.ResponseWriter, r *http.Request) { folder, err := runtime.OpenDirectoryDialog(appOnce.ctx, runtime.OpenDialogOptions{ DefaultDirectory: "", Title: "Select a folder", }) if err != nil { h.error(w, err.Error()) return } h.success(w, respData{ "folder": folder, }) } func (h *HttpServer) openFileDialog(w http.ResponseWriter, r *http.Request) { filePath, err := runtime.OpenFileDialog(appOnce.ctx, runtime.OpenDialogOptions{ Filters: []runtime.FileFilter{ { DisplayName: "Videos (*.mov;*.mp4)", Pattern: "*.mp4", }, }, Title: "Select a file", }) if err != nil { h.error(w, err.Error()) return } h.success(w, respData{ "file": filePath, }) } func (h *HttpServer) openFolder(w http.ResponseWriter, r *http.Request) { var data struct { FilePath string `json:"filePath"` } err := json.NewDecoder(r.Body).Decode(&data) if err == nil && data.FilePath == "" { return } filePath := data.FilePath var cmd *exec.Cmd switch sysRuntime.GOOS { case "darwin": cmd = exec.Command("open", "-R", filePath) case "windows": cmd = exec.Command("explorer", "/select,", filePath) case "linux": cmd = exec.Command("nautilus", filePath) if err := cmd.Start(); err != nil { cmd = exec.Command("thunar", filePath) if err := cmd.Start(); err != nil { cmd = exec.Command("dolphin", filePath) if err := cmd.Start(); err != nil { cmd = exec.Command("pcmanfm", filePath) if err := cmd.Start(); err != nil { globalLogger.Err(err) h.error(w, err.Error()) return } } } } default: h.error(w, "unsupported platform") return } err = cmd.Start() if err != nil { globalLogger.Err(err) h.error(w, err.Error()) return } h.success(w) } func (h *HttpServer) install(w http.ResponseWriter, r *http.Request) { if appOnce.isInstall() { h.success(w, respData{ "isPass": systemOnce.Password == "", }) return } out, err := appOnce.installCert() if err != nil { h.error(w, err.Error()+"\n"+out, respData{ "isPass": systemOnce.Password == "", }) return } h.success(w, respData{ "isPass": systemOnce.Password == "", }) } func (h *HttpServer) setSystemPassword(w http.ResponseWriter, r *http.Request) { var data struct { Password string `json:"password"` IsCache bool `json:"isCache"` } err := json.NewDecoder(r.Body).Decode(&data) if err != nil { h.error(w, err.Error()) return } systemOnce.SetPassword(data.Password, data.IsCache) h.success(w) } func (h *HttpServer) openSystemProxy(w http.ResponseWriter, r *http.Request) { err := appOnce.OpenSystemProxy() if err != nil { h.error(w, err.Error(), respData{ "value": appOnce.IsProxy, }) return } h.success(w, respData{ "value": appOnce.IsProxy, }) } func (h *HttpServer) unsetSystemProxy(w http.ResponseWriter, r *http.Request) { err := appOnce.UnsetSystemProxy() if err != nil { h.error(w, err.Error(), respData{ "value": appOnce.IsProxy, }) return } h.success(w, respData{ "value": appOnce.IsProxy, }) } func (h *HttpServer) isProxy(w http.ResponseWriter, r *http.Request) { h.success(w, respData{ "value": appOnce.IsProxy, }) } func (h *HttpServer) appInfo(w http.ResponseWriter, r *http.Request) { h.success(w, appOnce) } func (h *HttpServer) getConfig(w http.ResponseWriter, r *http.Request) { h.success(w, globalConfig) } func (h *HttpServer) setConfig(w http.ResponseWriter, r *http.Request) { var data Config if err := json.NewDecoder(r.Body).Decode(&data); err != nil { h.error(w, err.Error()) return } globalConfig.setConfig(data) h.success(w) } func (h *HttpServer) setType(w http.ResponseWriter, r *http.Request) { var data struct { Type string `json:"type"` } err := json.NewDecoder(r.Body).Decode(&data) if err == nil { if data.Type != "" { resourceOnce.setResType(strings.Split(data.Type, ",")) } else { resourceOnce.setResType([]string{}) } } h.success(w) } func (h *HttpServer) clear(w http.ResponseWriter, r *http.Request) { resourceOnce.clear() h.success(w) } func (h *HttpServer) delete(w http.ResponseWriter, r *http.Request) { var data struct { Sign string `json:"sign"` } err := json.NewDecoder(r.Body).Decode(&data) if err == nil && data.Sign != "" { resourceOnce.delete(data.Sign) } h.success(w) } func (h *HttpServer) download(w http.ResponseWriter, r *http.Request) { var data struct { MediaInfo DecodeStr string `json:"decodeStr"` } if err := json.NewDecoder(r.Body).Decode(&data); err != nil { h.error(w, err.Error()) return } resourceOnce.download(data.MediaInfo, data.DecodeStr) h.success(w) } func (h *HttpServer) wxFileDecode(w http.ResponseWriter, r *http.Request) { var data struct { MediaInfo Filename string `json:"filename"` DecodeStr string `json:"decodeStr"` } if err := json.NewDecoder(r.Body).Decode(&data); err != nil { h.error(w, err.Error()) return } savePath, err := resourceOnce.wxFileDecode(data.MediaInfo, data.Filename, data.DecodeStr) if err != nil { h.error(w, err.Error()) return } h.success(w, respData{ "save_path": savePath, }) } func (h *HttpServer) batchImport(w http.ResponseWriter, r *http.Request) { var data struct { Content string `json:"content"` } if err := json.NewDecoder(r.Body).Decode(&data); err != nil { h.error(w, err.Error()) return } fileName := filepath.Join(globalConfig.SaveDirectory, "res-downloader-"+GetCurrentDateTimeFormatted()+".txt") err := os.WriteFile(fileName, []byte(data.Content), 0644) if err != nil { h.error(w, err.Error()) return } h.success(w, respData{ "file_name": fileName, }) }