mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 19:45:13 +08:00
Delete .github/diy/packages/sing-box/patches/002-support-clash-proxy-providers.patch
This commit is contained in:
1 parent
700d0d7e02
commit
17c94aacbb
1 file changed
-403
@@ -1,403 +0,0 @@
|
|||||||
diff --git a/experimental/clashapi/provider.go b/experimental/clashapi/provider.go
|
|
||||||
index 352b289..ef07e6d 100644
|
|
||||||
--- a/experimental/clashapi/provider.go
|
|
||||||
+++ b/experimental/clashapi/provider.go
|
|
||||||
@@ -3,43 +3,65 @@ package clashapi
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
+ "os/exec"
|
|
||||||
+ "regexp"
|
|
||||||
+
|
|
||||||
+ "github.com/sagernet/sing-box/option"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"github.com/go-chi/render"
|
|
||||||
)
|
|
||||||
|
|
||||||
-func proxyProviderRouter() http.Handler {
|
|
||||||
+func proxyProviderRouter(server *Server) http.Handler {
|
|
||||||
r := chi.NewRouter()
|
|
||||||
- r.Get("/", getProviders)
|
|
||||||
+ r.Get("/", getProviders(server))
|
|
||||||
|
|
||||||
r.Route("/{name}", func(r chi.Router) {
|
|
||||||
- r.Use(parseProviderName, findProviderByName)
|
|
||||||
- r.Get("/", getProvider)
|
|
||||||
+ r.Use(parseProviderName, findProviderByName(server))
|
|
||||||
+ r.Get("/", getProvider(server))
|
|
||||||
r.Put("/", updateProvider)
|
|
||||||
r.Get("/healthcheck", healthCheckProvider)
|
|
||||||
})
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
-func getProviders(w http.ResponseWriter, r *http.Request) {
|
|
||||||
- render.JSON(w, r, render.M{
|
|
||||||
- "providers": render.M{},
|
|
||||||
- })
|
|
||||||
+func getProviders(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ providers := render.M{}
|
|
||||||
+ for _, provider := range server.proxyProviders {
|
|
||||||
+ if provider.Name == "" {
|
|
||||||
+ continue
|
|
||||||
+ }
|
|
||||||
+ providers[provider.Name] = proxyProviderInfo(server, provider)
|
|
||||||
+ }
|
|
||||||
+ render.JSON(w, r, render.M{
|
|
||||||
+ "providers": providers,
|
|
||||||
+ })
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
-func getProvider(w http.ResponseWriter, r *http.Request) {
|
|
||||||
- /*provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
|
|
||||||
- render.JSON(w, r, provider)*/
|
|
||||||
- render.NoContent(w, r)
|
|
||||||
+func getProvider(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ provider := r.Context().Value(CtxKeyProvider).(option.ClashProxyProviderOptions)
|
|
||||||
+ render.JSON(w, r, proxyProviderInfo(server, provider))
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateProvider(w http.ResponseWriter, r *http.Request) {
|
|
||||||
- /*provider := r.Context().Value(CtxKeyProvider).(provider.ProxyProvider)
|
|
||||||
- if err := provider.Update(); err != nil {
|
|
||||||
+ provider := r.Context().Value(CtxKeyProvider).(option.ClashProxyProviderOptions)
|
|
||||||
+ if !regexp.MustCompile(`^[0-9a-f]{32}$`).MatchString(provider.UpdateID) {
|
|
||||||
+ render.Status(r, http.StatusServiceUnavailable)
|
|
||||||
+ render.JSON(w, r, newError("Provider update is unavailable"))
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ command := exec.Command("/bin/sh", "/etc/homeproxy/scripts/update_provider.sh", provider.UpdateID)
|
|
||||||
+ if err := command.Start(); err != nil {
|
|
||||||
render.Status(r, http.StatusServiceUnavailable)
|
|
||||||
render.JSON(w, r, newError(err.Error()))
|
|
||||||
return
|
|
||||||
- }*/
|
|
||||||
+ }
|
|
||||||
+ _ = command.Process.Release()
|
|
||||||
render.NoContent(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -57,18 +79,58 @@ func parseProviderName(next http.Handler) http.Handler {
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
-func findProviderByName(next http.Handler) http.Handler {
|
|
||||||
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
- /*name := r.Context().Value(CtxKeyProviderName).(string)
|
|
||||||
- providers := tunnel.ProxyProviders()
|
|
||||||
- provider, exist := providers[name]
|
|
||||||
- if !exist {*/
|
|
||||||
- render.Status(r, http.StatusNotFound)
|
|
||||||
- render.JSON(w, r, ErrNotFound)
|
|
||||||
- //return
|
|
||||||
- //}
|
|
||||||
+func findProviderByName(server *Server) func(next http.Handler) http.Handler {
|
|
||||||
+ return func(next http.Handler) http.Handler {
|
|
||||||
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ name := r.Context().Value(CtxKeyProviderName).(string)
|
|
||||||
+ for _, provider := range server.proxyProviders {
|
|
||||||
+ if provider.Name == name {
|
|
||||||
+ ctx := context.WithValue(r.Context(), CtxKeyProvider, provider)
|
|
||||||
+ next.ServeHTTP(w, r.WithContext(ctx))
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ render.Status(r, http.StatusNotFound)
|
|
||||||
+ render.JSON(w, r, ErrNotFound)
|
|
||||||
+ })
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
|
|
||||||
- // ctx := context.WithValue(r.Context(), CtxKeyProvider, provider)
|
|
||||||
- // next.ServeHTTP(w, r.WithContext(ctx))
|
|
||||||
- })
|
|
||||||
+func proxyProviderInfo(server *Server, provider option.ClashProxyProviderOptions) render.M {
|
|
||||||
+ providerType := provider.Type
|
|
||||||
+ if providerType == "" {
|
|
||||||
+ providerType = "Proxy"
|
|
||||||
+ }
|
|
||||||
+ vehicleType := provider.VehicleType
|
|
||||||
+ if vehicleType == "" {
|
|
||||||
+ vehicleType = "HTTP"
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ proxies := make([]any, 0, len(provider.Proxies))
|
|
||||||
+ for _, proxyName := range provider.Proxies {
|
|
||||||
+ proxy, exists := lookupProxyByName(server, proxyName)
|
|
||||||
+ if !exists {
|
|
||||||
+ continue
|
|
||||||
+ }
|
|
||||||
+ proxies = append(proxies, proxyInfo(server, proxy))
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ info := render.M{
|
|
||||||
+ "name": provider.Name,
|
|
||||||
+ "type": providerType,
|
|
||||||
+ "vehicleType": vehicleType,
|
|
||||||
+ "proxies": proxies,
|
|
||||||
+ }
|
|
||||||
+ if provider.UpdatedAt != "" {
|
|
||||||
+ info["updatedAt"] = provider.UpdatedAt
|
|
||||||
+ }
|
|
||||||
+ if provider.SubscriptionInfo != nil {
|
|
||||||
+ info["subscriptionInfo"] = render.M{
|
|
||||||
+ "Upload": provider.SubscriptionInfo.Upload,
|
|
||||||
+ "Download": provider.SubscriptionInfo.Download,
|
|
||||||
+ "Total": provider.SubscriptionInfo.Total,
|
|
||||||
+ "Expire": provider.SubscriptionInfo.Expire,
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return info
|
|
||||||
}
|
|
||||||
diff --git a/experimental/clashapi/proxies.go b/experimental/clashapi/proxies.go
|
|
||||||
index ef88ff3..1f7d14d 100644
|
|
||||||
--- a/experimental/clashapi/proxies.go
|
|
||||||
+++ b/experimental/clashapi/proxies.go
|
|
||||||
@@ -21,6 +21,50 @@ import (
|
|
||||||
"github.com/go-chi/render"
|
|
||||||
)
|
|
||||||
|
|
||||||
+func proxyDisplayName(tag string) string {
|
|
||||||
+ switch tag {
|
|
||||||
+ case "GLOBAL":
|
|
||||||
+ return "GLOBAL"
|
|
||||||
+ case "main-out":
|
|
||||||
+ return "主代理"
|
|
||||||
+ case "main-udp-out":
|
|
||||||
+ return "UDP 主代理"
|
|
||||||
+ case "direct-out":
|
|
||||||
+ return "直连"
|
|
||||||
+ case "block-out":
|
|
||||||
+ return "拦截"
|
|
||||||
+ default:
|
|
||||||
+ return tag
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+func lookupProxyByName(server *Server, name string) (adapter.Outbound, bool) {
|
|
||||||
+ proxy, exist := server.outbound.Outbound(name)
|
|
||||||
+ if exist {
|
|
||||||
+ return proxy, true
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for _, detour := range server.outbound.Outbounds() {
|
|
||||||
+ if proxyDisplayName(detour.Tag()) == name {
|
|
||||||
+ return detour, true
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for _, endpoint := range server.endpoint.Endpoints() {
|
|
||||||
+ if proxyDisplayName(endpoint.Tag()) == name {
|
|
||||||
+ return endpoint, true
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return nil, false
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+func proxyDisplayNames(tags []string) []string {
|
|
||||||
+ return common.Map(tags, func(tag string) string {
|
|
||||||
+ return proxyDisplayName(tag)
|
|
||||||
+ })
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
func proxyRouter(server *Server, router adapter.Router) http.Handler {
|
|
||||||
r := chi.NewRouter()
|
|
||||||
r.Get("/", getProxies(server))
|
|
||||||
@@ -29,7 +73,7 @@ func proxyRouter(server *Server, router adapter.Router) http.Handler {
|
|
||||||
r.Use(parseProxyName, findProxyByName(server))
|
|
||||||
r.Get("/", getProxy(server))
|
|
||||||
r.Get("/delay", getProxyDelay(server))
|
|
||||||
- r.Put("/", updateProxy)
|
|
||||||
+ r.Put("/", updateProxy(server))
|
|
||||||
})
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
@@ -46,7 +90,7 @@ func findProxyByName(server *Server) func(next http.Handler) http.Handler {
|
|
||||||
return func(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
name := r.Context().Value(CtxKeyProxyName).(string)
|
|
||||||
- proxy, exist := server.outbound.Outbound(name)
|
|
||||||
+ proxy, exist := lookupProxyByName(server, name)
|
|
||||||
if !exist {
|
|
||||||
render.Status(r, http.StatusNotFound)
|
|
||||||
render.JSON(w, r, ErrNotFound)
|
|
||||||
@@ -68,7 +112,7 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
|
|
||||||
clashType = C.ProxyDisplayName(detour.Type())
|
|
||||||
}
|
|
||||||
info.Put("type", clashType)
|
|
||||||
- info.Put("name", detour.Tag())
|
|
||||||
+ info.Put("name", proxyDisplayName(detour.Tag()))
|
|
||||||
info.Put("udp", common.Contains(detour.Network(), N.NetworkUDP))
|
|
||||||
delayHistory := server.urlTestHistory.LoadURLTestHistory(adapter.OutboundTag(detour))
|
|
||||||
if delayHistory != nil {
|
|
||||||
@@ -77,8 +121,8 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
|
|
||||||
info.Put("history", []*adapter.URLTestHistory{})
|
|
||||||
}
|
|
||||||
if group, isGroup := detour.(adapter.OutboundGroup); isGroup {
|
|
||||||
- info.Put("now", group.Now())
|
|
||||||
- info.Put("all", group.All())
|
|
||||||
+ info.Put("now", proxyDisplayName(group.Now()))
|
|
||||||
+ info.Put("all", proxyDisplayNames(group.All()))
|
|
||||||
}
|
|
||||||
return &info
|
|
||||||
}
|
|
||||||
@@ -102,10 +146,10 @@ func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
case C.TypeDirect, C.TypeBlock, C.TypeDNS:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
- allProxies = append(allProxies, detour.Tag())
|
|
||||||
+ allProxies = append(allProxies, proxyDisplayName(detour.Tag()))
|
|
||||||
}
|
|
||||||
|
|
||||||
- defaultTag := server.outbound.Default().Tag()
|
|
||||||
+ defaultTag := proxyDisplayName(server.outbound.Default().Tag())
|
|
||||||
|
|
||||||
sort.SliceStable(allProxies, func(i, j int) bool {
|
|
||||||
return allProxies[i] == defaultTag
|
|
||||||
@@ -114,7 +158,7 @@ func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// fix clash dashboard
|
|
||||||
proxyMap.Put("GLOBAL", map[string]any{
|
|
||||||
"type": "Fallback",
|
|
||||||
- "name": "GLOBAL",
|
|
||||||
+ "name": proxyDisplayName("GLOBAL"),
|
|
||||||
"udp": true,
|
|
||||||
"history": []*adapter.URLTestHistory{},
|
|
||||||
"all": allProxies,
|
|
||||||
@@ -126,7 +170,7 @@ func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if detour.Tag() == "" {
|
|
||||||
tag = F.ToString(i)
|
|
||||||
} else {
|
|
||||||
- tag = detour.Tag()
|
|
||||||
+ tag = proxyDisplayName(detour.Tag())
|
|
||||||
}
|
|
||||||
proxyMap.Put(tag, proxyInfo(server, detour))
|
|
||||||
}
|
|
||||||
@@ -159,29 +203,36 @@ type UpdateProxyRequest struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
-func updateProxy(w http.ResponseWriter, r *http.Request) {
|
|
||||||
- req := UpdateProxyRequest{}
|
|
||||||
- if err := render.DecodeJSON(r.Body, &req); err != nil {
|
|
||||||
- render.Status(r, http.StatusBadRequest)
|
|
||||||
- render.JSON(w, r, ErrBadRequest)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+func updateProxy(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
+ req := UpdateProxyRequest{}
|
|
||||||
+ if err := render.DecodeJSON(r.Body, &req); err != nil {
|
|
||||||
+ render.Status(r, http.StatusBadRequest)
|
|
||||||
+ render.JSON(w, r, ErrBadRequest)
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
|
||||||
- selector, ok := proxy.(*group.Selector)
|
|
||||||
- if !ok {
|
|
||||||
- render.Status(r, http.StatusBadRequest)
|
|
||||||
- render.JSON(w, r, newError("Must be a Selector"))
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+ proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
|
||||||
+ selector, ok := proxy.(*group.Selector)
|
|
||||||
+ if !ok {
|
|
||||||
+ render.Status(r, http.StatusBadRequest)
|
|
||||||
+ render.JSON(w, r, newError("Must be a Selector"))
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- if !selector.SelectOutbound(req.Name) {
|
|
||||||
- render.Status(r, http.StatusBadRequest)
|
|
||||||
- render.JSON(w, r, newError("Selector update error: not found"))
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+ selectedName := req.Name
|
|
||||||
+ if targetProxy, exist := lookupProxyByName(server, req.Name); exist {
|
|
||||||
+ selectedName = targetProxy.Tag()
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if !selector.SelectOutbound(selectedName) {
|
|
||||||
+ render.Status(r, http.StatusBadRequest)
|
|
||||||
+ render.JSON(w, r, newError("Selector update error: not found"))
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- render.NoContent(w, r)
|
|
||||||
+ render.NoContent(w, r)
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProxyDelay(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go
|
|
||||||
index b9222ad5440..d4fd9dd3db1 100644
|
|
||||||
--- a/experimental/clashapi/server.go
|
|
||||||
+++ b/experimental/clashapi/server.go
|
|
||||||
@@ -57,6 +57,7 @@ type Server struct {
|
|
||||||
externalUI string
|
|
||||||
externalUIDownloadURL string
|
|
||||||
externalUIDownloadDetour string
|
|
||||||
+ proxyProviders []option.ClashProxyProviderOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewServer(ctx context.Context, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.LifecycleService, error) {
|
|
||||||
@@ -92,6 +93,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
|
||||||
externalController: options.ExternalController != "",
|
|
||||||
externalUIDownloadURL: options.ExternalUIDownloadURL,
|
|
||||||
externalUIDownloadDetour: options.ExternalUIDownloadDetour,
|
|
||||||
+ proxyProviders: options.ProxyProviders,
|
|
||||||
}
|
|
||||||
//goland:noinspection GoDeprecation
|
|
||||||
//nolint:staticcheck
|
|
||||||
@@ -120,7 +122,7 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
|
||||||
r.Mount("/proxies", proxyRouter(s, s.router))
|
|
||||||
r.Mount("/rules", ruleRouter(s.router))
|
|
||||||
r.Mount("/connections", connectionRouter(s.ctx, s.network, trafficManager))
|
|
||||||
- r.Mount("/providers/proxies", proxyProviderRouter())
|
|
||||||
+ r.Mount("/providers/proxies", proxyProviderRouter(s))
|
|
||||||
r.Mount("/providers/rules", ruleProviderRouter())
|
|
||||||
r.Mount("/script", scriptRouter())
|
|
||||||
r.Mount("/profile", profileRouter())
|
|
||||||
diff --git a/option/experimental.go b/option/experimental.go
|
|
||||||
index bf144ad4452..89f303a7b26 100644
|
|
||||||
--- a/option/experimental.go
|
|
||||||
+++ b/option/experimental.go
|
|
||||||
@@ -34,6 +34,7 @@ type ClashAPIOptions struct {
|
|
||||||
ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty" reference:"outbound"`
|
|
||||||
Secret string `json:"secret,omitempty"`
|
|
||||||
DefaultMode string `json:"default_mode,omitempty"`
|
|
||||||
+ ProxyProviders []ClashProxyProviderOptions `json:"proxy_providers,omitempty"`
|
|
||||||
AccessControlAllowOrigin badoption.Listable[string] `json:"access_control_allow_origin,omitempty"`
|
|
||||||
AccessControlAllowPrivateNetwork bool `json:"access_control_allow_private_network,omitempty"`
|
|
||||||
|
|
||||||
@@ -49,6 +50,23 @@ type ClashAPIOptions struct {
|
|
||||||
StoreFakeIP bool `json:"store_fakeip,omitempty" schema:"omit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
+type ClashProxyProviderOptions struct {
|
|
||||||
+ Name string `json:"name,omitempty"`
|
|
||||||
+ Type string `json:"type,omitempty"`
|
|
||||||
+ VehicleType string `json:"vehicle_type,omitempty"`
|
|
||||||
+ Proxies []string `json:"proxies,omitempty"`
|
|
||||||
+ UpdatedAt string `json:"updated_at,omitempty"`
|
|
||||||
+ UpdateID string `json:"update_id,omitempty"`
|
|
||||||
+ SubscriptionInfo *ClashProxyProviderSubscriptionInfo `json:"subscription_info,omitempty"`
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+type ClashProxyProviderSubscriptionInfo struct {
|
|
||||||
+ Upload uint64 `json:"upload,omitempty"`
|
|
||||||
+ Download uint64 `json:"download,omitempty"`
|
|
||||||
+ Total uint64 `json:"total,omitempty"`
|
|
||||||
+ Expire int64 `json:"expire,omitempty"`
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
type V2RayAPIOptions struct {
|
|
||||||
Listen string `json:"listen,omitempty"`
|
|
||||||
Stats *V2RayStatsServiceOptions `json:"stats,omitempty"`
|
|
||||||
Reference in new issue
Block a user