使用Go制作IOTQQ插件

本文最后更新于 超过 5 年前,文中所描述的信息可能已发生改变。
mcoo - iotqq-plugins-demo

使用Go制作IOTQQ插件

踩坑记录:

用Go写插件可以生成二进制文件,这算是一个优点吧。

  1. 安装golang-socketio
sh
go get github.com/graarh/golang-socketio
  1. 连接IOTQQ的Api接口:
go
package main
import (
"github.com/graarh/golang-socketio"
"github.com/graarh/golang-socketio/transport"
"log"
"runtime"
"time"
"fmt"
)
site := ""
port := 8888
c, err := gosocketio.Dial(
  gosocketio.GetUrl(site, port, false),
  transport.GetDefaultWebsocketTransport())
if err != nil {
  log.Fatal(err)
}
err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
  log.Fatal("Disconnected")
})
if err != nil {
  log.Fatal(err)
}
err = c.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
  log.Println("Connected")
})
if err != nil {
  log.Fatal(err)
}
Demo:
go
package main
import (
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"time"

"github.com/graarh/golang-socketio"
"github.com/graarh/golang-socketio/transport"
"github.com/mcoo/iotqq/model"
)
var url1, qq string
var conf iotqq.Conf
var zanok, qd []int64
func init() {
file, err := os.Open("main.conf")
conf = iotqq.Conf{true, make(map[string]int)}
//log.Println(file)
if err != nil {
    log.Println(err)
    os.Create("main.conf")
    f, _ := os.OpenFile("main.conf", os.O_APPEND, 0644)
    defer f.Close()
    enc := json.NewEncoder(f)
    conf.Enable = true
    conf.GData = make(map[string]int)
    enc.Encode(conf)
}
defer file.Close()
tmp := json.NewDecoder(file)
//log.Println(tmp)
for tmp.More() {
    err := tmp.Decode(&conf)
    if err != nil {
        fmt.Println("Error:", err)
    }
    //fmt.Println(conf)
}
}
func periodlycall(d time.Duration, f func()) {
for x := range time.Tick(d) {
    f()
    log.Println(x)
}
}
func resetzan() {

m1 := len(zanok)
for m := 0; m < m1; m++ {
    i := 0
    zanok = append(zanok[:i], zanok[i+1:]...)
}
m2 := len(qd)
for m := 0; m < m2; m++ {
    i := 0
    qd = append(qd[:i], qd[i+1:]...)
}
}
func SendJoin(c *gosocketio.Client) {
log.Println("获取QQ号连接")
result, err := c.Ack("GetWebConn", qq, time.Second*5)
if err != nil {
    log.Fatal(err)
} else {
    log.Println("emit", result)
}
}
func save() {
f, _ := os.OpenFile("main.conf", os.O_WRONLY|os.O_CREATE, 0644)
defer f.Close()
enc := json.NewEncoder(f)
enc.Encode(conf)
}
func main() {
var site string
var port int
port = 8888
fmt.Println("IOTQQ插件 - 基于SocketIO V0.0.1")
fmt.Println("作者:Enjoy")
fmt.Println("\n请输入Iotqq的Web地址(无需http://和端口): ")
fmt.Scan(&site)
fmt.Println("\n请输入Iotqq的端口号: ")
fmt.Scan(&port)
fmt.Println("\n请输入QQ机器人账号: ")
fmt.Scan(&qq)
iotqq.Set(url1, qq)
runtime.GOMAXPROCS(runtime.NumCPU())
url1 = site + ":" + strconv.Itoa(port)
c, err := gosocketio.Dial(
    gosocketio.GetUrl(site, port, false),
    transport.GetDefaultWebsocketTransport())
if err != nil {
    log.Fatal(err)
}
err = c.On("OnGroupiotqqs", func(h *gosocketio.Channel, args iotqq.Message) {
    var mess iotqq.Data = args.CurrentPacket.Data
    /*
        mess.Content 消息内容 string
        mess.FromGroupID 来源QQ群 int
        mess.FromUserID 来源QQ int64
        mess.iotqqType 消息类型 string
    */
    log.Println("群聊消息: ", mess.FromNickName+"<"+strconv.FormatInt(mess.FromUserID, 10)+">: "+mess.Content)
    cm := strings.Split(mess.Content, " ")
    if mess.Content == "菜单" {
        iotqq.Send(mess.FromGroupID, 2, "你好我是米娅?\n1.赞我(50个赞哟?)\n2.签到(正在开发)\n3.获取用户 QQ号\n4.天气 城市")
        return
    }
    if mess.Content == "签到" {
        ok := true
        for i := 0; i < len(qd); i++ {
            if mess.FromUserID == 2435932516 {
                break
            }
            if qd[i] == mess.FromUserID {
                ok = false
                break
            }
        }
        if ok {
            _, err := conf.GData[strconv.FormatInt(mess.FromUserID, 10)]
            if err != false {
                conf.GData[strconv.FormatInt(mess.FromUserID, 10)] += 1
                iotqq.Send(mess.FromGroupID, 2, "签到成功 ? 当前金币:"+strconv.Itoa(conf.GData[strconv.FormatInt(mess.FromUserID, 10)]))
            } else {
                conf.GData[strconv.FormatInt(mess.FromUserID, 10)] = 1
                iotqq.Send(mess.FromGroupID, 2, "签到成功 这是你第一次签到哟? 当前金币:"+strconv.Itoa(conf.GData[strconv.FormatInt(mess.FromUserID, 10)]))
            }
            save()
            qd = append(qd, mess.FromUserID)
        } else {
            iotqq.Send(mess.FromGroupID, 2, "已经签到过了")
        }
        return
    }
    if mess.Content == "赞我" {
        ok := true
        for i := 0; i < len(zanok); i++ {
            if zanok[i] == mess.FromUserID {
                ok = false
            }
        }
        if ok {
            iotqq.Send(mess.FromGroupID, 2, "正在赞,可能需要50s时间?")
            for i := 1; i <= 50; i++ {
                iotqq.Zan(strconv.Atoi(strconv.FormatInt(mess.FromUserID, 10)))
                time.Sleep(time.Second * 1)
            }
            iotqq.Send(mess.FromGroupID, 2, "已经赞了50次,如果没有成功,可能是腾讯服务器限制了!")
            zanok = append(zanok, mess.FromUserID)
        } else {
            iotqq.Send(mess.FromGroupID, 2, "之前已经赞了")
        }
        return
    }
    if cm[0] == "语音" {
        if len(cm) < 2 {
            iotqq.Send(mess.FromGroupID, 2, "命令输入错误!")
            return
        }
        iotqq.SendVoice(mess.FromGroupID, 2, cm[1])
    }
    if cm[0] == "天气" {
        if len(cm) < 2 {
            iotqq.Send(mess.FromGroupID, 2, "命令输入错误!")
            return
        }
        tr := &http.Transport{
            TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //如果需要测试自签名的证书 这里需要设置跳过证书检测 否则编译报错
        client := &http.Client{Transport: tr}
        var req *http.Request
        tmp := iotqq.GetCook()
        req, _ = http.NewRequest("GET", "https://weather.mp.qq.com/cgi-bin/rich?g_tk="+tmp.Gtk+"&city="+url.PathEscape(cm[1]), nil)
        c1 := &http.Cookie{Name: "uin", Value: qq, Path: "/", Domain: ".weather.mp.qq.com"}
        c2 := &http.Cookie{Name: "skey", Value: tmp.Skey, Path: "/", Domain: ".weather.mp.qq.com"}
        req.AddCookie(c1)
        req.AddCookie(c2)
        req.Header.Add("Referer", "http://weather.mp.qq.com/ark")
        req.Header.Add("User-Agent", "PostmanRuntime/7.20.1")
        req.Header.Add("Accept", "PostmanRuntime/7.20.1")
        req.Header.Add("Content-Type", "text/json: charset=UTF-8")

        resp, err := client.Do(req)
        if err != nil {
            log.Fatal(err)
        }
        defer resp.Body.Close()
        b, _ := ioutil.ReadAll(resp.Body)
        var weather iotqq.Weather
        err = json.Unmarshal([]byte(string(b)), &weather)
        if err != nil {
            fmt.Println("反序列化出错,info:", err)
        }
        m := "{\"app\":\"com.tencent.weather\",\"desc\":\"天气\",\"view\":\"RichInfoView\",\"ver\":\"1.0.0.217\",\"prompt\":\"[应用]天气\",\"meta\":{\"richinfo\":{\"adcode\":\"%s\",\"air\":\"%s\",\"city\":\"%s\",\"date\":\"%s\",\"max\":\"%s\",\"min\":\"%s\",\"ts\":\"1554951408\",\"type\":\"%s\",\"wind\":\"%s\"}},\"config\":{\"forward\":1,\"autosize\":1,\"type\":\"card\"}}"
        n := fmt.Sprintf(m, weather.Data.Adcode, weather.Data.Air, weather.Data.City, weather.Data.Date, weather.Data.Max, weather.Data.Min, weather.Data.Type, weather.Data.Wind)
        log.Println(n)
        iotqq.SendA(mess.FromGroupID, 2, n, "Jsoniotqq")
    }
    if cm[0] == "获取用户" {
        if len(cm) < 2 {
            iotqq.Send(mess.FromGroupID, 2, "命令输入错误!")
            return
        }
        a, _ := strconv.Atoi(cm[1])
        temp := iotqq.Getinfo(a)
        var user iotqq.QQinfo
        err = json.Unmarshal([]byte(temp), &user)
        if err != nil {
            fmt.Println("反序列化出错,info:", err)
        } else {
            iotqq.Send(mess.FromGroupID, 2, "QQ昵称:"+user.Data.Nickname+"\nQQ账号:"+strconv.Itoa(user.Data.Uin)+"\nVip等级:"+strconv.Itoa(user.Data.Qqvip)+"\n绿钻等级:"+strconv.Itoa(user.Data.Greenvip)+"\n红钻等级:"+strconv.Itoa(user.Data.Redvip))
        }
        return
    }
})
if err != nil {
    log.Fatal(err)
}
err = c.On("OnFriendiotqqs", func(h *gosocketio.Channel, args iotqq.Message) {
    log.Println("私聊消息: ", args.CurrentPacket.Data.Content)
})
if err != nil {
    log.Fatal(err)
}
err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
    log.Fatal("Disconnected")
})
if err != nil {
    log.Fatal(err)
}
err = c.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
    log.Println("连接成功")
})
if err != nil {
    log.Fatal(err)
}
time.Sleep(1 * time.Second)
go SendJoin(c)
periodlycall(24*time.Hour, resetzan)
home:
time.Sleep(600 * time.Second)
SendJoin(c)
goto home
log.Println(" [x] Complete")
}
上面的Demo请去Github上下载。
武汉加油,中国加油!
Python绘图库使用-pyplot