x
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
.PHONY: build
|
||||
|
||||
BINARY_NAME=sillyGirl
|
||||
|
||||
build:
|
||||
GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}-darwin -ldflags "-s -w" main.go
|
||||
GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}-linux -ldflags "-s -w" main.go
|
||||
|
||||
|
||||
release:
|
||||
GOARCH=amd64 GOOS=darwin garble build -o ${BINARY_NAME}-darwin -a -ldflags "-s -w" -trimpath -buildmode=pie main.go
|
||||
GOARCH=amd64 GOOS=linux garble build -o ${BINARY_NAME}-linux -a -ldflags "-s -w" -trimpath -buildmode=pie main.go
|
||||
|
||||
pre-release:
|
||||
go install mvdan.cc/garble@latest
|
||||
run:
|
||||
go build -o ${BINARY_NAME} main.go
|
||||
./${BINARY_NAME}
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm ${BINARY_NAME}-darwin
|
||||
rm ${BINARY_NAME}-linux
|
||||
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func getJS(user, pass, title string) string {
|
||||
baseURL := "http://aut.zhelee.cn/plugin/download"
|
||||
queryParams := url.Values{}
|
||||
queryParams.Set("title", title)
|
||||
queryParams.Set("username", user)
|
||||
queryParams.Set("password", pass)
|
||||
queryParams.Set("version", "1")
|
||||
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
u.RawQuery = queryParams.Encode()
|
||||
|
||||
urlStr := u.String()
|
||||
method := "POST"
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, urlStr, nil)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
// fmt.Println(string(body))
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func main() {
|
||||
user := "test1234"
|
||||
pass := "test1234"
|
||||
title := "hook"
|
||||
plaintext := getJS(user, pass, title)
|
||||
key := getKey("test1234")
|
||||
panic(key)
|
||||
decrypted, err := decrypt(string(plaintext), []byte(key))
|
||||
// 打印解密后的数据
|
||||
fmt.Println(err)
|
||||
fmt.Printf("解密后的数据:%s\n", decrypted)
|
||||
}
|
||||
|
||||
func getKey(user string) string {
|
||||
t := user + "killsillygirltodeath109times"
|
||||
if len(t) > 32 {
|
||||
return t[:32]
|
||||
}
|
||||
// if len(t) > 24 {
|
||||
// return t[:24]
|
||||
// }
|
||||
// return t[:16]
|
||||
return t[:24]
|
||||
}
|
||||
|
||||
// 使用AES-CBC模式进行解密
|
||||
func decrypt(encrypted string, key []byte) (string, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
decrypter := cipher.NewCBCDecrypter(block, iv)
|
||||
decrypted := make([]byte, len(ciphertext))
|
||||
decrypter.CryptBlocks(decrypted, ciphertext)
|
||||
return string(decrypted), nil
|
||||
}
|
||||
@@ -613,6 +613,10 @@ func (sender *CustomSender) Reply(msgs ...interface{}) (string, error) {
|
||||
push = true
|
||||
case string:
|
||||
args = append(args, item)
|
||||
default:
|
||||
if item != nil {
|
||||
args = append(args, fmt.Sprint(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(args) == 0 {
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/admin/umi.29bb0b44.js"></script>
|
||||
<script src="/admin/umi.7bcd86f8.js"></script>
|
||||
|
||||
</body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -319,6 +319,7 @@ type CarryGroup struct {
|
||||
|
||||
// CARRY API
|
||||
func init() {
|
||||
|
||||
GinApi(GET, "/api/carry/groups", RequireAuth, func(ctx *gin.Context) {
|
||||
current := utils.Int(ctx.Query("current"))
|
||||
pageSize := utils.Int(ctx.Query("pageSize"))
|
||||
@@ -364,6 +365,41 @@ func init() {
|
||||
"data": names,
|
||||
})
|
||||
})
|
||||
GinApi(GET, "/api/proxy/scripts", RequireAuth, func(ctx *gin.Context) {
|
||||
var scripts = map[string]string{}
|
||||
functions := Functions
|
||||
for _, function := range functions {
|
||||
if function.UUID != "" {
|
||||
scripts[function.UUID] = function.Title + ".js"
|
||||
}
|
||||
}
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"success": true,
|
||||
"data": scripts,
|
||||
})
|
||||
})
|
||||
var isNumeric = func(keyword string) bool {
|
||||
for _, c := range keyword {
|
||||
if c != '.' && (c < '0' || c > '9') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
GinApi(GET, "/api/proxy/rules", RequireAuth, func(ctx *gin.Context) {
|
||||
keyword := ctx.Query("keyword")
|
||||
var scripts = map[string]string{}
|
||||
scripts[keyword] = keyword
|
||||
if strings.HasSuffix(keyword, ".") && !isNumeric(keyword) {
|
||||
for _, suffix := range []string{"com", "cn"} {
|
||||
scripts[keyword+suffix] = keyword + suffix
|
||||
}
|
||||
}
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"success": true,
|
||||
"data": scripts,
|
||||
})
|
||||
})
|
||||
GinApi(GET, "/api/carry/group_selects", RequireAuth, func(ctx *gin.Context) {
|
||||
chat_id := ctx.Query("chat_id")
|
||||
platform := ctx.Query("platform")
|
||||
|
||||
+3
-3
@@ -2,9 +2,9 @@ package core
|
||||
|
||||
import cron "github.com/robfig/cron/v3"
|
||||
|
||||
var C *cron.Cron
|
||||
var CRON *cron.Cron
|
||||
|
||||
func init() {
|
||||
C = cron.New(cron.WithSeconds())
|
||||
C.Start()
|
||||
CRON = cron.New(cron.WithSeconds())
|
||||
CRON.Start()
|
||||
}
|
||||
|
||||
+1
-1
@@ -383,7 +383,7 @@ func AddCommand(cmds []*common.Function) {
|
||||
if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 {
|
||||
Cron = "0 " + Cron
|
||||
}
|
||||
cronId, err := C.AddFunc(Cron, func() {
|
||||
cronId, err := CRON.AddFunc(Cron, func() {
|
||||
cmds[j].Handle(&Faker{
|
||||
Admin: true,
|
||||
Type: plt,
|
||||
|
||||
+38
-2
@@ -3,6 +3,8 @@ package core
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
@@ -33,14 +35,43 @@ func Init() {
|
||||
sillyGirl.Set("started_at", time.Now().Format("2006-01-02 15:04:05"))
|
||||
storage.Watch(sillyGirl, "compiled_at", func(old, new, key string) *storage.Final {
|
||||
if old != new {
|
||||
var transport *http.Transport
|
||||
instance, err := GetProxyTransport("https://raw.githubusercontent.com", "", nil)
|
||||
if err != nil {
|
||||
console.Error("升级代理错误:%s", err)
|
||||
return &storage.Final{
|
||||
Error: fmt.Errorf("升级代理错误::%s", err),
|
||||
}
|
||||
}
|
||||
if instance != nil {
|
||||
defer instance.Close()
|
||||
}
|
||||
if instance != nil {
|
||||
transport = &http.Transport{
|
||||
Dial: func(string, string) (net.Conn, error) {
|
||||
return instance, nil
|
||||
},
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
}
|
||||
var client = &http.Client{}
|
||||
if transport != nil {
|
||||
client.Transport = transport
|
||||
}
|
||||
console.Debug("正在从 cdle/binary 获取版本号...")
|
||||
data, err := httplib.Get("https://raw.githubusercontent.com/cdle/binary/main/compile_time.go").Bytes()
|
||||
req, _ := http.NewRequest("GET", "https://raw.githubusercontent.com/cdle/binary/main/compile_time.go", strings.NewReader(""))
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
console.Error("获取版本号错误:%s", err)
|
||||
return &storage.Final{
|
||||
Error: fmt.Errorf("貌似网络不太行啊:%s", err),
|
||||
}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var data, _ = ioutil.ReadAll(resp.Body)
|
||||
latest_version := regexp.MustCompile(`\d{13}`).FindString(string(data))
|
||||
if latest_version <= compiled_at {
|
||||
console.Debug("当前版本 %s 已是最新,无需升级", compiled_at)
|
||||
@@ -48,12 +79,17 @@ func Init() {
|
||||
Message: fmt.Sprintf("当前版本 %s 已是最新,无需升级", compiled_at),
|
||||
}
|
||||
}
|
||||
client = &http.Client{}
|
||||
if transport != nil {
|
||||
client.Transport = transport
|
||||
}
|
||||
console.Debug("正在从 cdle/binary 获取最新版本 %s 编译文件...", latest_version)
|
||||
qurl := "https://raw.githubusercontent.com/cdle/binary/master/sillyGirl_" + runtime.GOOS + "_" + runtime.GOARCH + "_" + latest_version
|
||||
if runtime.GOOS == "windows" {
|
||||
qurl += ".exe"
|
||||
}
|
||||
resp, err := http.Get(qurl)
|
||||
req, _ = http.NewRequest("GET", qurl, strings.NewReader(""))
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
console.Error("获取最新编译文件错误:%s", err)
|
||||
return &storage.Final{
|
||||
|
||||
+8
-5
@@ -18,9 +18,12 @@ func MakeBucketObject(vm *goja.Runtime, uuid string, on_start bool, bucket stora
|
||||
})
|
||||
return rt
|
||||
})
|
||||
obj.Set("set", func(key, value interface{}) error {
|
||||
_, err := SetBucketKeyValue(bucket, key, value)
|
||||
return err
|
||||
obj.Set("set", func(key, value interface{}) interface{} {
|
||||
msg, err := SetBucketKeyValue(bucket, key, value)
|
||||
if err != nil {
|
||||
panic(Error(vm, err))
|
||||
}
|
||||
return msg
|
||||
})
|
||||
obj.Set("delete", func(key interface{}) error {
|
||||
_, err := bucket.Set(key, "")
|
||||
@@ -84,10 +87,10 @@ func JsBucket(vm *goja.Runtime, name string, uuid string, on_start bool) goja.Pr
|
||||
return vm.ToValue(result)
|
||||
},
|
||||
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
||||
result := target.Get("set").Export().(func(interface{}, interface{}) error)(
|
||||
target.Get("set").Export().(func(interface{}, interface{}) interface{})(
|
||||
property, value.Export(),
|
||||
)
|
||||
return result == nil
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+55
-20
@@ -3,18 +3,20 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
u "net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/cdle/sillyplus/utils"
|
||||
"github.com/dop251/goja"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
|
||||
func fetch(vm *goja.Runtime, uuid string, wts ...interface{}) (interface{}, error) {
|
||||
var method = "get"
|
||||
var url = ""
|
||||
var req *http.Request
|
||||
@@ -31,6 +33,7 @@ func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
|
||||
// var useproxy bool
|
||||
var timeout time.Duration = 0
|
||||
var login = false
|
||||
var instance C.Conn
|
||||
for _, wt := range wts {
|
||||
switch wt := wt.(type) {
|
||||
case string:
|
||||
@@ -79,30 +82,63 @@ func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
|
||||
case "form":
|
||||
formData = props[i].(map[string]interface{})
|
||||
case "proxy":
|
||||
var url, user, password string
|
||||
for k, v := range props[i].(map[string]interface{}) {
|
||||
if k == "url" {
|
||||
url = fmt.Sprint(v)
|
||||
}
|
||||
if k == "user" {
|
||||
user = fmt.Sprint(v)
|
||||
}
|
||||
if k == "password" {
|
||||
password = fmt.Sprint(v)
|
||||
}
|
||||
var err error
|
||||
var params = props[i].(map[string]interface{})
|
||||
if _, ok := params["name"]; !ok {
|
||||
params["name"] = "临时"
|
||||
}
|
||||
if url != "" {
|
||||
var err error
|
||||
transport, err = GetTransport(url, user, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance, err = GetProxyTransport(url, uuid, params)
|
||||
if err != nil {
|
||||
panic(Error(vm, err))
|
||||
}
|
||||
if instance != nil {
|
||||
defer instance.Close()
|
||||
}
|
||||
|
||||
// var url, user, password string
|
||||
// for k, v := range props[i].(map[string]interface{}) {
|
||||
// if k == "url" {
|
||||
// url = fmt.Sprint(v)
|
||||
// }
|
||||
// if k == "user" {
|
||||
// user = fmt.Sprint(v)
|
||||
// }
|
||||
// if k == "password" {
|
||||
// password = fmt.Sprint(v)
|
||||
// }
|
||||
// }
|
||||
// if url != "" {
|
||||
// var err error
|
||||
// transport, err = GetTransport(url, user, password)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
var err error
|
||||
if instance == nil {
|
||||
instance, err = GetProxyTransport(url, uuid, nil)
|
||||
if err != nil {
|
||||
panic(Error(vm, err))
|
||||
}
|
||||
if instance != nil {
|
||||
defer instance.Close()
|
||||
}
|
||||
}
|
||||
if instance != nil {
|
||||
transport = &http.Transport{
|
||||
Dial: func(string, string) (net.Conn, error) {
|
||||
return instance, nil
|
||||
},
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
if len(formData) > 0 {
|
||||
data := u.Values{}
|
||||
for key, value := range formData {
|
||||
@@ -118,7 +154,6 @@ func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
|
||||
data.Set(key, fmt.Sprintf("%v", v))
|
||||
}
|
||||
}
|
||||
|
||||
req, err = http.NewRequest(method, url, strings.NewReader(data.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ func initPlugins() {
|
||||
Functions[i].Running = false
|
||||
if len(Functions[i].CronIds) != 0 {
|
||||
for _, id := range Functions[i].CronIds {
|
||||
C.Remove(cron.EntryID(id))
|
||||
CRON.Remove(cron.EntryID(id))
|
||||
}
|
||||
}
|
||||
Functions = append(Functions[:i], Functions[i+1:]...)
|
||||
|
||||
@@ -105,7 +105,7 @@ func CancelPluginCrons(uuid string) {
|
||||
v, ok := crons.Load(uuid)
|
||||
if ok {
|
||||
for _, id := range *v.(*[]cron.EntryID) {
|
||||
C.Remove(id)
|
||||
CRON.Remove(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func(
|
||||
if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 {
|
||||
cron = "0 " + cron
|
||||
}
|
||||
id, err := C.AddFunc(cron, func() {
|
||||
id, err := CRON.AddFunc(cron, func() {
|
||||
// mutex := GetMutex(uuid)
|
||||
// mutex.Lock()
|
||||
// defer mutex.Unlock()
|
||||
@@ -228,7 +228,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func(
|
||||
}
|
||||
})
|
||||
o.Set("remove", func(id cron.EntryID) {
|
||||
C.Remove(id)
|
||||
CRON.Remove(id)
|
||||
})
|
||||
return o
|
||||
})
|
||||
@@ -351,7 +351,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func(
|
||||
vm.Set("fetch", func(wts ...interface{}) interface{} {
|
||||
promise, resolve, reject := vm.NewPromise()
|
||||
go func() {
|
||||
obj, err := fetch(vm, wts...)
|
||||
obj, err := fetch(vm, uuid, wts...)
|
||||
if err != nil {
|
||||
reject(err)
|
||||
} else {
|
||||
@@ -361,7 +361,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func(
|
||||
return promise
|
||||
})
|
||||
vm.Set("request", func(wts ...interface{}) interface{} {
|
||||
obj, err := fetch(vm, wts...)
|
||||
obj, err := fetch(vm, uuid, wts...)
|
||||
if err != nil {
|
||||
panic(Error(vm, err))
|
||||
}
|
||||
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/cdle/sillyplus/core/storage"
|
||||
"github.com/cdle/sillyplus/utils"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// type ProxyKey struct {
|
||||
// }
|
||||
|
||||
type ProxyConfig struct {
|
||||
Type string `json:"type"`
|
||||
Server string `json:"server"`
|
||||
Port int `json:"port"`
|
||||
Name string `json:"name"`
|
||||
// ProxyKey
|
||||
// RuleMatcher *RuleMatcher `json:"-"`
|
||||
Conn C.Proxy `json:"-"`
|
||||
Rules []string `json:"rules"`
|
||||
Plugins []string `json:"plugins"`
|
||||
|
||||
Cipher string `json:"cipher,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
SkipCertVerify bool `json:"skip-cert-verify,omitempty"`
|
||||
TLS bool `json:"tls,omitempty"`
|
||||
CreatedAt int `json:"created_at,omitempty"`
|
||||
Remark string `json:"remark,omitempty"`
|
||||
Enable bool `json:"enable,omitempty"`
|
||||
// UDP bool `json:"udp,omitempty"`
|
||||
// Plugin string `json:"plugin,omitempty"`
|
||||
// PluginOpts map[string]string `json:"plugin-opts,omitempty"`
|
||||
// Obfs string `json:"obfs,omitempty"`
|
||||
// ObfsOpts map[string]string `json:"obfs-opts,omitempty"`
|
||||
// Enable bool `json:"enable,omitempty"`
|
||||
// ExcludeIPs []string `json:"exclude-ip,omitempty"`
|
||||
// ProxyGroups []string `json:"proxy-groups,omitempty"`
|
||||
|
||||
}
|
||||
|
||||
var Proxies sync.Map
|
||||
var proxies = MakeBucket("proxies")
|
||||
|
||||
func GetProxyTransport(rawURL string, uuid string, params map[string]interface{}) (C.Conn, error) {
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
port := u.Port()
|
||||
if port == "" {
|
||||
switch u.Scheme {
|
||||
case "https":
|
||||
port = "443"
|
||||
case "http":
|
||||
port = "80"
|
||||
default:
|
||||
err = fmt.Errorf("%s scheme not Support", rawURL)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
addr := C.Metadata{
|
||||
Host: u.Hostname(),
|
||||
DstIP: nil,
|
||||
DstPort: port,
|
||||
}
|
||||
var p *ProxyConfig
|
||||
if params != nil {
|
||||
params["port"] = utils.Int(params["port"])
|
||||
conn, err := adapter.ParseProxy(params)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("代理配置错误:%v", err)
|
||||
return nil, err
|
||||
}
|
||||
i, err := conn.DialContext(context.Background(), &addr)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("代理连接错误:%v", err)
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
var plugins = []*ProxyConfig{}
|
||||
Proxies.Range(func(key, value any) bool {
|
||||
cfg := value.(*ProxyConfig)
|
||||
if Contains(cfg.Rules, addr.Host) {
|
||||
p = cfg
|
||||
return false
|
||||
}
|
||||
if Contains(cfg.Plugins, uuid) {
|
||||
plugins = append(plugins, cfg)
|
||||
}
|
||||
return true
|
||||
})
|
||||
if p != nil {
|
||||
i, err := p.Conn.DialContext(context.Background(), &addr)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s(%s)代理错误:%v", p.Type, p.Name, err)
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
if len(plugins) != 0 {
|
||||
i, err := plugins[0].Conn.DialContext(context.Background(), &addr)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s(%s)代理错误:%v", p.Type, p.Name, err)
|
||||
}
|
||||
return i, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proxies.Foreach(func(b1, b2 []byte) error {
|
||||
new := string(b2)
|
||||
var ncfg = ProxyConfig{}
|
||||
if strings.HasPrefix(new, "o:") {
|
||||
err := json.Unmarshal([]byte(strings.Replace(new, "o:", "", 1)), &ncfg)
|
||||
if err != nil {
|
||||
console.Log("无法解析的代理数据:", err)
|
||||
return nil
|
||||
}
|
||||
// ncfg.RuleMatcher, err = preprocessRules(ncfg.Rules)
|
||||
if err != nil {
|
||||
console.Log("无法处理的代理匹配规则:", err)
|
||||
return nil
|
||||
}
|
||||
p, err := adapter.ParseProxy(structToMap(ncfg))
|
||||
if err != nil {
|
||||
console.Log("无法解析的代理:", err)
|
||||
return nil
|
||||
}
|
||||
ncfg.Conn = p
|
||||
// fmt.Println("===", string(utils.JsonMarshal(ncfg)))
|
||||
// fmt.Println(ncfg.RuleMatcher.Match("106.52.87.206"))
|
||||
// fmt.Println(ncfg.RuleMatcher.Match("api.telegram.org"))
|
||||
Proxies.Store(string(b1), &ncfg)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
storage.Watch(proxies, "*", func(old, new, key string) *storage.Final {
|
||||
_, err := uuid.Parse(key)
|
||||
if err != nil {
|
||||
return &storage.Final{
|
||||
Error: errors.New("非法的UUID"),
|
||||
}
|
||||
}
|
||||
// var ocfg = ProxyConfig{}
|
||||
// if strings.HasPrefix(new, "o:") {
|
||||
// json.Unmarshal([]byte(strings.Replace(old, "o:", "", 1)), &ocfg)
|
||||
// }
|
||||
// var okey = ProxyKey{
|
||||
// Type: ocfg.Type,
|
||||
// Server: ocfg.Server,
|
||||
// Port: ocfg.Port,
|
||||
// }
|
||||
// var nkey = ProxyKey{}
|
||||
var ncfg = ProxyConfig{}
|
||||
if new == "" { //删除逻辑
|
||||
Proxies.Delete(key)
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(new, "o:") {
|
||||
err := json.Unmarshal([]byte(strings.Replace(new, "o:", "", 1)), &ncfg)
|
||||
if err != nil {
|
||||
return &storage.Final{
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
// nkey = ProxyKey{
|
||||
// Type: ncfg.Type,
|
||||
// Server: ncfg.Server,
|
||||
// Port: ncfg.Port,
|
||||
// }
|
||||
}
|
||||
// ov, ok := Proxies.Load(nkey)
|
||||
// if ok && (!IsDifferent(ocfg, ncfg, []string{"Name", "UUID", "Rules", "Plugins"}) || checkProxy(ov.(C.Proxy))) { //代理依旧有效
|
||||
// return nil
|
||||
// }
|
||||
// ncfg.RuleMatcher, err = preprocessRules(ncfg.Rules)
|
||||
if err != nil {
|
||||
return &storage.Final{
|
||||
Error: errors.New("不支持的代理匹配规则:" + err.Error()),
|
||||
}
|
||||
}
|
||||
p, err := adapter.ParseProxy(structToMap(ncfg))
|
||||
if err != nil {
|
||||
return &storage.Final{
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
ncfg.Conn = p
|
||||
ncfg.CreatedAt = int(time.Now().Unix())
|
||||
Proxies.Store(key, &ncfg)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func structToMap(s interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
d, _ := json.Marshal(s)
|
||||
json.Unmarshal(d, &result)
|
||||
return result
|
||||
}
|
||||
|
||||
func IsDifferent(a, b interface{}, ignoreFields []string) bool {
|
||||
aVal := reflect.ValueOf(a)
|
||||
bVal := reflect.ValueOf(b)
|
||||
|
||||
if aVal.Kind() != reflect.Struct || bVal.Kind() != reflect.Struct {
|
||||
// 如果不是 struct 类型,则返回 true(不同)
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取 struct 的字段数
|
||||
numFields := aVal.NumField()
|
||||
|
||||
// 遍历 struct 的所有字段,检查是否有不同
|
||||
for i := 0; i < numFields; i++ {
|
||||
aField := aVal.Field(i)
|
||||
bField := bVal.Field(i)
|
||||
|
||||
// 获取字段名
|
||||
fieldName := aVal.Type().Field(i).Name
|
||||
|
||||
// 如果字段名在 ignoreFields 中,则跳过比较
|
||||
if Contains(ignoreFields, fieldName) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果字段类型不同,则返回 true(不同)
|
||||
if aField.Type() != bField.Type() {
|
||||
return true
|
||||
}
|
||||
|
||||
// 如果字段值不同,则返回 true(不同)
|
||||
if !reflect.DeepEqual(aField.Interface(), bField.Interface()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有字段都相同,则返回 false(相同)
|
||||
return false
|
||||
}
|
||||
+13
-8
@@ -312,11 +312,16 @@ func initWeb() {
|
||||
// handleHTTP(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
port := sillyGirl.GetString("port", "8080")
|
||||
port := sillyGirl.GetInt("port")
|
||||
if port == 0 {
|
||||
sillyGirl.Set("port", 8080)
|
||||
port = 8080
|
||||
}
|
||||
srvs := []*http.Server{{
|
||||
Addr: ":" + port,
|
||||
Addr: ":" + fmt.Sprint(port),
|
||||
Handler: Server,
|
||||
}}
|
||||
|
||||
storage.Watch(sillyGirl, "port", func(old, new, key string) *storage.Final {
|
||||
if new == "" {
|
||||
new = "8080"
|
||||
@@ -334,9 +339,9 @@ func initWeb() {
|
||||
srvs = append(srvs, srv)
|
||||
|
||||
go func() {
|
||||
logs.Info("Http服务(%s)重新运行", port)
|
||||
logs.Info("Http服务(%d)重新运行", port)
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
logs.Error("Http服务(%s)运行失败:%s", port, err.Error())
|
||||
logs.Error("Http服务(%d)运行失败:%s", port, err.Error())
|
||||
ch <- err
|
||||
}
|
||||
}()
|
||||
@@ -350,7 +355,7 @@ func initWeb() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := srvs[0].Shutdown(ctx); err == nil {
|
||||
logs.Info("Http服务(%s)关闭", old)
|
||||
logs.Info("Http服务(%d)关闭", old)
|
||||
}
|
||||
srvs = srvs[1:]
|
||||
}
|
||||
@@ -362,12 +367,12 @@ func initWeb() {
|
||||
// logs.Info("Http服务(%s)开始运行", port)
|
||||
|
||||
logs.Info("管理员面板:")
|
||||
logs.Info(" > 本机: http://localhost:%s/admin", port)
|
||||
logs.Info(" > 本机: http://localhost:%d/admin", port)
|
||||
local_ip := getLocalIP()
|
||||
logs.Info(" > 局域网: http://%s:%s/admin", local_ip, port)
|
||||
logs.Info(" > 局域网: http://%s:%d/admin", local_ip, port)
|
||||
ip := sillyGirl.GetString("ip")
|
||||
if ip != "" {
|
||||
logs.Info(" > 广域网: http://%s:%s/admin", ip, port)
|
||||
logs.Info(" > 广域网: http://%s:%d/admin", ip, port)
|
||||
}
|
||||
sillyGirl.Set("local_ip", local_ip)
|
||||
go func() {
|
||||
|
||||
Reference in New Issue
Block a user