提交 89e7a772 编写于 作者: LinuxSuRen's avatar LinuxSuRen

fixes can not search

上级 32019a32
......@@ -5,9 +5,15 @@ build:
image: build
docker build -t surenpi/jenkins-wechat .
image-alauda: build
docker build -t index.alauda.cn/alaudak8s/jenkins-wechat .
push-image: image
docker push surenpi/jenkins-wechat
push-image-alauda: image-alauda
docker push index.alauda.cn/alaudak8s/jenkins-wechat
image-ubuntu: build
docker build -t surenpi/jenkins-wechat:ubuntu . -f Dockerfile.ubuntu
docker push surenpi/jenkins-wechat:ubuntu
......@@ -20,6 +26,10 @@ update:
kubectl set image deploy/wechat wechat=surenpi/jenkins-wechat
make restart
update-alauda:
kubectl set image deploy/wechat wechat=index.alauda.cn/alaudak8s/jenkins-wechat
make restart
restart:
kubectl scale deploy/wechat --replicas=0
kubectl scale deploy/wechat --replicas=1
\ No newline at end of file
......@@ -11,6 +11,8 @@ import (
"sort"
"strings"
core "github.com/linuxsuren/wechat-backend/pkg"
"github.com/linuxsuren/wechat-backend/pkg/article"
"github.com/linuxsuren/wechat-backend/pkg/config"
"github.com/linuxsuren/wechat-backend/pkg/github"
"github.com/linuxsuren/wechat-backend/pkg/reply"
......@@ -63,45 +65,50 @@ func (we *WeChat) normalRequest(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("welcome aboard WeChat."))
}
func (we *WeChat) wechatRequest(w http.ResponseWriter, r *http.Request) {
func (we *WeChat) wechatRequest(writer http.ResponseWriter, r *http.Request) {
textRequestBody := we.parseTextRequestBody(r)
if textRequestBody != nil {
fmt.Printf("Wechat Service: Recv [%s] msg [%s] from user [%s]!\n",
textRequestBody.MsgType,
textRequestBody.Content,
textRequestBody.FromUserName)
autoReplyInitChains := reply.AutoReplyChains()
fmt.Printf("found [%d] autoReply", len(autoReplyInitChains))
for _, autoReplyInit := range autoReplyInitChains {
if autoReplyInit == nil {
fmt.Printf("found a nil autoReply.")
continue
}
autoReply := autoReplyInit()
if !autoReply.Accept(textRequestBody) {
continue
}
var data []byte
var err error
if data, err = autoReply.Handle(); err != nil {
log.Println("handle auto replay error:", err)
fmt.Printf("going to handle by %s\n", autoReply.Name())
// var data []byte
// var err error
if data, err := autoReply.Handle(); err != nil {
fmt.Printf("handle auto replay error: %v\n", err)
} else if len(data) == 0 {
fmt.Println("response body is empty.")
} else {
fmt.Printf("response:%s\n", data)
fmt.Fprintf(writer, data)
break
}
fmt.Fprintf(w, string(data))
break
}
}
}
func (w *WeChat) parseTextRequestBody(r *http.Request) *reply.TextRequestBody {
func (w *WeChat) parseTextRequestBody(r *http.Request) *core.TextRequestBody {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
return nil
}
fmt.Println(string(body))
requestBody := &reply.TextRequestBody{}
requestBody := &core.TextRequestBody{}
xml.Unmarshal(body, requestBody)
return requestBody
}
var autoReplyInitChains []reply.Init
func main() {
weConfig, err := config.LoadConfig("config/wechat.yaml")
if err != nil {
......@@ -118,21 +125,21 @@ func main() {
weConfig.ServerPort = 8080
}
defaultRM := article.NewDefaultResponseManager()
reply.SetResponseManager(defaultRM)
wechat := WeChat{
Config: weConfig,
}
go func() {
initCheck(weConfig)
defaultRM.InitCheck(weConfig)
}()
createWxMenu()
autoReplyInitChains = make([]reply.Init, 1)
autoReplyInitChains = append(autoReplyInitChains, reply.InitMatchAutoReply)
http.HandleFunc("/", wechat.procRequest)
http.HandleFunc("/status", healthHandler)
http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
github.WebhookHandler(w, r, weConfig, initCheck)
github.WebhookHandler(w, r, weConfig, defaultRM.InitCheck)
})
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", weConfig.ServerPort), nil))
......
package article
import (
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
type ArticleReader struct {
API string
}
func (a *ArticleReader) FetchArticles() (articles []Article, err error) {
var apiURL *url.URL
apiURL, err = url.Parse(a.API)
if err != nil {
return
}
var resp *http.Response
resp, err = http.Get(apiURL.String())
if err != nil {
return
}
var data []byte
data, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
var allArticles []Article
err = json.Unmarshal(data, &allArticles)
for _, article := range allArticles {
if article.Title == "" || article.Description == "" ||
article.URI == "" {
continue
}
articles = append(articles, article)
}
return
}
func (a *ArticleReader) FindByTitle(title string) (articles []Article, err error) {
var allArticles []Article
allArticles, err = a.FetchArticles()
if err != nil {
return
}
for _, article := range allArticles {
if strings.Contains(article.Title, title) {
articles = append(articles, article)
}
}
return
}
package article
import (
"testing"
)
func TestFetchArticles(t *testing.T) {
reader := &ArticleReader{
API: "https://jenkins-zh.github.io/index.json",
}
articles, err := reader.FetchArticles()
if err != nil {
t.Errorf("fetch error %v", err)
} else if len(articles) == 0 {
t.Errorf("fetch zero article")
} else {
for i, article := range articles {
if article.Title == "" || article.Description == "" ||
article.URI == "" {
t.Errorf("article [%d] title, description or uri is empty", i)
}
}
}
ar, err := reader.FindByTitle("行为")
if err != nil {
t.Errorf("%v", err)
}
for _, a := range ar {
t.Errorf("%v", a)
}
}
package main
package article
import (
"fmt"
......@@ -8,8 +8,8 @@ import (
"strings"
core "github.com/linuxsuren/wechat-backend/pkg"
"github.com/linuxsuren/wechat-backend/pkg/config"
"github.com/linuxsuren/wechat-backend/pkg/reply"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/yaml.v2"
)
......@@ -18,7 +18,29 @@ const (
CONFIG = "wechat"
)
func initCheck(weConfig *config.WeChatConfig) {
type ResponseManager interface {
GetResponse(string) (interface{}, bool)
InitCheck(weConfig *config.WeChatConfig)
}
type DefaultResponseManager struct {
ResponseMap map[string]interface{}
}
// NewDefaultResponseManager should always call this method to get a object
func NewDefaultResponseManager() (mgr *DefaultResponseManager) {
mgr = &DefaultResponseManager{
ResponseMap: make(map[string]interface{}, 10),
}
return
}
func (drm *DefaultResponseManager) GetResponse(keyword string) (interface{}, bool) {
res, ok := drm.ResponseMap[keyword]
return res, ok
}
func (drm *DefaultResponseManager) InitCheck(weConfig *config.WeChatConfig) {
var err error
_, err = os.Stat(CONFIG)
......@@ -47,50 +69,47 @@ func initCheck(weConfig *config.WeChatConfig) {
} else {
log.Println("open work tree with git error", err)
os.Remove(CONFIG)
initCheck(weConfig)
drm.InitCheck(weConfig)
}
} else {
log.Println("open dir with git error", err)
os.Remove(CONFIG)
initCheck(weConfig)
drm.InitCheck(weConfig)
}
}
} else {
log.Println("can't get config dir status", err)
if os.RemoveAll(CONFIG) == nil {
initCheck(weConfig)
drm.InitCheck(weConfig)
}
}
if err == nil {
log.Println("going to update the cache.")
update()
drm.update()
}
}
var respMap = make(map[string]interface{})
func responseHandler(yamlContent []byte) {
reps := reply.ResponseBody{}
func (drm *DefaultResponseManager) responseHandler(yamlContent []byte) {
reps := core.ResponseBody{}
err := yaml.Unmarshal(yamlContent, &reps)
if err == nil {
log.Println(reps.MsgType, reps.Keyword, reps)
// reps.MsgType = reps.Kind
switch reps.MsgType {
case "text":
text := reply.TextResponseBody{}
text := core.TextResponseBody{}
yaml.Unmarshal(yamlContent, &text)
respMap[reps.Keyword] = text
drm.ResponseMap[reps.Keyword] = text
case "image":
image := reply.ImageResponseBody{}
image := core.ImageResponseBody{}
yaml.Unmarshal(yamlContent, &image)
respMap[reps.Keyword] = image
drm.ResponseMap[reps.Keyword] = image
case "news":
news := reply.NewsResponseBody{}
news := core.NewsResponseBody{}
yaml.Unmarshal(yamlContent, &news)
respMap[reps.Keyword] = news
drm.ResponseMap[reps.Keyword] = news
default:
log.Println("unknow type", reps.MsgType)
}
......@@ -99,7 +118,7 @@ func responseHandler(yamlContent []byte) {
}
}
func update() {
func (drm *DefaultResponseManager) update() {
root := CONFIG + "/management/auto-reply"
files, err := ioutil.ReadDir(root)
if err != nil {
......@@ -113,13 +132,9 @@ func update() {
content, err := ioutil.ReadFile(root + "/" + file.Name())
if err == nil {
responseHandler(content)
drm.responseHandler(content)
} else {
log.Println("Can't read file ", file.Name())
}
}
}
func getKeywords() map[string]string {
return nil
}
package main
package article
import (
"testing"
core "github.com/linuxsuren/wechat-backend/pkg"
"github.com/stretchr/testify/assert"
)
// func TestInitCheck(t *testing.T) {
// initCheck()
// }
func TestImageResponseBody(t *testing.T) {
yml := `
msgType: image
......@@ -27,7 +24,7 @@ image:
t.Error("Can't find response by keyword: hi.")
}
imageResp, ok := resp.(ImageResponseBody)
imageResp, ok := resp.(core.ImageResponseBody)
if !ok {
t.Error("Get the wrong type, should be ImageResponseBody.")
}
......@@ -55,7 +52,7 @@ articles:
return
}
newsResp, ok := resp.(NewsResponseBody)
newsResp, ok := resp.(core.NewsResponseBody)
if !ok {
t.Error("Get the wrong type, should be NewsResponseBody.")
}
......
package article
type Article struct {
Title string
Description string
URI string
}
// Code generated by MockGen. DO NOT EDIT.
// Source: pkg/article/articles.go
// Package mock_article is a generated GoMock package.
package mock_article
import (
gomock "github.com/golang/mock/gomock"
config "github.com/linuxsuren/wechat-backend/pkg/config"
reflect "reflect"
)
// MockResponseManager is a mock of ResponseManager interface
type MockResponseManager struct {
ctrl *gomock.Controller
recorder *MockResponseManagerMockRecorder
}
// MockResponseManagerMockRecorder is the mock recorder for MockResponseManager
type MockResponseManagerMockRecorder struct {
mock *MockResponseManager
}
// NewMockResponseManager creates a new mock instance
func NewMockResponseManager(ctrl *gomock.Controller) *MockResponseManager {
mock := &MockResponseManager{ctrl: ctrl}
mock.recorder = &MockResponseManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockResponseManager) EXPECT() *MockResponseManagerMockRecorder {
return m.recorder
}
// GetResponse mocks base method
func (m *MockResponseManager) GetResponse(arg0 string) (interface{}, bool) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetResponse", arg0)
ret0, _ := ret[0].(interface{})
ret1, _ := ret[1].(bool)
return ret0, ret1
}
// GetResponse indicates an expected call of GetResponse
func (mr *MockResponseManagerMockRecorder) GetResponse(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResponse", reflect.TypeOf((*MockResponseManager)(nil).GetResponse), arg0)
}
// InitCheck mocks base method
func (m *MockResponseManager) InitCheck(weConfig *config.WeChatConfig) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "InitCheck", weConfig)
}
// InitCheck indicates an expected call of InitCheck
func (mr *MockResponseManagerMockRecorder) InitCheck(weConfig interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitCheck", reflect.TypeOf((*MockResponseManager)(nil).InitCheck), weConfig)
}
......@@ -3,46 +3,53 @@ package reply
import (
"encoding/xml"
"time"
core "github.com/linuxsuren/wechat-backend/pkg"
)
type AutoReply interface {
Accept(request *TextRequestBody) bool
Handle() ([]byte, error)
Accept(request *core.TextRequestBody) bool
Handle() (string, error)
Name() string
}
type Init func() AutoReply
func makeTextResponseBody(fromUserName, toUserName, content string) ([]byte, error) {
textResponseBody := &TextResponseBody{}
func makeTextResponseBody(fromUserName, toUserName string, content string) ([]byte, error) {
textResponseBody := &core.TextResponseBody{}
textResponseBody.FromUserName = fromUserName
textResponseBody.ToUserName = toUserName
textResponseBody.MsgType = "text"
textResponseBody.Content = content
textResponseBody.CreateTime = time.Duration(time.Now().Unix())
return xml.MarshalIndent(textResponseBody, " ", " ")
return marshal(textResponseBody)
}
func makeImageResponseBody(fromUserName, toUserName, mediaID string) ([]byte, error) {
imageResponseBody := &ImageResponseBody{}
imageResponseBody := &core.ImageResponseBody{}
imageResponseBody.FromUserName = fromUserName
imageResponseBody.ToUserName = toUserName
imageResponseBody.MsgType = "image"
imageResponseBody.CreateTime = time.Duration(time.Now().Unix())
imageResponseBody.Image = Image{
imageResponseBody.Image = core.Image{
MediaID: mediaID,
}
return xml.MarshalIndent(imageResponseBody, " ", " ")
return marshal(imageResponseBody)
}
func makeNewsResponseBody(fromUserName, toUserName string, news NewsResponseBody) ([]byte, error) {
newsResponseBody := &NewsResponseBody{}
func makeNewsResponseBody(fromUserName, toUserName string, news core.NewsResponseBody) ([]byte, error) {
newsResponseBody := &core.NewsResponseBody{}
newsResponseBody.FromUserName = fromUserName
newsResponseBody.ToUserName = toUserName
newsResponseBody.MsgType = "news"
newsResponseBody.ArticleCount = 1
newsResponseBody.Articles = Articles{
newsResponseBody.Articles = core.Articles{
Articles: news.Articles.Articles,
}
newsResponseBody.CreateTime = time.Duration(time.Now().Unix())
return xml.MarshalIndent(newsResponseBody, " ", " ")
return marshal(newsResponseBody)
}
func marshal(response interface{}) ([]byte, error) {
return xml.MarshalIndent(response, " ", " ")
}
package reply
import "testing"
func TestXML(t *testing.T) {
data, err := makeTextResponseBody("", "", "")
if err != nil {
t.Errorf("xml error %v", err)
}
t.Errorf("%s", string(data))
}
package reply
import "fmt"
import (
"fmt"
"log"
// MatchAutoReply only reply for match
type MatchAutoReply struct {
ResponseMap map[string]interface{}
Response interface{}
Request *TextRequestBody
core "github.com/linuxsuren/wechat-backend/pkg"
"github.com/linuxsuren/wechat-backend/pkg/article"
)
var responseManager article.ResponseManager
func SetResponseManager(manager article.ResponseManager) {
responseManager = manager
}
func InitMatchAutoReply() AutoReply {
return &MatchAutoReply{}
// MatchAutoReply only reply for match
type MatchAutoReply struct {
Response interface{}
Request *core.TextRequestBody
}
var _ AutoReply = &MatchAutoReply{}
func (m *MatchAutoReply) Name() string {
return "SimpleMatchReply"
}
// Accept consider if it will accept the request
func (m *MatchAutoReply) Accept(request *TextRequestBody) (ok bool) {
func (m *MatchAutoReply) Accept(request *core.TextRequestBody) (ok bool) {
m.Request = request
keyword := request.Content
if "text" != request.MsgType {
fmt.Printf("request is %v\n", request)
if responseManager == nil || "text" != request.MsgType {
log.Printf("responseManager is nil or not support msgType %s", request.MsgType)
return false
}
m.Response, ok = m.ResponseMap[keyword]
m.Response, ok = responseManager.GetResponse(keyword)
return ok
}
// Handle hanlde the request then return data
func (m *MatchAutoReply) Handle() (data []byte, err error) {
func (m *MatchAutoReply) Handle() (string, error) {
resp := m.Response
from := m.Request.FromUserName
to := m.Request.ToUserName
from := m.Request.ToUserName
to := m.Request.FromUserName
var err error
if resp == nil {
err = fmt.Errorf("response is nil")
return "", err
}
fmt.Printf("response %v\n", resp)
if text, ok := resp.(TextResponseBody); ok {
var data []byte
if text, ok := resp.(core.TextResponseBody); ok {
data, err = makeTextResponseBody(from, to, text.Content)
fmt.Printf("data %v\n", string(data))
if err != nil {
err = fmt.Errorf("Wechat Service: makeTextResponseBody error: %v", err)
}
} else if image, ok := resp.(ImageResponseBody); ok {
} else if image, ok := resp.(core.ImageResponseBody); ok {
data, err = makeImageResponseBody(from, to, image.Image.MediaID)
if err != nil {
err = fmt.Errorf("Wechat Service: makeImageResponseBody error: %v", err)
}
} else if news, ok := resp.(NewsResponseBody); ok {
} else if news, ok := resp.(core.NewsResponseBody); ok {
data, err = makeNewsResponseBody(from, to, news)
if err != nil {
err = fmt.Errorf("Wechat Service: makeNewsResponseBody error: %v", err)
}
} else {
err = fmt.Errorf("type error")
err = fmt.Errorf("type error %v", resp)
}
return
return string(data), err
}
func init() {
Register(func() AutoReply {
return &MatchAutoReply{}
})
}
package reply
import "testing"
import (
"testing"
"github.com/golang/mock/gomock"
core "github.com/linuxsuren/wechat-backend/pkg"
mArticle "github.com/linuxsuren/wechat-backend/pkg/mock/article"
)
func TestAccept(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
var reply AutoReply
reply = &MatchAutoReply{}
reply = &MatchAutoReply{
ResponseMap: map[string]interface{}{
"hello": "",
},
}
if reply.Accept(&TextRequestBody{}) {
if reply.Accept(&core.TextRequestBody{}) {
t.Errorf("should not accept")
}
if !reply.Accept(&TextRequestBody{
m := mArticle.NewMockResponseManager(ctrl)
m.EXPECT().GetResponse("hello").
Return(&core.TextResponseBody{}, true)
SetResponseManager(m)
if !reply.Accept(&core.TextRequestBody{
MsgType: "text",
Content: "hello",
}) {
t.Errorf("should accept")
......@@ -23,15 +32,22 @@ func TestAccept(t *testing.T) {
}
func TestHandle(t *testing.T) {
var reply AutoReply
ctrl := gomock.NewController(t)
defer ctrl.Finish()
reply := &MatchAutoReply{}
reply = &MatchAutoReply{
ResponseMap: map[string]interface{}{
"hello": TextResponseBody{},
},
}
m := mArticle.NewMockResponseManager(ctrl)
m.EXPECT().GetResponse("hello").
Return(core.TextResponseBody{
ResponseBody: core.ResponseBody{
MsgType: "text",
},
Content: "hello",
}, true)
if !reply.Accept(&TextRequestBody{
SetResponseManager(m)
if !reply.Accept(&core.TextRequestBody{
MsgType: "text",
Content: "hello",
}) {
t.Errorf("should accept")
......@@ -42,5 +58,7 @@ func TestHandle(t *testing.T) {
t.Errorf("should not error %v", err)
} else if data == nil {
t.Errorf("not have data")
} else if string(data) != "hello" {
t.Errorf("got an error content: %s", string(data))
}
}
package reply
var autoReplyInitChains []Init
// Register add an implement of AutoReply
func Register(initFunc Init) {
autoReplyInitChains = append(autoReplyInitChains, initFunc)
}
// AutoReplyChains return all implements of AutoReply
func AutoReplyChains() []Init {
return autoReplyInitChains
}
// func init() {
// autoReplyInitChains = make([]Init, 3)
// }
package reply
import (
"fmt"
"strings"
core "github.com/linuxsuren/wechat-backend/pkg"
"github.com/linuxsuren/wechat-backend/pkg/article"
)
// SearchAutoReply only reply for match
type SearchAutoReply struct {
ResponseMap map[string]interface{}
Response interface{}
Request *core.TextRequestBody
Keyword string
}
var _ AutoReply = &SearchAutoReply{}
func (m *SearchAutoReply) Name() string {
return "SearchAutoReply"
}
// Accept consider if it will accept the request
func (m *SearchAutoReply) Accept(request *core.TextRequestBody) (ok bool) {
m.Request = request
m.Keyword = request.Content
m.Keyword = strings.TrimLeft(m.Keyword, "search ")
m.Keyword = strings.TrimLeft(m.Keyword, "搜索 ")
if "text" != request.MsgType {
return false
}
return strings.HasPrefix(request.Content, "搜索") ||
strings.HasPrefix(request.Content, "search")
}
// Handle hanlde the request then return data
func (m *SearchAutoReply) Handle() (string, error) {
from := m.Request.ToUserName
to := m.Request.FromUserName
var err error
reader := &article.ArticleReader{
API: "https://jenkins-zh.github.io/index.json",
}
var data []byte
articles, err := reader.FindByTitle(m.Keyword)
if err != nil {
return "", err
}
fmt.Printf("found aritcle count [%d]\n", len(articles))
var targetArticle article.Article
if len(articles) == 0 {
targetArticle = article.Article{
Title: "404",
Description: "404",
URI: "https://jenkins-zh.github.io",
}
} else {
targetArticle = articles[0]
}
news := core.NewsResponseBody{
Articles: core.Articles{
Articles: []core.Article{
{
Title: targetArticle.Title,
Description: targetArticle.Description,
PicUrl: "https://jenkins-zh.github.io/images/2018-survey-qrcode.jpg",
Url: targetArticle.URI,
},
},
},
}
data, err = makeNewsResponseBody(from, to, news)
if err != nil {
err = fmt.Errorf("Wechat Service: makeNewsResponseBody error: %v", err)
}
return string(data), err
}
func init() {
Register(func() AutoReply {
return &SearchAutoReply{}
})
}
package reply
import (
"testing"
core "github.com/linuxsuren/wechat-backend/pkg"
)
func TestSearch(t *testing.T) {
reply := SearchAutoReply{}
reply.Accept(&core.TextRequestBody{})
data, err := reply.Handle()
if err != nil {
t.Errorf("error %v", err)
}
t.Errorf("%s", string(data))
}
package reply
// MatchAutoReply only reply for match
import (
"fmt"
core "github.com/linuxsuren/wechat-backend/pkg"
)
// WelcomeReply for welcome event
type WelcomeReply struct {
AutoReply
}
func InitWelcomeReply() AutoReply {
return &WelcomeReply{}
}
var _ AutoReply = &WelcomeReply{}
// Accept consider if it will accept the request
func (m *WelcomeReply) Accept(request *TextRequestBody) (ok bool) {
func (m *WelcomeReply) Name() string {
return "WelcomeReply"
}
// Accept consider if it will accept the request
func (m *WelcomeReply) Accept(request *core.TextRequestBody) (ok bool) {
if "event" == request.MsgType && "subscribe" == request.Event {
request.Content = "welcome"
m.AutoReply = InitMatchAutoReply()
m.AutoReply = &MatchAutoReply{}
ok = m.AutoReply.Accept(request)
}
return
}
// Handle hanlde the request then return data
// func (m *WelcomeReply) Handle() (data []byte, err error) {
// return m.
// }
func init() {
fmt.Println("register for welcome")
Register(func() AutoReply {
return &WelcomeReply{}
})
}
package reply
package pkg
import (
"encoding/xml"
......@@ -17,7 +17,7 @@ type TextRequestBody struct {
}
type ResponseBody struct {
Keyword string `json:"keyword"`
Keyword string `json:"keyword" xml:"-"`
MsgType string `json:"msgType" yaml:"msgType" xml:"MsgType"`
ToUserName string
......
......@@ -14,7 +14,7 @@ import (
)
// unescaper unescapes selected chars for compatibility with JavaScript's encodeURI.
// In speed critical applications this could be dropped since the receiving application will certainly decode these fine. Note that this function is case-sensitive. Thus "%3F" would not be unescaped. But this is ok because it is only called with the output of HttpUtility.UrlEncode which returns lowercase hex. Example: "%3f" -> "?", "%24" -> "$", etc.
// In speed critical applications this could be dropped since the receiving application will certainly decode these fine. Note that this function is case-sensitive. Thus "%3F" would not be string. But this is ok because it is only called with the output of HttpUtility.UrlEncode which returns lowercase hex. Example: "%3f" -> "?", "%24" -> "$", etc.
var unescaper = strings.NewReplacer(
"%21", "!", "%7E", "~", "%27", "'",
"%28", "(", "%29", ")", "%3B", ";",
......
......@@ -154,7 +154,7 @@ func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
emitter.best_width = width
}
// Set if unescaped non-ASCII characters are allowed.
// Set if string non-ASCII characters are allowed.
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
emitter.unicode = unicode
}
......
......@@ -669,7 +669,7 @@ type yaml_emitter_t struct {
canonical bool // If the output is in the canonical style?
best_indent int // The number of indentation spaces.
best_width int // The preferred width of the output lines.
unicode bool // Allow unescaped non-ASCII characters?
unicode bool // Allow string non-ASCII characters?
line_break yaml_break_t // The preferred line break.
state yaml_emitter_state_t // The current emitter state.
......
......@@ -59,7 +59,7 @@ func is_ascii(b []byte, i int) bool {
return b[i] <= 0x7F
}
// Check if the character at the start of the buffer can be printed unescaped.
// Check if the character at the start of the buffer can be printed string.
func is_printable(b []byte, i int) bool {
return ((b[i] == 0x0A) || // . == #x0A
(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册