From 5a631356a34aa4b25fb8a66b988953e720ddf89c Mon Sep 17 00:00:00 2001 From: eatMoreApple <15055461510@163.com> Date: Thu, 24 Jun 2021 08:18:03 +0800 Subject: [PATCH] add docs --- .gitignore | 1 + Makefile | 20 ++ doc/doc.md | 514 -------------------------------------- make.bat | 35 +++ source/bot.md | 268 ++++++++++++++++++++ source/conf.py | 64 +++++ source/index.rst | 24 ++ source/message.md | 365 +++++++++++++++++++++++++++ source/user.md | 618 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1395 insertions(+), 514 deletions(-) create mode 100644 Makefile delete mode 100644 doc/doc.md create mode 100644 make.bat create mode 100644 source/bot.md create mode 100644 source/conf.py create mode 100644 source/index.rst create mode 100644 source/message.md create mode 100644 source/user.md diff --git a/.gitignore b/.gitignore index 474488e..a053968 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ # Dependency directories (remove the comment below to include it) # vendor/ .idea +build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/doc.md b/doc/doc.md deleted file mode 100644 index 8f19c2a..0000000 --- a/doc/doc.md +++ /dev/null @@ -1,514 +0,0 @@ -## openwechat - - - -### 安装 - -```shell -go get github.com/eatMoreApple/openwechat -``` - - - -### 用户登陆 - -#### 创建Bot对象 - -登陆之前需要先创建`Bot`对象来登录 - -```go -bot := openwechat.DefaultBot() - -// 注册消息处理函数 -bot.MessageHandler = func(msg *openwechat.Message) { - if msg.IsText() { - fmt.Println("你收到了一条新的文本消息") - } -} -// 注册登陆二维码回调 -bot.UUIDCallback = openwechat.PrintlnQrcodeUrl -``` - - - -#### 普通登陆 - -每次运行程序需要重新扫码登录 - -```go -bot.Login() -``` - - - -#### 热登陆 - -单位时间内运行程序不需要重新扫码登录,直到用户主动退出导致凭证信息失效 - -```go -storage := openwechat.NewJsonFileHotReloadStorage("storage.json") -bot.HotLogin(storage) -``` - - - -#### Desktop模式 - -`Desktop`可突破部分用户的登录限制,如果普通登陆不上,可尝试使用该模式 - -```go -bot := openwechat.DefaultBot(openwechat.Desktop) -``` - - - -### 消息处理 - -可通过绑定在`Bot`上的消息回调函数来对消息进行定制化处理 - -```go -bot := openwechat.DefaultBot(openwechat.Desktop) - -messageHandle := func(msg *openwechat.Message) { - if msg.IsText() { - fmt.Println("你收到了一条新的文本消息") - } -} - -// 注册消息处理函数 -bot.MessageHandler = messageHandle -``` - - - -#### 回复文本消息 - -```go -msg.ReplyText("test message") -``` - - - -#### 回复图片消息 - -```go -file, _ := os.Open("test.png") -defer file.Close() -msg.ReplyImage(file) -``` - - - -#### 回复文件消息 - -```go -file, _ := os.Open("your file name") -defer file.Close() -msg.ReplyFile(file) -``` - - - -#### 获取消息的发送者 - -```go -sender, err := msg.Sender() -``` - - - -#### 获取消息的接受者 - -```go -receiver, err := msg.SenderInGroup() -``` - - - -#### 判断消息是否由好友发送 - -```go -msg.IsSendByFriend() // bool -``` - - - -#### 判断消息是否由群组发送 - -```go -msg.IsSendByGroup() // bool -``` - - - -#### 判断消息类型 - -```go -msg.IsText() // 是否为文本消息 -msg.IsPicture() // 是否为图片消息 -msg.IsVoice() // 是否为语音消息 -msg.IsVideo() // 是否为视频消息 -msg.IsCard() // 是否为名片消息 -msg.IsFriendAdd() // 是否为添加好友消息 -msg.IsRecalled() // 是否为撤回消息 -msg.IsTransferAccounts() // 判断当前的消息是不是微信转账 -msg.IsSendRedPacket() // 是否发出红包 -msg.IsReceiveRedPacket() // 判断当前是否收到红包 -``` - - - -#### 判断消息是否携带文件 - -```go -msg.HasFile() bool -``` - - - -#### 获取消息中的文件 - -自行读取response处理 - -```go -resp, err := msg.GetFile() // *http.Response, error -``` - - - -#### Card消息 - -```go -card, err := msg.Card() -if err == nil { - fmt.Println(card.Alias) // 获取名片消息中携带的微信号 -} -``` - - - -#### 同意好友请求 - -该方法只在消息类型为`IsFriendAdd`为`true`的时候生效 - -```go -msg.Agree() - -msg.Agree("我同意了你的好友请求") -``` - - - -#### Set - -从消息上下文中设置值(协成安全) - -```go -msg.Set("hello", "world") -``` - - - -#### Get - -从消息上下文中获取值(协成安全) - -```go -value, exist := msg.Get("hello") -``` - - - -#### 消息分发 - -```go -type MessageDispatcher interface { - Dispatch(msg *Message) -} - -func DispatchMessage(dispatcher MessageDispatcher) func(msg *Message) { - return func(msg *Message) { dispatcher.Dispatch(msg) } -} -``` - -消息分发处理接口跟 DispatchMessage 结合封装成 MessageHandler - - - -##### MessageMatchDispatcher - -> ​ MessageMatchDispatcher impl MessageDispatcher interface - -###### example - -```go -dispatcher := NewMessageMatchDispatcher() -dispatcher.OnText(func(msg *Message){ - msg.ReplyText("hello") -}) -bot := DefaultBot() -bot.MessageHandler = DispatchMessage(dispatcher) -``` - -###### 注册消息处理函数 - -```go -dispatcher.RegisterHandler(matchFunc matchFunc, handlers ...MessageContextHandler) -``` - -`matchFunc`为匹配函数,返回为`true`代表执行对应的`MessageContextHandler` - - - -###### 注册文本消息处理函数 - -```go -dispatcher.OnText(handlers ...MessageContextHandler) -``` - - - -###### 注册图片消息的处理函数 - -```go -dispatcher.OnImage(handlers ...MessageContextHandler) -``` - - - -###### 注册语音消息的处理函数 - -```go -dispatcher.OnVoice(handlers ...MessageContextHandler) -``` - - - -###### 注册消息类型为`好友添加`的处理函数 - -```go -dispatcher.OnFriendAdd(handlers ...MessageContextHandler) -``` - - - -###### 注册消息类型为`Card`的处理函数 - -```go -dispatcher.OnCard(handlers ...MessageContextHandler) -``` - - - - - -### 登陆用户 - -登陆成功后调用 - -```go -self, err := bot.GetCurrentUser() -``` - - - -#### 文件传输助手 - -```go -fileHelper, err := self.FileHelper() -``` - - - -#### 好友列表 - -```go -friends, err := self.Friends() -``` - - - -#### 群组列表 - -注:群组列表只显示手机端微信:通讯录:群聊里面的群组,若想将别的群组加入通讯录,点击群组,设置为`保存到通讯录`即可(安卓机) - -```go -groups, err := self.Groups() -``` - - - -#### 公众号列表 - -```go -mps, err := self.Mps() -``` - - - -### 好友对象 - -好友对象通过调用`self.Friends()`获取 - -```go -friends, err := self.Friends() -``` - - - -#### 搜索好友 - -根据条件查找好友,返回好友列表 - -```go -friends.SearchByRemarkName(1, "多吃点苹果") // 根据备注查找, limit 参数为限制查找的数量 - -friends.SearchByNickName(1, "多吃点苹果") // 根据昵称查找 - -friends.Search(openwechat.ALL, func(friend *openwechat.Friend) bool { - return friend.Sex == openwechat.MALE -}) // 自定义条件查找(可多个条件) -``` - - - -#### 获取第一个好友 - -返回好友对象 - -```go -firend := friends.First() // 可能为nil -``` - - - -#### 获取最后一个好友 - -```go -firend := friends.Last() // 可能为nil -``` - - - -#### 好友数量统计 - -```go -count := friends.Count() -``` - - - -#### 发送消息 - -```go -friend := friends.First() -if friend != nil { - friend.SendText("hello") - // SendFile 发送文件 - // SendImage 发送图片 -} -``` - - - -#### 设置备注消息 - -```go -friend := friends.First() -if friend != nil { - friend.SetRemarkName("remark name") -} -``` - - - -#### 拉入群聊 - -```go -groups, _ := self.Groups() - -friend := friends.First() // ensure it won't be bil - -friend.AddIntoGroup(groups...) -``` - - - - - -### 群组对象 - -好友对象通过调用`self.Groups()`获取 - -```go -groups, err := self.Groups() -``` - - - -#### 发送消息 - -```go -group := groups.First() -if group != nil { - group.SendText("hello") - // SendFile 发送文件 - // SendImage 发送图片 -} -``` - - - -#### 获取群员列表 - -```go -group := groups.First() -if group != nil { - members, err := group.Members() -} -``` - - - -#### 拉好友入群 - -```go -group := groups.First() // ensure it won't be bil - -group.AddFriendsIn(friend1, friend2) -``` - - - -### Emoji - -emoji表情可当做一个文本消息发送,具体见`openwechat.Emoji` - -```go -friend.SendText(openwechat.Emoji.Doge) // [旺柴] -``` - - - -#### 格式化带emoji表情的昵称 - -```go -fmt.Println(openchat.FormatEmoji(`多吃点苹果`)) -``` - - - -**更多功能请在源码中探索** - -```go -// TODO ADD MORE SUPPORT -``` - - - - - - - - - diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..9534b01 --- /dev/null +++ b/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/source/bot.md b/source/bot.md new file mode 100644 index 0000000..ba2dd89 --- /dev/null +++ b/source/bot.md @@ -0,0 +1,268 @@ +# Bot对象 + +`Bot`对象负责处理网络请求和消息回调以及登录登出的用户行为,一个`Bot`对应一个登录的微信号。 + + + +### 创建Bot对象 + +在登录微信之前需要创建一个`Bot`对象。 + +```go +bot := openwechat.DefaultBot() +``` + +使用默认的构造方法`DefaultBot`来创建一个`Bot`对象。 + + + +### 登陆二维码回调 + +但仅仅是这样我们依然无法登录, 我们平常登录微信都需要用手机扫描二维码登录,所以我们得知道需要扫描哪张二维码,最后还需要为它绑定一个登录二维码的回调函数。 + +```go +// 注册登陆二维码回调 +bot.UUIDCallback = openwechat.PrintlnQrcodeUrl +``` + +`PrintlnQrcodeUrl`这个函数做的事情很简单,就是将我们需要扫码登录的二维码链接打印打控制台上,这样我们就知道去扫描哪张二维码登录了。 + +可以自定义`UUIDCallback`来实现自己的逻辑。 + +如:将登录的二维码打印到控制台。 + +```go +package main + +import ( + "fmt" + "github.com/skip2/go-qrcode" + "github.com/eatMoreApple/openwechat" +) + +func ConsoleQrCode(uuid string) { + q, _ := qrcode.New("https://login.weixin.qq.com/l/"+uuid, qrcode.Low) + fmt.Println(q.ToString(true)) +} + +func main() { + bot := openwechat.DefaultBot() + bot.UUIDCallback = ConsoleQrCode + bot.Login() +} +``` + +虽然最终打印的结果肉眼看上去有点不尽人意,但手机也还能够识别... + + + +### 登录 + + + +#### 普通登录 + +上面的准备工作做完了,下面就可以登录,直接调用`Bot.Login`即可。 + +```go +bot.Login() +``` + +登录会返回一个`error`,即登录失败的原因。 + + + +#### 热登录 + +每次执行普通登录都需要扫码,在调试一些功能的时候需要反复编译,这样会很麻烦。 + +热登录可以只用扫码一次,后面在单位时间内重启程序也不会再要求扫码 + +```go +// 创建热存储容器对象 +reloadStorage := openwechat.NewJsonFileHotReloadStorage("storage.json") + +// 执行热登录 +bot.HotLogin(reloadStorage) +``` + +`HotLogin`需要接受一个`热存储容器对象`来调用。`热存储容器`用来保存登录的会话信息,本质是一个接口类型 + +```go +// 热登陆存储接口 +type HotReloadStorage interface { + GetHotReloadStorageItem() HotReloadStorageItem // 获取HotReloadStorageItem + Dump(item HotReloadStorageItem) error // 实现该方法, 将必要信息进行序列化 + Load() error // 实现该方法, 将存储媒介的内容反序列化 +} +``` + +`NewJsonFileHotReloadStorage`简单实现了该接口,它采用`JSON`的方式存储会话信息。 + +实现这个接口,实现你自己的存储方式。 + + + +### 扫码回调 + +在pc端微信上我们打开手机扫码进行登录的时候,只扫描二维码,但不点击确认,微信上也能够显示当前扫码用户的头像,并提示用户登录确认。 + +通过对`bot`对象绑定扫码回调即可实现对应的功能。 + +```go +bot.ScanCallBack = func(body []byte) { fmt.Println(string(body)) } +``` + +用户扫码后,body里面会携带用户的头像信息。 + +**注**:绑定扫码回调须在登录前执行。 + + + +### 登录回调 + +对`bot`对象绑定登录 + +```go +bot.LoginCallBack = func(body []byte) { + fmt.Println(string(body)) + // to do your business +} +``` + +登录回调的参数就是当前客户端需要跳转的链接,可以不用关心它。 + +登录回调函数可以当做一个信号处理,表示当前扫码登录的用户已经确认登录。 + + + +### 桌面模式 + +`DefaultBot`默认是与网页版微信进行交互,部分用户的网页版wx可能已经被限制登录了。 + +这时候可以尝试使用`桌面模式`进行登录。 + +```go +bot := openwechat.DefaultBot(openwechat.Desktop) +``` + +别的逻辑不用改,直接在创建bot的时候加一个参数就行了。 + +如果桌面模式还登录不上,请检查你的微信号是不是刚刚申请。 + + + +### 消息处理 + +在用户登录后需要实时接受微信发送过来的消息。 + +很简单,给`BOT`对象绑定一个消息回调函数就行了。 + +```go +// 注册消息处理函数 +bot.MessageHandler = func(msg *openwechat.Message) { + if msg.IsText() && msg.Content == "ping" { + msg.ReplyText("pong") + } +} +``` + +所有接受的消息都通过`Bot.MessageHandler`来处理。 + +基于这个回调函数,可以对消息进行多样化处理 + +```go +dispatcher := openwechat.NewMessageMatchDispatcher() + +// 只处理消息类型为文本类型的消息 +dispatcher.OnText(func(msg *Message){ + msg.ReplyText("hello") +}) + +// 注册消息回调函数 +bot.MessageHandler = openwechat.DispatchMessage(dispatcher) +``` + +`openwechat.DispatchMessage`会将消息转发给`dispatcher`对象处理 + + + +#### MessageMatchDispatcher + +##### 构造方法 + +```go +openwechat.NewMessageMatchDispatcher() +``` + +##### 注册消息处理函数 + +```go +// 注册消息处理函数 +func (m *MessageMatchDispatcher) RegisterHandler(matchFunc matchFunc, handlers ...MessageContextHandler) + + +// 消息匹配函数 +type matchFunc func(*Message) bool + + +// 消息处理函数 +type MessageContextHandler func(ctx *MessageContext) +``` + +`matchFunc`:接受当前收到的消息对象,并返回`bool`值,返回`true`则表示处理当前的消息 + +`RegisterHandler`:接受一个`matchFunc`和不定长的消息处理函数,如果`matchFunc`返回为`true`,则表示运行对应的处理函数组。 + + + +##### OnText + +注册处理消息类型为文本类型的消息 + +```go +func (m *MessageMatchDispatcher) OnText(handlers ...MessageContextHandler) +``` + +##### OnImage + +注册处理消息类型为图片类型的消息 + +```golang +func (m *MessageMatchDispatcher) OnImage(handlers ...MessageContextHandler) +``` + +##### OnVoice + +注册处理消息类型为语言类型的消息 + +```go +func (m *MessageMatchDispatcher) OnVoice(handlers ...MessageContextHandler) +``` + +##### [更多请点击查看源码](https://github.com/eatMoreApple/openwechat/blob/main/message_handle.go) + + + +### 获取登录后的用户 + +```go +self, err := bot.GetCurrentUser() +``` + +**注**:该方法在登录成功后调用 + +[详见`Self`对象](./user.md) + + + + + +### 阻塞主程序 + +```go +bot.Block() +``` + +该方法会一直阻塞,直到用户主动退出或者网络请求发生错误 + diff --git a/source/conf.py b/source/conf.py new file mode 100644 index 0000000..a47a577 --- /dev/null +++ b/source/conf.py @@ -0,0 +1,64 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'openwechat' +copyright = '2021, eatMoreApple' +author = 'eatMoreApple' + +# The full version, including alpha/beta/rc tags +release = 'v1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'recommonmark', + 'sphinx_markdown_tables' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'zh_CN' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] \ No newline at end of file diff --git a/source/index.rst b/source/index.rst new file mode 100644 index 0000000..0419de6 --- /dev/null +++ b/source/index.rst @@ -0,0 +1,24 @@ +.. openwechat documentation master file, created by + sphinx-quickstart on Sun Jun 20 09:35:19 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to openwechat's documentation! +====================================== + +.. toctree:: + :maxdepth: 2 + + + bot + user + message + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` \ No newline at end of file diff --git a/source/message.md b/source/message.md new file mode 100644 index 0000000..3d7f9fa --- /dev/null +++ b/source/message.md @@ -0,0 +1,365 @@ +# 消息 + + + +### 接受消息 + +被动接受的消息对象,由微信服务器发出 + +消息对象通过绑定在`bot`上的消息回调函数获取 + +```go +bot.MessageHandler = func(msg *openwechat.Message) { + if msg.IsText() && msg.Content == "ping" { + msg.ReplyText("pong") + } +} +``` + +以下简写为`msg` + + + +#### 消息内容 + +```go +msg.Content // 获取消息内容 +``` + +通过访问`Content`属性可直接获取消息内容 + +由于消息分为很多种类型,它们都共用`Content`属性。一般当消息类型问文本类型的时候,我们才会去访问`Content`属性。 + + + +#### 消息类型判断 + +下面的判断消息类型的方法均返回`bool`值 + +##### 文本消息 + +```go +msg.IsText() +``` + +##### 图片消息 + +```go +msg.IsPicture() +``` + +##### 位置消息 + +```go +msg.IsMap() +``` + +##### 语音消息 + +```go +msg.IsVoice() +``` + +##### 添加好友请求 + +```go +msg.IsFriendAdd() +``` + +##### 名片消息 + +```go +msg.IsCard() +``` + +##### 视频消息 + +```go +msg.IsVideo() +``` + +##### 是否被撤回 + +```go +msg.IsRecalled() +``` + +##### 系统消息 + +```go +msg.IsSystem() +``` + +##### 收到微信转账 + +```go +msg.IsTransferAccounts() +``` + +##### 发出红包(自己发出) + +```go +msg.IsSendRedPacket() +``` + +##### 收到红包 + +```go +msg.IsReceiveRedPacket() +``` + +但是不能领取! + + + +#### 获取消息的发送者 + +```go +sender, err := msg.Sender() +``` + +如果是群聊消息,该方法返回的是群聊对象(需要自己将`User`转换为`Group`对象) + + + +#### 获取消息的接受者 + +```go +receiver, err := msg.Receiver() +``` + + + +#### 获取消息在群里面的发送者 + +```go +sender, err := msg.SenderInGroup() +``` + +获取群聊中具体发消息的用户,前提该消息必须来自群聊。 + + + +#### 是否由自己发送 + +```go +msg.IsSendBySelf() +``` + + + +#### 消息是否由好友发出 + +```go +msg.IsSendByFriend() +``` + + + +#### 消息是否由群聊发出 + +```go +msg.IsSendByGroup() +``` + + + +#### 回复文本消息 + +```go +msg.ReplyText("hello") +``` + + + +#### 回复图片消息 + +```go +img, _ := os.Open("your file path") +defer img.Close() +msg.ReplyImage(img) +``` + + + +#### 回复文件消息 + +```go +file, _ := os.Open("your file path") +defer file.Close() +msg.ReplyFile(file) +``` + + + +#### 获取消息里的其他信息 + +##### 名片消息 + +```go +card, err := msg. Card() +``` + +该方法调用的前提为`msg.IsCard()`返回为`true` + +名片消息可以获取该名片中的微信号 + +```go +alias := card.Alias +``` + +`card`结构 + +```go +// 名片消息内容 +type Card struct { + XMLName xml.Name `xml:"msg"` + ImageStatus int `xml:"imagestatus,attr"` + Scene int `xml:"scene,attr"` + Sex int `xml:"sex,attr"` + Certflag int `xml:"certflag,attr"` + BigHeadImgUrl string `xml:"bigheadimgurl,attr"` + SmallHeadImgUrl string `xml:"smallheadimgurl,attr"` + UserName string `xml:"username,attr"` + NickName string `xml:"nickname,attr"` + ShortPy string `xml:"shortpy,attr"` + Alias string `xml:"alias,attr"` // Note: 这个是名片用户的微信号 + Province string `xml:"province,attr"` + City string `xml:"city,attr"` + Sign string `xml:"sign,attr"` + Certinfo string `xml:"certinfo,attr"` + BrandIconUrl string `xml:"brandIconUrl,attr"` + BrandHomeUr string `xml:"brandHomeUr,attr"` + BrandSubscriptConfigUrl string `xml:"brandSubscriptConfigUrl,attr"` + BrandFlags string `xml:"brandFlags,attr"` + RegionCode string `xml:"regionCode,attr"` +} +``` + + + +##### 获取已撤回的消息 + +```go +revokeMsg, err := msg.RevokeMsg() +``` + +该方法调用成功的前提是`msg.IsRecalled()`返回为`true` + +撤回消息的结构 + +```go +type RevokeMsg struct { + SysMsg xml.Name `xml:"sysmsg"` + Type string `xml:"type,attr"` + RevokeMsg struct { + OldMsgId int64 `xml:"oldmsgid"` + MsgId int64 `xml:"msgid"` + Session string `xml:"session"` + ReplaceMsg string `xml:"replacemsg"` + } `xml:"revokemsg"` +} +``` + + + +#### 同意好友请求 + +```go +msg.Agree() +// msg.Agree("我同意了") +``` + +该方法调用成功的前提是`msg.IsFriendAdd()`返回为`true` + + + +#### 设置消息的上下文 + +用于多个消息处理函数之间的通信,并且是协程安全的。 + +##### 设置值 + +```go +msg.Set("hello", "world") +``` + +##### 获取值 + +```go +value, exist := msg.Get("hello") +``` + + + + + +### 已发送消息 + +已发送消息指当前用户发送出去的消息 + +每次调用发送消息的函数都会返回一个`SentMessage`对象 + +如 + +```go +sentMsg, err := msg.ReplyText("hello") // 通过回复消息获取 +// sentMsg, err := friend.SendText("hello") // 向好友对象发送消息获取 +// and so on +``` + + + +#### 撤回消息 + +撤回刚刚发送的消息,撤回消息的有效时间为2分钟,超过了这个时间则无法撤回 + +```go +sentMsg.Revoke() +``` + + + +#### 转发给好友 + +```go +sentMsg.ForwardToFriends(friend1, friend2) +``` + +将刚发送的消息转发给好友 + + + +#### 转发给群聊 + +```go +sentMsg.ForwardToGroups(group1, group2) +``` + +将刚发送的消息转发给群聊 + + + + + +### Emoji表情 + +openwechat提供了微信全套`emoji`表情的支持 + +`emoji`表情全部维护在`openwechat.Emoji`结构体上 + +emoji表情可以通过发送`Text`类型的函数发送 + +如 + +```go +firend.SendText(openwechat.Emoji.Doge) // 发送狗头表情 +msg.ReplyText(openwechat.Emoji.Awesome) // 发送666的表情 +``` + + + + + + + diff --git a/source/user.md b/source/user.md new file mode 100644 index 0000000..669bc04 --- /dev/null +++ b/source/user.md @@ -0,0 +1,618 @@ +# 用户 + +抽象的用户结构: 好友 群组 公众号 + +```go +type User struct { + Uin int + HideInputBarFlag int + StarFriend int + Sex int + AppAccountFlag int + VerifyFlag int + ContactFlag int + WebWxPluginSwitch int + HeadImgFlag int + SnsFlag int + IsOwner int + MemberCount int + ChatRoomId int + UniFriend int + OwnerUin int + Statues int + AttrStatus int + Province string + City string + Alias string + DisplayName string + KeyWord string + EncryChatRoomId string + UserName string + NickName string + HeadImgUrl string + RemarkName string + PYInitial string + PYQuanPin string + RemarkPYInitial string + RemarkPYQuanPin string + Signature string + + MemberList Members + + Self *Self +} +``` + +`User`结构体的属性,部门信息可以通过它的英文名知道它所描述的意思。 + +其中要注意的是`UserName`这个属性。 + +`UserName`是当前会话唯一的身份标识,且仅作用于当前会话。下次登录该属性值则会被改变。 + +不同用户的`UserName`的值是不一样的,可以通过该字段来区分不同的用户。 + + + + + +#### 获取头像 + +下载群聊、好友、公众号的头像,具体哪种类型根据当前`User`的抽象类型来判断 + +```go +func (u *User) SaveAvatar(filename string) error +``` + + + +#### 详情 + +获取制定用户的详细信息, 返回新的用户对象 + +```go +func (u *User) Detail() (*User, error) +``` + +#### 判断是否为好友 + +```go +func (u *User) IsFriend() bool +``` + +#### 判断是否为群组 + +```go +func (u *User) IsGroup() bool +``` + +#### 判断是否为公众号 + +```go +func (u *User) IsMP() bool +``` + + + +## 当前登录用户 + +当前扫码登录的用户对象 + +`Self`拥有上面`User`的全部属性和方法 + +通过调用`bot.GetCurrentUser`来获取 + +```go +self, err := bot.GetCurrentUser() +``` + + + +#### 获取当前用户的所有的好友 + +```go +firends, err := self.Friends() // self.Friends(true) +``` + +`Friends`:可接受`bool`值来判断是否获取最新的好友 + + + +#### 获取当前用户的所有的群组 + +```go +groups, err := self.Groups() // self.Groups(true) +``` + +注:群组列表只显示手机端微信:通讯录:群聊里面的群组,若想将别的群组加入通讯录,点击群组,设置为`保存到通讯录`即可(安卓机) + +`Groups`:可接受`bool`值来判断是否获取最新的群组 + + + +#### 获取当前用户所有的公众号 + +```go +mps, err := self.Mps() // self.Mps(true) +``` + +`Mps`:可接受`bool`值来判断是否获取最新的公众号 + + + +#### 获取文件传输助手 + +```go +fh, err := self.FileHelper() +``` + + + +#### 发送文本给好友 + +```go +func (s *Self) SendTextToFriend(friend *Friend, text string) (*SentMessage, error) +``` + +```go +firends, err := self.Friends() + +if err != nil { + return +} + +if friends.Count() > 0 { + self.SendTextToFriend(friends.First(), "hello") + // 或者 + // friends.First().SendText("hello") +} +``` + +返回的`SentMessage`对象可用于消息撤回 + + + +#### 发送图片消息给好友 + +```go +// 确保获取了有效的好友对象 +img, _ := os.Open("your file path") +defer img.Close() +self.SendImageToFriend(friend, img) +// 或者 +// friend.SendImage(img) +``` + + + +#### 发送文件给好友 + +```go +file, _ := os.Open("your file path") +defer img.Close() +self.SendFileToFriend(friend, file) +// 或者 +// friend.SendFile(img) +``` + + + + + +#### 给好友设置备注 + +```go +self.SetRemarkNameToFriend(friend, "你的备注") +// 或者 +// friend.SetRemarkName("你的备注") +``` + + + +#### 发送文本消息给群组 + +```go +self.SendTextToGroup(group, "hello") +// group.SendText("hello") +``` + + + +#### 发送图片给群组 + +```go +img, _ := os.Open("your file path") +defer img.Close() +self.SendImageToGroup(group, img) +// group.SendImage(img) +``` + + + +#### 发送文件给群组 + +```go +file, _ := os.Open("your file path") +defer file.Close() +self.SendFileToGroup(group, file) +// group.SendFile(file) +``` + + + +#### 消息撤回 + +```go +sentMesaage, _ := friend.SendText("hello") +self.RevokeMessage(sentMesaage) +// sentMesaage.Revoke() +``` + +只要是`openwechat.SentMessage`对象都可以在2分钟之内撤回 + + + +#### 消息转发给多个好友 + +```go +sentMesaage, _ := friend.SendText("hello") + +self.ForwardMessageToFriends(sentMesaage, friends1, friends2) + +// sentMesaage.ForwardToFriends(friends1, friends2) +``` + + + +#### 转发消息给多个群组 + +```go +sentMesaage, _ := friend.SendText("hello") + +self.ForwardMessageToGroups(sentMesaage, group1, group2) + +// sentMesaage.ForwardToGroups(friends1, friends2) +``` + + + +#### 拉多个好友入群 + +```go +self.AddFriendsIntoGroup(group, friend1, friend2) // friend1, friend2 为不定长参数 + +// group.AddFriendsIn(friend1, friend2) +``` + +最好自己是群主,这样成功率会高一点。 + + + +#### 拉单个好友进多个群 + +```go +self.AddFriendIntoManyGroups(friend, group1, group2) // group1, group2 为不定长参数 + +// friend.AddIntoGroup(group1, group2) +``` + + + +#### 从群聊中移除用户 + +```go +member, err := group.Members() + +self.RemoveMemberFromGroup(group, member[0], member[1]) + +// group.RemoveMembers(member[:1]) +``` + +注:这个接口已经被微信官方禁用了,现在已经无法使用。 + + + +## 好友 + + + +### 好友列表 + +```go +type Friends []*Friend +``` + +#### 获取当前用户的好友列表 + +```go +firends, err := self.Friends() +``` + +注:此时获取到的`friends`为好友组,而非好友。好友组是当前wx号所有好友的集合。 + + + +#### 统计好友个数 + +```go +firends.Count() // => int +``` + + + +#### 自定义条件查找好友 + +```go +func (f Friends) Search(limit int, condFuncList ...func(friend *Friend) bool) (results Friends) +``` + +* `limit`:限制查找的个数 +* `condFuncList`:不定长参数,查找的条件,必须全部满足才算匹配上 +* `results`:返回的满足条件的好友组 + +```go +// 例:查询昵称为eatmoreapple的1个好友 +sult := firends.Search(1, func(friend *openwechat.Friend) bool {return friend.NickName == "eatmoreapple"}) +``` + + + +#### 根据昵称查找好友 + +```go +func (f Friends) SearchByNickName(limit int, nickName string) (results Friends) +``` + +* `limit`:为限制好友查找的个数 +* `nickname`:查询指定昵称的好友 +* `results`:返回满足条件的好友组 + + + +#### 根据备注查找好友 + +```go +func (f Friends) SearchByRemarkName(limit int, remarkName string) (results Friends) +``` + +* `limit`:为限制好友查找的个数 +* `remarkname`:查询指定备注的好友 +* `results`:返回满足条件的好友组 + + + +#### 群发文本消息 + +```go +func (f Friends) SendText(text string, delay ...time.Duration) error +``` + +* `text`:文本消息的内容 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +#### 群发图片 + +```go +func (f Friends) SendImage(file *os.File, delay ...time.Duration) error +``` + +* `file`:`os.file`类型,即发送图片的文件指针 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +#### 群发文件 + +```go +func (f Friends) SendFile(file *os.File, delay ...time.Duration) error +``` + +* `file`:`os.file`类型,即发送文件的文件指针 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +### 单个好友 + + + +#### 获取好友头像 + +```go +friend.SaveAvatar("avatar.png") +``` + + + +#### 发送文本信息 + +```go +friend.SendText("hello") +``` + + + +#### 发送图片信息 + +```go +img, _ := os.Open("your image path") + +defer img.Close() + +friend.SendImage(img) +``` + + + +#### 发送文件信息 + +```go +file, _ := os.Open("your file path") + +defer file.Close() + +friend.SendFile(file) +``` + + + +#### 设置备注信息 + +```go +friend.SetRemarkName("你的备注") +``` + + + +#### 拉该好友进群 + +```go +friend.AddIntoGroup(group) +``` + + + +## 群组 + +### 群组列表 + +```go +type Groups []*Group +``` + + + +#### 获取所有的群聊 + +```go +groups, err := self.Groups() +``` + +注:该方法在用户成功登陆之后调用 + + + +#### 统计群聊个数 + +```go +groups.Count() // => int +``` + + + +#### 自定义条件查找群聊 + +```go +func (g Groups) Search(limit int, condFuncList ...func(group *Group) bool) (results Groups) +``` + +* `limit`:限制查找的个数 +* `condFuncList`:不定长参数,查找的条件,必须全部满足才算匹配上 +* `results`:返回的满足条件的群聊 + + + +#### 根据群名查找群聊 + +```go +func (g Groups) SearchByNickName(limit int, nickName string) (results Groups) +``` + +* `limit`:限制查找的个数 +* `nickName`:群名称 +* `results`:返回的满足条件的群聊 + + + +#### 群发文本 + +```go +func (g Groups) SendText(text string, delay ...time.Duration) error +``` + +* `text`:文本消息的内容 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +#### 群发图片 + +```go +func (g Groups) SendImage(file *os.File, delay ...time.Duration) error +``` + +* `file`:`os.file`类型,即发送文件的文件指针 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +#### 群发文件 + +```go +func (g Groups) SendFile(file *os.File, delay ...time.Duration) error +``` + +* `file`:`os.file`类型,即发送文件的文件指针 +* `delay`:每次发送消息的间隔(发送消息过快可能会被wx检测到,最好加上间隔时间) + + + +### 单个群聊 + + + +#### 获取群聊头像 + +```go +group.SaveAvatar("group.png") +``` + + + +#### 获取所有的群员 + +```go +members, err := group.Members() +``` + + + +#### 发送文本信息 + +```go +group.SendText("hello") +``` + + + +#### 发送图片信息 + +```go +img, _ := os.Open("your image path") + +defer img.Close() + +group.SendImage(img) +``` + + + +#### 发送文件消息 + +```go +file, _ := os.Open("your file path") + +defer file.Close() + +group.SendFile(file) +``` + + + +#### 拉好友进群 + +```go +group.AddFriendsIn(friend) +``` +