wechat

package module
v0.0.0-...-5175aa2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2020 License: MIT Imports: 26 Imported by: 0

README

Go Wechat

提供微信公众号基础能力支持

已实现

  • 自定义菜单
  • 消息管理
    • 接收消息
    • 被动回复
    • 消息加密
    • 模板消息 [待改进]
    • 群发消息
  • 素材管理
  • 留言管理(not tested)
  • 用户管理
  • 账号管理

TODO

  • 支持 TLS

PS需要更多支持,请参考wechat

快速上手

接入指南

参考微信开发文档

基本的消息与事件处理

package main
import (
	"fmt"
	wc "github.com/dreamer2q/go_wechat"
	"github.com/pkg/errors"
	"log"
	"time"
)

func main() {
	wx := wc.New(&wc.Config{
		AppID:        AppID,
		AppSecret:    AppSecret,
		AppToken:     AppToken,
		AesEncodeKey: AesEncodeKey,
		Timeout:      10 * time.Second,
		Callback:     "/wx",
		Debug:        true,
	})

	wx.SetEventHandler(func(m wc.MessageReceive) wc.MessageReply {
		switch m.Event {
		case wc.EvSubscribe:
			userInfo, err := wx.User.GetUserInfo(m.FromUserName)
			if err != nil {
				log.Printf("error: %#v", errors.Wrap(err, "getUserInfo"))
				return wc.Text{Content: "something went wrong"}
			}
			return wc.Text{Content: fmt.Sprintf("%s welcome you", userInfo.Nickname)}
		case wc.EvUnsubscribe:
			log.Printf("unsubscribe event")
		}
		//nil means no reply
		return nil
	})

	wx.SetMessageHandler(func(m wc.MessageReceive) wc.MessageReply {
		switch m.MsgType {
		case wc.MsgText:
			return wc.Text{Content: m.Content}
		default:
			return wc.Text{Content: "Not support type"}
		}
	})

	log.Panicln(wx.Run(":80"))
}

菜单处理

创建菜单
    err := wx.Menu.Create(
		menu.RootMenu{
			Menus: []menu.Item{
				&menu.ClickMenu{
					Name: "点击测试",
					Key:  "click_test",
				},
				&menu.SubMenu{
					Name: "二级菜单",
					Menus: []menu.Item{
						&menu.ViewMenu{
							Name: "博客",
							Url:  "https://dreamer2q.wang",
						},
						&menu.ClickMenu{
							Name: "关于我",
							Key:  "click_about",
						},
						&menu.ClickMenu{
							Name: "点我没反应",
							Key:  "noempty",
						},
					},
				},
			},
		})
	if err != nil {
		log.Panic(err)
    }
处理菜单事件
  • 方法一,订阅事件
	wx.On("event.CLICK.click_test", func(msg wc.MessageReceive) wc.MessageReply {
		return wc.Text{Content: "点击菜单测试"}
	})
	wx.On("event.CLICK.click_about", func(msg wc.MessageReceive) wc.MessageReply {
		return wc.Text{Content: "关于我: 我是傻逼开发者"}
	})
	wx.On("event.CLICK.noempty", func(msg wc.MessageReceive) wc.MessageReply {
		return nil //no reply
	})
	wx.On("event.VIEW.https://dreamer2q.wang", func(msg wc.MessageReceive) wc.MessageReply {
		log.Printf("view event") //记录事件
		return nil
	})

  • 方法二,在总事件中处理
    wx.SetEventHandler(func(m wc.MessageReceive) wc.MessageReply {
		log.Printf("EventHandler: user %s: %s\n", m.FromUserName, m.Event)
		switch m.Event {
		case wc.EvClick:
			switch m.EventKey {
			case "click_test":
				return wc.Text{Content: "点击菜单测试"}
			case "click_about":
				return wc.Text{Content: "关于我,我是xxxx"}
			case "noempty":
				return nil
			}
		case wc.EvView:
			log.Printf("view event: %s", m.EventKey)
		}
		return nil
	})

订阅事件优先级高,以高优先级处理结果为准。

素材管理

上传素材
获取素材列表

用户管理

账号管理

Documentation

Index

Constants

View Source
const (
	MsgText       = "text"
	MsgImage      = "image"
	MsgVoice      = "voice"
	MsgVideo      = "video"
	MsgShortVideo = "shortvideo"
	MsgLocation   = "location"
	MsgLink       = "link"
)
View Source
const (
	EvSubscribe   = "subscribe"
	EvUnsubscribe = "unsubscribe"
	EvScan        = "SCAN"
	EvLocation    = "LOCATION"
	EvClick       = "CLICK"
	EvView        = "VIEW"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type API

type API struct {
	Media    *media.Media
	Menu     *menu.Menu
	Template *message.Template
	User     *user.User
	Account  *account.Account

	*Ev

	Handlers []gin.HandlerFunc
	// contains filtered or unexported fields
}

func New

func New(c *Config) *API

func (*API) AttachToGin

func (w *API) AttachToGin(r *gin.Engine)

attach route to a gin

func (*API) Run

func (w *API) Run(addr ...string) error

default instance

func (*API) SetEventHandler

func (w *API) SetEventHandler(handler Handler) Unsubscribe

func (*API) SetMessageHandler

func (w *API) SetMessageHandler(handler Handler) Unsubscribe

type ArticleItem

type ArticleItem struct {
	Title       string `xml:"Title"`
	Description string `xml:"Description"`
	PicURL      string `xml:"PicUrl"`
	URL         string `xml:"Url"`
}

type Articles

type Articles struct {
	Items []ArticleItem `xml:"item"`
}

func (Articles) Type

func (Articles) Type() string

type Config

type Config struct {
	//basic config
	AppID     string
	AppSecret string
	AppToken  string

	//message encode
	AesEncodeKey string

	//server callback address
	Callback string

	//request timeout
	Timeout time.Duration

	Debug bool
}

type ErrorWrapper

type ErrorWrapper []func() error

func (*ErrorWrapper) Add

func (e *ErrorWrapper) Add(f func() error) *ErrorWrapper

func (*ErrorWrapper) Run

func (e *ErrorWrapper) Run() error

type Ev

type Ev struct {
	// contains filtered or unexported fields
}

func (*Ev) Off

func (e *Ev) Off(event string, handler Handler)

取消订阅

func (*Ev) On

func (e *Ev) On(event string, handler Handler) Unsubscribe

添加订阅

type Handler

type Handler func(msg MessageReceive) MessageReply

type Image

type Image struct {
	MediaId string `xml:"MediaId"`
}

func (Image) Type

func (Image) Type() string

type Message

type Message interface {
	Type() string
}

type MessageHandler

type MessageHandler func(m *MessageReceive) MessageReply

type MessageReceive

type MessageReceive struct {
	//I do not know what are these for, just leave it untouched
	XMLName struct{} `xml:"xml"`
	Text    string   `xml:",chardata"`

	MsgId int64 `xml:"MsgId"`

	//MsgType: text
	Content string `xml:"Content"`
	//below types consist of it
	MediaId string `xml:"MediaId"`
	//MsgType: image
	PicUrl string `xml:"PicUrl"`

	//MsgType: voice
	Format      string `xml:"Format"`      //amr, speex
	Recognition string `xml:"Recognition"` //available when voice recognition is on

	//MsgType: video, shortvideo
	ThumbMediaId string `xml:"ThumbMediaId"`

	//MsgType: location
	LocationX string `xml:"Location_X"`
	LocationY string `xml:"Location_Y"`
	Scale     string `xml:"Scale"`
	Label     string `xml:"Label"`

	//MsgType: link
	Title       string `xml:"Title"`
	Description string `xml:"Description"`
	URL         string `xml:"Url"`

	///////////////////////////
	//MsgType: event
	Event string `xml:"Event"` //subscribe, unsubscribe

	//Event: subscript(first time to subscribe), SCAN(has subscribed)
	//Event: CLICK, VIEW
	EventKey string `xml:"EventKey"`
	Ticket   string `xml:"Ticket"`

	//Event: LOCATION(upload position event)
	Latitude  string `xml:"Latitude"`
	Longitude string `xml:"Longitude"`
	Precision string `xml:"Precision"`
	// contains filtered or unexported fields
}

func (MessageReceive) IsEvent

func (m MessageReceive) IsEvent() bool

func (MessageReceive) Type

func (m MessageReceive) Type() string

type MessageReply

type MessageReply interface {
	Type() string
}

type Music

type Music struct {
	Title       string `xml:"Title"`
	Description string `xml:"Description"`
	MusicURL    string `xml:"MusicUrl"`
	HqURL       string `xml:"HQMusicUrl"`
	ThumbID     string `xml:"ThumbMediaId"`
}

func (Music) Type

func (Music) Type() string

type Text

type Text struct {
	Content string `xml:"Content"`
}

func (Text) MarshalXML

func (t Text) MarshalXML(e *xml.Encoder, start xml.StartElement) error

func (Text) Type

func (Text) Type() string

type Unsubscribe

type Unsubscribe func()

type Video

type Video struct {
	MediaID     string `xml:"MediaId"`
	Title       string `xml:"Title"`
	Description string `xml:"Description"`
}

func (Video) Type

func (Video) Type() string

type Voice

type Voice struct {
	MediaID string `xml:"MediaId"`
}

func (Voice) Type

func (Voice) Type() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL