From da5bea9f5c6feb634c01c893e7a76fa123f45787 Mon Sep 17 00:00:00 2001 From: godo Date: Sat, 4 Jan 2025 14:05:34 +0800 Subject: [PATCH] change frp --- docs/Faq.md | 2 + .../src/components/setting/LocalProxy.vue | 60 ++++- godo/cmd/main.go | 11 + godo/model/init.go | 1 + godo/model/local_proxy.go | 19 ++ godo/{sys => proxy}/frpc.go | 2 +- godo/proxy/local.go | 242 ++++++++++++++++++ 7 files changed, 323 insertions(+), 14 deletions(-) rename godo/{sys => proxy}/frpc.go (99%) create mode 100644 godo/proxy/local.go diff --git a/docs/Faq.md b/docs/Faq.md index b420d47..2b34124 100644 --- a/docs/Faq.md +++ b/docs/Faq.md @@ -30,6 +30,8 @@ daemon.json文件配置: } ``` +systemctl daemon-reload +systemctl restart docker ### linux版本如何做守护进程 - 下载web版 diff --git a/frontend/src/components/setting/LocalProxy.vue b/frontend/src/components/setting/LocalProxy.vue index e53631e..36bffd5 100644 --- a/frontend/src/components/setting/LocalProxy.vue +++ b/frontend/src/components/setting/LocalProxy.vue @@ -2,29 +2,63 @@ import { Plus } from '@element-plus/icons-vue' import { ref, computed } from "vue"; import { OpenDirDialog } from "@/util/goutil"; +import { getSystemConfig } from '@/system/config'; +import { notifySuccess,notifyError } from '@/util/msg'; interface ProxyItem { id: number; port: string; proxyType: string; domain: string; } -const localKey = "godoos_local_proxy" -const getProxies = (): ProxyItem[] => { - const proxies = localStorage.getItem(localKey); - return proxies ? JSON.parse(proxies) : []; -}; +const config = getSystemConfig(); +const proxies = ref([]); +const total = ref(0) -const saveProxies = (proxies: ProxyItem[]) => { - localStorage.setItem(localKey, JSON.stringify(proxies)); +const fetchProxies = async () => { + try { + const response = await fetch(config.apiUrl + "/api/v1/proxy/list"); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + if (data.proxies && Array.isArray(data.proxies)) { + proxies.value = data.proxies; + total.value = data.total; + } else { + console.error('Invalid data format:', data); + } + } catch (error) { + console.error('Failed to fetch proxies:', error); + } +}; +onMounted(async () => { + await fetchProxies(); +}); +const saveProxies = (data: ProxyItem) => { + //localStorage.setItem(localKey, JSON.stringify(proxies)); + fetch(config.apiUrl + '/api/proxy/add', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }).then(res => { + if (!res.ok) { + notifyError('保存代理失败'); + }else{ + notifySuccess('保存代理成功'); + } + }); }; -const proxies = ref(getProxies()); -const proxyData = ref({ +// const proxies = ref(getProxies()); +const proxyInit = { id: Date.now(), port: "", proxyType: "http", domain: "", -}); +} +const proxyData = ref(proxyInit); const types = ref([ { label: 'HTTP', value: 'http' }, { label: 'Udp', value: 'udp' }, @@ -37,9 +71,9 @@ const pwdRef = ref(null); const addProxy = () => { if (pwdRef.value.validate()) { proxies.value.push({ ...proxyData.value }); - saveProxies(proxies.value); + saveProxies(proxyData.value); proxyDialogShow.value = false; - proxyData.value = { id: Date.now(), port: "", domain: "", proxyType: "http" }; + proxyData.value = proxyInit; } }; @@ -56,7 +90,7 @@ const updateProxy = () => { proxies.value[index] = { ...proxyData.value }; saveProxies(proxies.value); proxyDialogShow.value = false; - proxyData.value = { id: Date.now(), port: "", domain: "", proxyType: "http" }; + proxyData.value = proxyInit; isEditing.value = false; } } diff --git a/godo/cmd/main.go b/godo/cmd/main.go index 40b3c48..dd1caf4 100644 --- a/godo/cmd/main.go +++ b/godo/cmd/main.go @@ -25,6 +25,8 @@ import ( "godo/files" "godo/libs" "godo/localchat" + db "godo/model" + "godo/proxy" "godo/store" "godo/sys" "godo/webdav" @@ -46,6 +48,8 @@ func OsStart() { log.Fatalf("InitOsSystem error: %v", err) return } + db.InitDB() + proxy.InitProxyHandlers() webdav.InitWebdav() router := mux.NewRouter() router.Use(recoverMiddleware) @@ -149,6 +153,13 @@ func OsStart() { ieRouter.HandleFunc("/back", store.HandleBack).Methods(http.MethodGet) ieRouter.HandleFunc("/forward", store.HandleForward).Methods(http.MethodGet) ieRouter.HandleFunc("/refresh", store.HandleRefresh).Methods(http.MethodGet) + //注册代理路由 + proxyRouter := router.PathPrefix("/proxy").Subrouter() + proxyRouter.HandleFunc("/local/create", proxy.CreateLocalProxyHandler).Methods(http.MethodPost) + proxyRouter.HandleFunc("/local/delete", proxy.DeleteLocalProxyHandler).Methods(http.MethodGet) + proxyRouter.HandleFunc("/local/get", proxy.GetLocalProxyHandler).Methods(http.MethodGet) + proxyRouter.HandleFunc("/local/list", proxy.GetLocalProxiesHandler).Methods(http.MethodGet) + proxyRouter.HandleFunc("/local/update", proxy.UpdateLocalProxyHandler).Methods(http.MethodPost) // 注册根路径的处理函数 distFS, _ := fs.Sub(deps.Frontendassets, "dist") diff --git a/godo/model/init.go b/godo/model/init.go index de10475..75347ee 100644 --- a/godo/model/init.go +++ b/godo/model/init.go @@ -21,6 +21,7 @@ func InitDB() { db.AutoMigrate(&SysDisk{}) // 初始化 SysDisk 记录 initSysDisk(db) + db.AutoMigrate(&LocalProxy{}) db.AutoMigrate(&SysUser{}) db.AutoMigrate(&ClientUser{}) db.AutoMigrate(&ServerUser{}) diff --git a/godo/model/local_proxy.go b/godo/model/local_proxy.go index 48658aa..44001ed 100644 --- a/godo/model/local_proxy.go +++ b/godo/model/local_proxy.go @@ -12,3 +12,22 @@ type LocalProxy struct { func (*LocalProxy) TableName() string { return "local_proxy" } + +// GetLocalProxies 获取所有 LocalProxy,支持分页 +func GetLocalProxies(page, limit int) ([]LocalProxy, int64, error) { + var proxies []LocalProxy + var total int64 + + // 先计算总数 + if err := Db.Model(&LocalProxy{}).Count(&total).Error; err != nil { + return nil, 0, err + } + + // 再进行分页查询 + offset := (page - 1) * limit + if err := Db.Limit(limit).Offset(offset).Find(&proxies).Error; err != nil { + return nil, 0, err + } + + return proxies, total, nil +} diff --git a/godo/sys/frpc.go b/godo/proxy/frpc.go similarity index 99% rename from godo/sys/frpc.go rename to godo/proxy/frpc.go index b1add0e..2c5083f 100644 --- a/godo/sys/frpc.go +++ b/godo/proxy/frpc.go @@ -1,4 +1,4 @@ -package sys +package proxy import ( "fmt" diff --git a/godo/proxy/local.go b/godo/proxy/local.go new file mode 100644 index 0000000..d3446e4 --- /dev/null +++ b/godo/proxy/local.go @@ -0,0 +1,242 @@ +package proxy + +import ( + "encoding/json" + "fmt" + "godo/model" + "net" + "net/http" + "net/http/httputil" + "net/url" + "strconv" +) + +// 创建 LocalProxy 的 HTTP 处理函数 +func CreateLocalProxyHandler(w http.ResponseWriter, r *http.Request) { + + var lp model.LocalProxy + err := json.NewDecoder(r.Body).Decode(&lp) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + err = model.Db.Create(&lp).Error + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(lp) + +} + +// GetLocalProxiesHandler 获取所有 LocalProxy 的 HTTP 处理函数 +func GetLocalProxiesHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // 获取查询参数 page 和 limit + pageStr := r.URL.Query().Get("page") + limitStr := r.URL.Query().Get("limit") + + page, err := strconv.Atoi(pageStr) + if err != nil || page < 1 { + page = 1 + } + + limit, err := strconv.Atoi(limitStr) + if err != nil || limit < 1 { + limit = 10 + } + + // 定义响应结构体 + type ProxyResponse struct { + Proxies []model.LocalProxy `json:"proxies"` + Total int64 `json:"total"` + } + + // 修改处理函数 + proxies, total, err := model.GetLocalProxies(page, limit) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + response := ProxyResponse{ + Proxies: proxies, + Total: total, + } + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + return + } +} + +// GetLocalProxyHandler 获取单个 LocalProxy 的 HTTP 处理函数 +func GetLocalProxyHandler(w http.ResponseWriter, r *http.Request) { + idStr := r.URL.Query().Get("id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "Invalid ID", http.StatusBadRequest) + return + } + var proxy model.LocalProxy + err = model.Db.First(&proxy, uint(id)).Error + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(proxy) +} + +// UpdateLocalProxyHandler 更新 LocalProxy 的 HTTP 处理函数 +func UpdateLocalProxyHandler(w http.ResponseWriter, r *http.Request) { + + var lp model.LocalProxy + err := json.NewDecoder(r.Body).Decode(&lp) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + err = model.Db.Model(&model.LocalProxy{}).Where("id = ?", lp.ID).Updates(lp).Error + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(lp) +} + +// DeleteLocalProxyHandler 删除 LocalProxy 的 HTTP 处理函数 +func DeleteLocalProxyHandler(w http.ResponseWriter, r *http.Request) { + idStr := r.URL.Query().Get("id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "Invalid ID", http.StatusBadRequest) + return + } + + err = model.Db.Delete(&model.LocalProxy{}, uint(id)).Error + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// 初始化代理处理函数 +func InitProxyHandlers() { + proxies, _, err := model.GetLocalProxies(1, 1000) // 获取所有代理配置 + if err != nil { + fmt.Println("Failed to get local proxies:", err) + return + } + + for _, proxy := range proxies { + switch proxy.ProxyType { + case "http": + go func(p model.LocalProxy) { + httpProxyHandler(p) + }(proxy) + case "udp": + // UDP 转发的处理逻辑 + go func(p model.LocalProxy) { + udpProxyHandler(p) + }(proxy) + case "file": + http.Handle(fmt.Sprintf("/file/%d/", proxy.Port), http.StripPrefix(fmt.Sprintf("/file/%d/", proxy.Port), http.FileServer(http.Dir(proxy.Domain)))) + fmt.Printf("Setting up file server for port %d at %s\n", proxy.Port, proxy.Domain) + default: + fmt.Printf("Unknown proxy type: %s\n", proxy.ProxyType) + } + } +} + +// HTTP 代理处理函数 +func httpProxyHandler(proxy model.LocalProxy) { + remote, err := url.Parse(proxy.Domain) + if err != nil { + fmt.Printf("Failed to parse remote URL for port %d: %v\n", proxy.Port, err) + return + } + + reverseProxy := httputil.NewSingleHostReverseProxy(remote) + + // 启动 HTTP 服务器并监听指定端口 + server := &http.Server{ + Addr: fmt.Sprintf(":%d", proxy.Port), + Handler: reverseProxy, + } + + fmt.Printf("Starting HTTP proxy on port %d and forwarding to %s:%d\n", proxy.Port, proxy.Domain, proxy.Port) + if err := server.ListenAndServe(); err != nil { + fmt.Printf("Failed to start HTTP proxy on port %d: %v\n", proxy.Port, err) + } +} + +// UDP 代理处理函数 +func udpProxyHandler(proxy model.LocalProxy) { + + localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", proxy.Port)) + if err != nil { + fmt.Printf("Failed to resolve local UDP address for port %d: %v\n", proxy.Port, err) + return + } + + remoteAddr, err := net.ResolveUDPAddr("udp", proxy.Domain) + if err != nil { + fmt.Printf("Failed to resolve remote UDP address for port %d: %v\n", proxy.Port, err) + return + } + + conn, err := net.ListenUDP("udp", localAddr) + if err != nil { + fmt.Printf("Failed to listen on UDP port %d: %v\n", proxy.Port, err) + return + } + defer conn.Close() + + buffer := make([]byte, 1024) + for { + n, addr, err := conn.ReadFromUDP(buffer) + if err != nil { + fmt.Printf("Failed to read from UDP: %v\n", err) + continue + } + + remoteConn, err := net.DialUDP("udp", nil, remoteAddr) + if err != nil { + fmt.Printf("Failed to dial remote UDP: %v\n", err) + continue + } + + _, err = remoteConn.Write(buffer[:n]) + if err != nil { + fmt.Printf("Failed to write to remote UDP: %v\n", err) + continue + } + + // 读取远程服务器的响应并转发回客户端 + n, err = remoteConn.Read(buffer) + if err != nil { + fmt.Printf("Failed to read from remote UDP: %v\n", err) + continue + } + + _, err = conn.WriteToUDP(buffer[:n], addr) + if err != nil { + fmt.Printf("Failed to write to client UDP: %v\n", err) + continue + } + } +}