This commit is contained in:
cdle
2023-07-05 17:19:56 +08:00
parent 873bccce55
commit 643ecd0f9c
21 changed files with 573 additions and 81 deletions
+23
View File
@@ -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
+96
View File
@@ -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
}
+4
View File
@@ -613,6 +613,10 @@ func (sender *CustomSender) Reply(msgs ...interface{}) (string, error) {
push = true push = true
case string: case string:
args = append(args, item) args = append(args, item)
default:
if item != nil {
args = append(args, fmt.Sprint(item))
}
} }
} }
if len(args) == 0 { if len(args) == 0 {
+1 -1
View File
@@ -8,6 +8,6 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script src="/admin/umi.29bb0b44.js"></script> <script src="/admin/umi.7bcd86f8.js"></script>
</body></html> </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
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
+36
View File
@@ -319,6 +319,7 @@ type CarryGroup struct {
// CARRY API // CARRY API
func init() { func init() {
GinApi(GET, "/api/carry/groups", RequireAuth, func(ctx *gin.Context) { GinApi(GET, "/api/carry/groups", RequireAuth, func(ctx *gin.Context) {
current := utils.Int(ctx.Query("current")) current := utils.Int(ctx.Query("current"))
pageSize := utils.Int(ctx.Query("pageSize")) pageSize := utils.Int(ctx.Query("pageSize"))
@@ -364,6 +365,41 @@ func init() {
"data": names, "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) { GinApi(GET, "/api/carry/group_selects", RequireAuth, func(ctx *gin.Context) {
chat_id := ctx.Query("chat_id") chat_id := ctx.Query("chat_id")
platform := ctx.Query("platform") platform := ctx.Query("platform")
+3 -3
View File
@@ -2,9 +2,9 @@ package core
import cron "github.com/robfig/cron/v3" import cron "github.com/robfig/cron/v3"
var C *cron.Cron var CRON *cron.Cron
func init() { func init() {
C = cron.New(cron.WithSeconds()) CRON = cron.New(cron.WithSeconds())
C.Start() CRON.Start()
} }
+1 -1
View File
@@ -383,7 +383,7 @@ func AddCommand(cmds []*common.Function) {
if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 { if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 {
Cron = "0 " + Cron Cron = "0 " + Cron
} }
cronId, err := C.AddFunc(Cron, func() { cronId, err := CRON.AddFunc(Cron, func() {
cmds[j].Handle(&Faker{ cmds[j].Handle(&Faker{
Admin: true, Admin: true,
Type: plt, Type: plt,
+38 -2
View File
@@ -3,6 +3,8 @@ package core
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net"
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
@@ -33,14 +35,43 @@ func Init() {
sillyGirl.Set("started_at", time.Now().Format("2006-01-02 15:04:05")) 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 { storage.Watch(sillyGirl, "compiled_at", func(old, new, key string) *storage.Final {
if old != new { 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 获取版本号...") 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 { if err != nil {
console.Error("获取版本号错误:%s", err) console.Error("获取版本号错误:%s", err)
return &storage.Final{ return &storage.Final{
Error: fmt.Errorf("貌似网络不太行啊:%s", err), Error: fmt.Errorf("貌似网络不太行啊:%s", err),
} }
} }
defer resp.Body.Close()
var data, _ = ioutil.ReadAll(resp.Body)
latest_version := regexp.MustCompile(`\d{13}`).FindString(string(data)) latest_version := regexp.MustCompile(`\d{13}`).FindString(string(data))
if latest_version <= compiled_at { if latest_version <= compiled_at {
console.Debug("当前版本 %s 已是最新,无需升级", compiled_at) console.Debug("当前版本 %s 已是最新,无需升级", compiled_at)
@@ -48,12 +79,17 @@ func Init() {
Message: fmt.Sprintf("当前版本 %s 已是最新,无需升级", compiled_at), Message: fmt.Sprintf("当前版本 %s 已是最新,无需升级", compiled_at),
} }
} }
client = &http.Client{}
if transport != nil {
client.Transport = transport
}
console.Debug("正在从 cdle/binary 获取最新版本 %s 编译文件...", latest_version) console.Debug("正在从 cdle/binary 获取最新版本 %s 编译文件...", latest_version)
qurl := "https://raw.githubusercontent.com/cdle/binary/master/sillyGirl_" + runtime.GOOS + "_" + runtime.GOARCH + "_" + latest_version qurl := "https://raw.githubusercontent.com/cdle/binary/master/sillyGirl_" + runtime.GOOS + "_" + runtime.GOARCH + "_" + latest_version
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
qurl += ".exe" qurl += ".exe"
} }
resp, err := http.Get(qurl) req, _ = http.NewRequest("GET", qurl, strings.NewReader(""))
resp, err = client.Do(req)
if err != nil { if err != nil {
console.Error("获取最新编译文件错误:%s", err) console.Error("获取最新编译文件错误:%s", err)
return &storage.Final{ return &storage.Final{
+8 -5
View File
@@ -18,9 +18,12 @@ func MakeBucketObject(vm *goja.Runtime, uuid string, on_start bool, bucket stora
}) })
return rt return rt
}) })
obj.Set("set", func(key, value interface{}) error { obj.Set("set", func(key, value interface{}) interface{} {
_, err := SetBucketKeyValue(bucket, key, value) msg, err := SetBucketKeyValue(bucket, key, value)
return err if err != nil {
panic(Error(vm, err))
}
return msg
}) })
obj.Set("delete", func(key interface{}) error { obj.Set("delete", func(key interface{}) error {
_, err := bucket.Set(key, "") _, 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) return vm.ToValue(result)
}, },
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) { 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(), property, value.Export(),
) )
return result == nil return true
}, },
}) })
} }
+55 -20
View File
@@ -3,18 +3,20 @@ package core
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"net"
"net/http" "net/http"
u "net/url" u "net/url"
"strconv" "strconv"
"strings" "strings"
"time" "time"
C "github.com/Dreamacro/clash/constant"
"github.com/cdle/sillyplus/utils" "github.com/cdle/sillyplus/utils"
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/goccy/go-json" "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 method = "get"
var url = "" var url = ""
var req *http.Request var req *http.Request
@@ -31,6 +33,7 @@ func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
// var useproxy bool // var useproxy bool
var timeout time.Duration = 0 var timeout time.Duration = 0
var login = false var login = false
var instance C.Conn
for _, wt := range wts { for _, wt := range wts {
switch wt := wt.(type) { switch wt := wt.(type) {
case string: case string:
@@ -79,30 +82,63 @@ func fetch(vm *goja.Runtime, wts ...interface{}) (interface{}, error) {
case "form": case "form":
formData = props[i].(map[string]interface{}) formData = props[i].(map[string]interface{})
case "proxy": case "proxy":
var url, user, password string var err error
for k, v := range props[i].(map[string]interface{}) { var params = props[i].(map[string]interface{})
if k == "url" { if _, ok := params["name"]; !ok {
url = fmt.Sprint(v) params["name"] = "临时"
}
if k == "user" {
user = fmt.Sprint(v)
}
if k == "password" {
password = fmt.Sprint(v)
}
} }
if url != "" { instance, err = GetProxyTransport(url, uuid, params)
var err error if err != nil {
transport, err = GetTransport(url, user, password) panic(Error(vm, err))
if err != nil {
return nil, 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 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 { if len(formData) > 0 {
data := u.Values{} data := u.Values{}
for key, value := range formData { 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)) data.Set(key, fmt.Sprintf("%v", v))
} }
} }
req, err = http.NewRequest(method, url, strings.NewReader(data.Encode())) req, err = http.NewRequest(method, url, strings.NewReader(data.Encode()))
if err != nil { if err != nil {
return nil, err return nil, err
+1 -1
View File
@@ -214,7 +214,7 @@ func initPlugins() {
Functions[i].Running = false Functions[i].Running = false
if len(Functions[i].CronIds) != 0 { if len(Functions[i].CronIds) != 0 {
for _, id := range Functions[i].CronIds { for _, id := range Functions[i].CronIds {
C.Remove(cron.EntryID(id)) CRON.Remove(cron.EntryID(id))
} }
} }
Functions = append(Functions[:i], Functions[i+1:]...) Functions = append(Functions[:i], Functions[i+1:]...)
+5 -5
View File
@@ -105,7 +105,7 @@ func CancelPluginCrons(uuid string) {
v, ok := crons.Load(uuid) v, ok := crons.Load(uuid)
if ok { if ok {
for _, id := range *v.(*[]cron.EntryID) { 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 { if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 {
cron = "0 " + cron cron = "0 " + cron
} }
id, err := C.AddFunc(cron, func() { id, err := CRON.AddFunc(cron, func() {
// mutex := GetMutex(uuid) // mutex := GetMutex(uuid)
// mutex.Lock() // mutex.Lock()
// defer mutex.Unlock() // 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) { o.Set("remove", func(id cron.EntryID) {
C.Remove(id) CRON.Remove(id)
}) })
return o 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{} { vm.Set("fetch", func(wts ...interface{}) interface{} {
promise, resolve, reject := vm.NewPromise() promise, resolve, reject := vm.NewPromise()
go func() { go func() {
obj, err := fetch(vm, wts...) obj, err := fetch(vm, uuid, wts...)
if err != nil { if err != nil {
reject(err) reject(err)
} else { } else {
@@ -361,7 +361,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func(
return promise return promise
}) })
vm.Set("request", func(wts ...interface{}) interface{} { vm.Set("request", func(wts ...interface{}) interface{} {
obj, err := fetch(vm, wts...) obj, err := fetch(vm, uuid, wts...)
if err != nil { if err != nil {
panic(Error(vm, err)) panic(Error(vm, err))
} }
+253
View File
@@ -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
View File
@@ -312,11 +312,16 @@ func initWeb() {
// handleHTTP(c.Writer, c.Request) // 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{{ srvs := []*http.Server{{
Addr: ":" + port, Addr: ":" + fmt.Sprint(port),
Handler: Server, Handler: Server,
}} }}
storage.Watch(sillyGirl, "port", func(old, new, key string) *storage.Final { storage.Watch(sillyGirl, "port", func(old, new, key string) *storage.Final {
if new == "" { if new == "" {
new = "8080" new = "8080"
@@ -334,9 +339,9 @@ func initWeb() {
srvs = append(srvs, srv) srvs = append(srvs, srv)
go func() { go func() {
logs.Info("Http服务(%s)重新运行", port) logs.Info("Http服务(%d)重新运行", port)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { 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 ch <- err
} }
}() }()
@@ -350,7 +355,7 @@ func initWeb() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
if err := srvs[0].Shutdown(ctx); err == nil { if err := srvs[0].Shutdown(ctx); err == nil {
logs.Info("Http服务(%s)关闭", old) logs.Info("Http服务(%d)关闭", old)
} }
srvs = srvs[1:] srvs = srvs[1:]
} }
@@ -362,12 +367,12 @@ func initWeb() {
// logs.Info("Http服务(%s)开始运行", port) // logs.Info("Http服务(%s)开始运行", port)
logs.Info("管理员面板:") logs.Info("管理员面板:")
logs.Info(" > 本机: http://localhost:%s/admin", port) logs.Info(" > 本机: http://localhost:%d/admin", port)
local_ip := getLocalIP() 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") ip := sillyGirl.GetString("ip")
if 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) sillyGirl.Set("local_ip", local_ip)
go func() { go func() {