diff --git a/client/mysql.go b/client/mysql.go index 87e66cab..d40ae9f7 100644 --- a/client/mysql.go +++ b/client/mysql.go @@ -1,6 +1,7 @@ package client import ( + "go-wechat/config" "gorm.io/driver/mysql" "gorm.io/gorm" "log" @@ -10,11 +11,9 @@ import ( var MySQL *gorm.DB func InitMySQLClient() { - dsn := "wechat:wechat123@tcp(10.0.0.31:3307)/wechat?charset=utf8mb4&parseTime=True&loc=Local" - // 创建连接对象 mysqlConfig := mysql.Config{ - DSN: dsn, + DSN: config.Conf.MySQL.GetDSN(), DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式 DontSupportRenameColumn: true, // 用 `change` 重命名列 } diff --git a/config.yaml b/config.yaml index 225cf229..3b300b4c 100644 --- a/config.yaml +++ b/config.yaml @@ -1,13 +1,32 @@ +# 微信HOOK配置 +wechat: + # 微信HOOK接口地址 + host: 10.0.0.73:19088 + # 是否在启动的时候自动设置hook服务的回调 + autoSetCallback: true + # 回调IP,如果是Docker运行,本参数必填,如果Docker修改了映射,格式为 ip:port + callback: 10.0.0.51 + +# 数据库 +mysql: + host: 10.0.0.31 + port: 3307 + user: wechat + password: wechat123 + db: wechat + task: - enable: true + enable: false syncFriends: enable: true cron: '0 * * * *' waterGroup: enable: true cron: '30 9 * * *' + # 需要发送水群排行榜的群Id groups: - '18958257758@chatroom' - '49448748645@chatroom' + # 不计入统计范围的用户Id blacklist: - - 'wxid_778868788691exit2' \ No newline at end of file + - 'wxid_7788687886912' \ No newline at end of file diff --git a/config/config.go b/config/config.go index 70801a39..4c1963f5 100644 --- a/config/config.go +++ b/config/config.go @@ -5,7 +5,9 @@ var Conf Config // Config // @description: 配置 type Config struct { - Task task `json:"task" yaml:"task"` // 定时任务配置 + Task task `json:"task" yaml:"task"` // 定时任务配置 + MySQL mysql `json:"mysql" yaml:"mysql"` // MySQL 配置 + Wechat wechat `json:"wechat" yaml:"wechat"` // 微信助手 } // task diff --git a/config/mysql.go b/config/mysql.go new file mode 100644 index 00000000..e03024d2 --- /dev/null +++ b/config/mysql.go @@ -0,0 +1,24 @@ +package config + +import ( + "fmt" +) + +// mysql +// @description: MySQL配置 +type mysql struct { + Host string `mapstructure:"host" yaml:"host"` // 主机 + Port int `mapstructure:"port" yaml:"port"` // 端口 + User string `mapstructure:"user" yaml:"user"` // 用户名 + Password string `mapstructure:"password" yaml:"password"` // 密码 + Db string `mapstructure:"db" yaml:"db"` // 数据库名称 +} + +// GetDSN +// @description: 返回 MySQL 连接字符串 +// @receiver c +// @return string +func (c mysql) GetDSN() string { + return fmt.Sprintf("%s:%s@tcp(%s:%v)/%s?charset=utf8mb4&parseTime=True&loc=Local", + c.User, c.Password, c.Host, c.Port, c.Db) +} diff --git a/config/wechat.go b/config/wechat.go new file mode 100644 index 00000000..e3054d22 --- /dev/null +++ b/config/wechat.go @@ -0,0 +1,33 @@ +package config + +import "strings" + +// wxHelper +// @description: 微信助手 +type wechat struct { + Host string `json:"host" yaml:"host"` // 接口地址 + AutoSetCallback bool `json:"autoSetCallback" yaml:"autoSetCallback"` // 是否自动设置回调地址 + Callback string `json:"callback" yaml:"callback"` // 回调地址 +} + +// Check +// @description: 检查配置是否可用 +// @receiver w +// @return bool +func (w wechat) Check() bool { + if w.Host == "" { + return false + } + if w.AutoSetCallback && w.Callback == "" { + return false + } + return true +} + +func (w wechat) GetURL(uri string) string { + host := w.Host + if !strings.HasPrefix(w.Host, "http://") { + host = "http://" + w.Host + } + return host + uri +} diff --git a/go.mod b/go.mod index 134dba33..b710f05a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module go-wechat go 1.21 require ( + github.com/duke-git/lancet/v2 v2.2.7 github.com/fsnotify/fsnotify v1.6.0 github.com/go-co-op/gocron v1.34.1 github.com/go-resty/resty/v2 v2.8.0 diff --git a/go.sum b/go.sum index 2201f313..c0f33f62 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/duke-git/lancet/v2 v2.2.7 h1:u9zr6HR+MDUvZEtTlAFtSTIgZfEFsN7cKi27n5weZsw= +github.com/duke-git/lancet/v2 v2.2.7/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= diff --git a/config/func.go b/initialization/mysql.go similarity index 66% rename from config/func.go rename to initialization/mysql.go index dff7ab44..fdcfadbc 100644 --- a/config/func.go +++ b/initialization/mysql.go @@ -1,8 +1,10 @@ -package config +package initialization import ( "github.com/fsnotify/fsnotify" "github.com/spf13/viper" + "go-wechat/client" + "go-wechat/config" "log" ) @@ -21,23 +23,29 @@ func InitConfig() { log.Panicf("读取配置文件失败: %v", err) } // 绑定配置文件 - if err := vp.Unmarshal(&Conf); err != nil { + if err := vp.Unmarshal(&config.Conf); err != nil { log.Panicf("配置文件解析失败: %v", err) } - log.Printf("配置文件解析完成: %+v", Conf) + log.Printf("配置文件解析完成: %+v", config.Conf) + if !config.Conf.Wechat.Check() { + log.Panicf("微信HOOK配置缺失") + } // 初始化数据库连接 - //db.Init() + client.InitMySQLClient() //redis.Init() // 下面的代码是配置变动之后自动刷新的 vp.WatchConfig() vp.OnConfigChange(func(e fsnotify.Event) { // 绑定配置文件 - if err := vp.Unmarshal(&Conf); err != nil { + if err := vp.Unmarshal(&config.Conf); err != nil { log.Printf("配置文件更新失败: %v", err) } else { + if !config.Conf.Wechat.Check() { + log.Panicf("微信HOOK配置缺失") + } // 初始化数据库连接 - //db.Init() + client.InitMySQLClient() //redis.Init() } }) diff --git a/main.go b/main.go index 6a59c6ac..ab6ee78c 100644 --- a/main.go +++ b/main.go @@ -2,18 +2,19 @@ package main import ( "bytes" - "go-wechat/client" "go-wechat/config" "go-wechat/handler" + "go-wechat/initialization" "go-wechat/tasks" + "go-wechat/utils" "io" "log" "net" + "time" ) func init() { - config.InitConfig() - client.InitMySQLClient() + initialization.InitConfig() tasks.InitTasks() } @@ -37,6 +38,13 @@ func process(conn net.Conn) { } func main() { + // 如果启用了自动配置回调,就设置一下 + if config.Conf.Wechat.AutoSetCallback { + utils.ClearCallback() + time.Sleep(500 * time.Millisecond) // 休眠五百毫秒再设置 + utils.SetCallback(config.Conf.Wechat.Callback) + } + // 建立 tcp 服务 listen, err := net.Listen("tcp", "0.0.0.0:19099") if err != nil { diff --git a/tasks/friends.go b/tasks/friends.go index 873ee658..0b0342c0 100644 --- a/tasks/friends.go +++ b/tasks/friends.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/go-resty/resty/v2" "go-wechat/client" + "go-wechat/config" "go-wechat/constant" "go-wechat/entity" "go-wechat/model" @@ -27,7 +28,7 @@ func syncFriends() { resp, err := hc.R(). SetHeader("Content-Type", "application/json;chartset=utf-8"). SetResult(&base). - Post("http://10.0.0.73:19088/api/getContactList") + Post(config.Conf.Wechat.GetURL("/api/getContactList")) if err != nil { log.Printf("获取好友列表失败: %s", err.Error()) return @@ -105,7 +106,7 @@ func syncGroupUsers(tx *gorm.DB, gid string) { SetHeader("Content-Type", "application/json;chartset=utf-8"). SetBody(string(pbs)). SetResult(&baseResp). - Post("http://10.0.0.73:19088/api/getMemberFromChatRoom") + Post(config.Conf.Wechat.GetURL("/api/getMemberFromChatRoom")) if err != nil { log.Printf("获取群成员信息失败: %s", err.Error()) return @@ -189,7 +190,7 @@ func getContactProfile(wxid string) (ent model.ContactProfile, err error) { SetHeader("Content-Type", "application/json;chartset=utf-8"). SetBody(string(pbs)). SetResult(&baseResp). - Post("http://10.0.0.73:19088/api/getContactProfile") + Post(config.Conf.Wechat.GetURL("/api/getContactProfile")) if err != nil { log.Printf("获取成员详情失败: %s", err.Error()) return diff --git a/utils/callback.go b/utils/callback.go new file mode 100644 index 00000000..1189f59c --- /dev/null +++ b/utils/callback.go @@ -0,0 +1,62 @@ +package utils + +import ( + "encoding/json" + "github.com/duke-git/lancet/v2/netutil" + "github.com/go-resty/resty/v2" + "go-wechat/config" + "log" + "net" + "strconv" + "strings" +) + +// ClearCallback +// @description: 清理微信HOOK回调 +func ClearCallback() { + res := resty.New() + resp, err := res.R(). + SetHeader("Content-Type", "application/json;chartset=utf-8"). + Post(config.Conf.Wechat.GetURL("/api/unhookSyncMsg")) + if err != nil { + log.Panicf("清理微信HOOK回调失败: %s", err.Error()) + } + log.Printf("清理微信HOOK回调结果: %s", resp.String()) +} + +// SetCallback +// @description: 设置微信HOOK回调 +// @param host +func SetCallback(userHost string) { + // 获取本机IP地址 + host := net.ParseIP(netutil.GetInternalIp()).String() + port := 19099 + if userHost != "" { + uh := strings.Split(strings.TrimSpace(userHost), ":") + host = uh[0] + if len(uh) == 2 { + port, _ = strconv.Atoi(uh[1]) + } + } + + // 组装参数 + param := map[string]any{ + "port": port, // socket端口 + "ip": host, // socketIP + "url": "", // http接口地址 + "timeout": 3000, // 超时毫秒数 + "enableHttp": 0, // 是否使用http接口 + } + pbs, _ := json.Marshal(param) + log.Printf("设置微信HOOK回调参数: %s", string(pbs)) + + res := resty.New() + resp, err := res.R(). + SetHeader("Content-Type", "application/json;chartset=utf-8"). + SetBody(string(pbs)). + Post(config.Conf.Wechat.GetURL("/api/hookSyncMsg")) + if err != nil { + log.Panicf("设置微信HOOK回调失败: %s", err.Error()) + } + log.Printf("设置微信HOOK回调结果: %s", resp.String()) +} diff --git a/utils/send.go b/utils/send.go index dabe5f10..ef250ad9 100644 --- a/utils/send.go +++ b/utils/send.go @@ -3,6 +3,7 @@ package utils import ( "encoding/json" "github.com/go-resty/resty/v2" + "go-wechat/config" "log" "time" ) @@ -28,7 +29,7 @@ func SendMessage(toId, atId, msg string, retryCount int) { resp, err := res.R(). SetHeader("Content-Type", "application/json;chartset=utf-8"). SetBody(string(pbs)). - Post("http://10.0.0.73:19088/api/sendTextMsg") + Post(config.Conf.Wechat.GetURL("/api/sendTextMsg")) if err != nil { log.Printf("发送文本消息失败: %s", err.Error()) // 休眠五秒后重新发送