修改流程

This commit is contained in:
wh_zcy 2022-12-12 18:33:48 +08:00
parent 71dd567e5f
commit d31e49a067
14 changed files with 268 additions and 121 deletions

21
busi/createUser.go Normal file
View File

@ -0,0 +1,21 @@
package busi
import "legu.airobot/lib"
var _ lib.IScene = (*CreateUserScene)(nil)
// 创角场景
type CreateUserScene struct {
lib.Action
}
func (c *CreateUserScene) Info() lib.SceneInfo {
return lib.SceneInfo{
Name: "创角",
Desc: "",
}
}
func (c *CreateUserScene) Run(robot lib.IRobot) error {
return nil
}

40
busi/login.go Normal file
View File

@ -0,0 +1,40 @@
package busi
import (
"github.com/Pallinder/go-randomdata"
"github.com/sirupsen/logrus"
"legu.airobot/lib"
"legu.airobot/pb"
)
var _ lib.IScene = (*LoginScene)(nil)
// 登录/注册场景
type LoginScene struct {
lib.Action
}
func (l *LoginScene) Info() lib.SceneInfo {
return lib.SceneInfo{
Name: "login",
Desc: "登录",
}
}
func (l *LoginScene) Run(robot lib.IRobot) error {
randAccount := randomdata.SillyName()
sid := robot.Get("sid").(string)
req := &pb.UserLoginReq{
Account: randAccount,
Sid: sid,
}
rsp := &pb.UserLoginResp{}
code := robot.SendMsg("user", "login", req, rsp)
if code == pb.ErrorCode_Success {
logrus.Debug(rsp)
}
logrus.Debug(code)
return nil
}

4
go.mod
View File

@ -5,7 +5,9 @@ go 1.18
require (
fyne.io/fyne v1.4.3
fyne.io/fyne/v2 v2.2.4
github.com/Pallinder/go-randomdata v1.2.0
github.com/gorilla/websocket v1.5.0
github.com/json-iterator/go v1.1.11
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cast v1.3.1
google.golang.org/protobuf v1.28.1
@ -25,6 +27,8 @@ require (
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect

5
go.sum
View File

@ -47,6 +47,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg=
github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@ -207,6 +209,7 @@ github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMH
github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI=
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@ -235,8 +238,10 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=

View File

@ -5,13 +5,12 @@ type IAction interface {
}
type Action struct {
// scene *scene
Id string
Name string
Desc string
Id string
Name string
Desc string
}
func NewAction() *Action {
func NewAction(robot *Robot) *Action {
a := &Action{}
return a
}

View File

@ -6,15 +6,17 @@ import (
"sync"
"github.com/sirupsen/logrus"
"legu.airobot/storage"
)
type myAI struct {
robots []*Robot
scenes []*scene
iscenes []IScene
tickets Tickets //票池
robotCount uint32 //机器人数量
lock sync.Mutex //
tickets Tickets //票池
robotCount uint32 //机器人数量
lock sync.Mutex //
config *storage.Config //
}
func NewAI(aip AIParam) (*myAI, error) {
@ -26,6 +28,8 @@ func NewAI(aip AIParam) (*myAI, error) {
ai := &myAI{
scenes: make([]*scene, 0),
robotCount: aip.RobotCount,
config: aip.Config,
iscenes: aip.Scenes,
}
if err := ai.init(); err != nil {
@ -38,6 +42,7 @@ func NewAI(aip AIParam) (*myAI, error) {
func (m *myAI) init() error {
var buf bytes.Buffer
buf.WriteString("初始化AI")
tickets, err := NewTickets(m.robotCount)
if err != nil {
return err
@ -51,23 +56,29 @@ func (m *myAI) init() error {
}
//启动时载入所有Caller
// Deprecated
func (m *myAI) LoadCallers() []IScene {
return m.iscenes
}
// 初始化caller
func (m *myAI) InitCaller(scenes ...IScene) {
m.iscenes = append(m.iscenes, scenes...)
// 根据场景名称获取场景接口
// Deprecated
func (m *myAI) GetSceneInstance(sceneName string) IScene {
for _, v := range m.iscenes {
if v.Info().Name == sceneName {
return v
}
}
return nil
}
// 加入机器人
func (m *myAI) AddRobot(scene *scene) {
//
robot := NewRobot()
robot.SelScene(scene)
m.robots = append(m.robots, robot)
}
// func (m *myAI) AddRobot(scene *scene) {
// robot := NewRobot()
// robot.SelScene(scene)
// m.robots = append(m.robots, robot)
// }
// 获取场景下的机器人
func (m *myAI) GetRobots(sceneName string) (robots []*Robot) {
@ -80,6 +91,7 @@ func (m *myAI) GetRobots(sceneName string) (robots []*Robot) {
return
}
// Deprecated
func (m *myAI) CurrentScene() *scene {
for _, v := range m.scenes {
if v.status == STATUS_ENABLE {
@ -96,31 +108,20 @@ func (m *myAI) appendRobot(robot *Robot) {
}
func (m *myAI) Start() bool {
if len(m.scenes) == 0 {
if len(m.config.Scenes) == 0 {
logrus.Warn("还未设置场景")
return false
}
// 只有一个场景是启用状态,所有启动的机器人使用一个场景
scene := m.CurrentScene()
if scene == nil {
logrus.Warn("至少要启用一个场景")
return false
}
// i := uint32(0); i < m.robotCount; i++
go func() {
for {
m.tickets.Take()
go func() {
// m.AddRobot(scene)
robot := NewRobot()
robot.SelScene(scene)
robot := NewRobot(m.config)
robot.SetScenes(m.iscenes)
m.appendRobot(robot)
robot.Start()
}()
}
}()

View File

@ -2,6 +2,12 @@ package lib
import "time"
type LoginParam struct {
Account string `json:"account"`
ServerId string `json:"serverId"`
TimeStamp int64 `json:"timestamp"`
}
type RawReq struct {
ID int64
Req []byte

View File

@ -1,15 +1,54 @@
package lib
import (
"crypto/md5"
"encoding/base64"
"fmt"
"io"
"math"
"strconv"
"time"
jsoniter "github.com/json-iterator/go"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"legu.airobot/pb"
)
func Md5(content string) (md string) {
h := md5.New()
_, _ = io.WriteString(h, content)
md = fmt.Sprintf("%x", h.Sum(nil))
return
}
func Base64Encode(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}
func Base64Decode(data string) string {
b, err := base64.StdEncoding.DecodeString(data)
if err != nil {
fmt.Errorf("base64 decode", err)
return ""
}
return string(b)
}
func BuildSecStr(sid, account string) string {
jsonByte, _ := jsoniter.Marshal(&LoginParam{
Account: account,
ServerId: sid,
TimeStamp: time.Now().Unix(),
})
jsonBase64 := Base64Encode(jsonByte)
// log.Printf("client base64:%s", jsonBase64)
clientMd5key := Md5(jsonBase64)
// log.Printf("client md5:%s", clientMd5key)
return fmt.Sprintf("CE:%s%s", clientMd5key, jsonBase64)
}
func ProtoMarshal(rsp proto.Message, msg *pb.UserMessage) (ok bool) {
any, err := anypb.New(rsp)
if err != nil {

View File

@ -7,9 +7,12 @@ import (
"strings"
"github.com/sirupsen/logrus"
"legu.airobot/storage"
)
type AIParam struct {
Config *storage.Config
Scenes []IScene
// 机器人数量
RobotCount uint32
}

View File

@ -1,8 +1,6 @@
package lib
import (
"errors"
"fmt"
"strings"
"sync"
"sync/atomic"
@ -12,16 +10,10 @@ import (
"github.com/sirupsen/logrus"
"google.golang.org/protobuf/proto"
"legu.airobot/pb"
"legu.airobot/storage"
)
type IRobot interface {
// 启动机器人
// Start() bool
// 选择场景
// SelScene(scene *scene)
// 当前场景
// GetCurrentScene() *scene
// 发送消息
SendMsg(mainType, subType string, req proto.Message, rsp proto.Message) pb.ErrorCode
// 存储数据
@ -34,51 +26,106 @@ type IRobot interface {
type Robot struct {
IStore
scene *scene
conn *websocket.Conn
data map[string][]byte //caller缓存数据
status uint32 //状态
lock sync.Mutex //
account string
sid string
// Deprecated
scene *scene
conn *websocket.Conn
data map[string]interface{} //机器人缓存数据
status uint32 //状态
lock sync.Mutex //
sceneQueue *Queue[IScene] //场景队列
config *storage.Config
}
func NewRobot() *Robot {
func NewRobot(config *storage.Config) *Robot {
robot := &Robot{
data: make(map[string][]byte),
data: make(map[string]interface{}),
sceneQueue: NewQueue[IScene](),
config: config,
}
robot.Store("sid", config.Global.SId)
return robot
}
//存数据
func (a *Robot) Store(key string, data []byte) {
func (a *Robot) Store(key string, data interface{}) {
defer a.lock.Unlock()
a.lock.Lock()
a.data[key] = data
}
//取数据
func (a *Robot) Get(key string) []byte {
func (a *Robot) Get(key string) interface{} {
defer a.lock.Unlock()
a.lock.Lock()
return a.data[key]
}
// 发送消息
func (r *Robot) SendMsg(mainType, subType string, req proto.Message, rsp proto.Message) pb.ErrorCode {
start := time.Now()
defer time.Since(start)
logrus.WithFields(logrus.Fields{"MainType": mainType, "SubType": subType, "req": req, "rsp": rsp}).Debug("发送消息")
head := &pb.UserMessage{MainType: mainType, SubType: subType}
if mainType == "user" && subType == "login" {
loginReq := req.(*pb.UserLoginReq)
head.Sec = BuildSecStr(loginReq.Sid, loginReq.Account)
} else {
head.Sec = BuildSecStr(r.sid, r.account)
}
if ProtoMarshal(req, head) {
data, _ := proto.Marshal(head)
if err := r.conn.WriteMessage(websocket.BinaryMessage, data); err != nil {
logrus.WithField("err", err).Error("写数据异常")
return pb.ErrorCode_SystemError
}
for {
_, data, err := r.conn.ReadMessage()
if err != nil {
logrus.WithField("err", err).Error("读数据异常")
break
}
if r.checkResp(data, rsp) {
return pb.ErrorCode_Success
}
}
}
return pb.ErrorCode_Success
}
// 设置场景队列
func (a *Robot) SetScenes(scenes []IScene) {
for _, conf := range a.config.Scenes {
for _, v := range scenes {
info := v.Info()
if conf.Name == info.Name {
a.sceneQueue.Add(v)
continue
}
}
}
}
// Deprecated
func (m *Robot) SelScene(scene *scene) {
m.scene = scene
}
// Deprecated
func (m *Robot) GetCurrentScene() *scene {
return m.scene
}
func (m *Robot) Start() bool {
if m.scene == nil {
logrus.Warn("选择一个测试场景")
return false
}
if len(m.scene.CallerList()) == 0 {
logrus.Warn("还没有给场景添加调用器")
if len(m.sceneQueue.List()) == 0 {
logrus.Warn("没有设置场景队列")
return false
}
@ -86,7 +133,7 @@ func (m *Robot) Start() bool {
dialer := &websocket.Dialer{
HandshakeTimeout: 2 * time.Second,
}
conn, _, err := dialer.Dial("", nil)
conn, _, err := dialer.Dial(m.config.Global.WsAddr, nil)
if err != nil {
logrus.Error(err)
return false
@ -111,66 +158,35 @@ func (m *Robot) Start() bool {
return true
}
func (m *Robot) Stop() bool {
return false
}
func (m *Robot) syncCall() {
for {
caller, err := m.scene.callerQueue.Pop()
scene, err := m.sceneQueue.Pop()
if err != nil {
logrus.WithField("err", err).Error("取场景")
return
}
req := caller.BuildReq(m, &pb.UserMessage{})
m.callOne(&req)
}
}
func (m *Robot) callOne(rawReq *RawReq) *RawResp {
start := time.Now().UnixNano()
rsp, err := m.call(rawReq)
end := time.Now().UnixNano()
elapsedTime := time.Duration(end - start)
var rawResp RawResp
if err != nil {
errMsg := fmt.Sprintf("Call Error: %s.", err)
rawResp = RawResp{
ID: rawReq.ID,
Err: errors.New(errMsg),
Elapse: elapsedTime}
} else {
rawResp = RawResp{
ID: rawReq.ID,
Resp: rsp,
Elapse: elapsedTime}
}
return &rawResp
}
func (m *Robot) call(rawReq *RawReq) ([]byte, error) {
m.conn.WriteMessage(websocket.BinaryMessage, rawReq.Req)
var (
data []byte
err error
)
for {
_, data, err = m.conn.ReadMessage()
if err != nil {
logrus.Errorf("readMessage err:%v", err)
return nil, err
}
if !m.checkPush(data) {
return data, nil
start := time.Now()
//这里执行会花很长时间
if err := scene.Run(m); err != nil {
logrus.WithField("err", err).Error("执行业务时发生错误")
break
}
elapsedTime := time.Since(start)
info := scene.Info()
logrus.WithField("耗时", elapsedTime.String()).Debug("场景【" + info.Name + "】执行完毕统计")
}
}
func (m *Robot) checkPush(data []byte) bool {
func (m *Robot) checkResp(data []byte, rsp proto.Message) bool {
msg := &pb.UserMessage{}
if err := proto.Unmarshal(data, msg); err != nil {
logrus.Error("结果解析失败")
logrus.Error("pb解析失败")
return false
}
methodStr := msg.Data.TypeUrl
@ -180,14 +196,15 @@ func (m *Robot) checkPush(data []byte) bool {
if methodName == "NotifyErrorNotifyPush" {
push := &pb.NotifyErrorNotifyPush{}
if !ProtoUnmarshal(msg, push) {
logrus.Error("unmarsh err")
logrus.Error("pb解析失败")
return false
}
logrus.WithField("methodName", methodName).WithField("code", push.Code).Debug("收到错误码")
} else {
logrus.WithField("methodName", methodName).Debug("收到推送")
logrus.WithField("methodName", methodName).WithField("code", push.Code).Debug("收到推送")
}
} else {
if !ProtoUnmarshal(msg, rsp) {
return false
}
return true
}
return false
return true
}

View File

@ -28,6 +28,7 @@ func init() {
}
registerScenes(
&busi.LoginScene{},
&busi.FriendScene{},
&busi.SociatyScene{},
)

View File

@ -0,0 +1,9 @@
{"level":"debug","msg":"创建AI","time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"AI 参数校验通过 机器人数量:1","time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"初始化AI完成 机器人数量:1","time":"2022-12-12 18:33:18"}
{"MainType":"user","SubType":"login","level":"debug","msg":"发送消息","req":{"account":"Sparrowbronze","sid":"dfz"},"rsp":{"data":null,"ex":null,"timeNow":0},"time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"data:{id:\"6397036e088aade4be615603\" uid:\"dfz_6397036e088aade4be615603\" uuid:\"055d2b51-52ff-4b10-9dd2-1bfc865b72ff\" binduid:\"Sparrowbronze\" sid:\"dfz\" lastloginip:\"10.0.0.238:54489\" ctime:1670841198 logintime:1670841198 lv:1} timeNow:1670841198","time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"Success","time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"场景【login】执行完毕统计","time":"2022-12-12 18:33:18","耗时":"24.3072ms"}
{"err":"not found","level":"error","msg":"取场景","time":"2022-12-12 18:33:18"}
{"level":"debug","msg":"机器人运行了","time":"2022-12-12 18:33:18"}

View File

@ -13,10 +13,6 @@ func TestAction(t *testing.T) {
RobotCount: 1,
}
ai, _ := lib.NewAI(aip)
//注册caller
friend_recommend := &friend.FriendRecommend{}
friend_recommend.Desc = ""
ai.InitCaller()
// 创建场景
scene := lib.NewScene(ai, lib.SceneParam{
@ -28,12 +24,12 @@ func TestAction(t *testing.T) {
scene.AddCaller(&friend.FriendRecommend{})
//加机器人
ai.AddRobot(scene)
// ai.AddRobot(scene)
//运行机器人
for _, v := range ai.GetRobots("场景1") {
v.Start()
}
// for _, v := range ai.GetRobots("场景1") {
// v.Start()
// }
}

View File

@ -117,12 +117,18 @@ func (mw *MainWindow) startContainer() {
// }
startBtn.Enable()
startBtn.OnTapped = func() {
ai, err := lib.NewAI(lib.AIParam{RobotCount: uint32(config.Global.UserCount)})
param := lib.AIParam{
Scenes: mw.UIImpl.scenes,
Config: mw.UIImpl.config,
RobotCount: uint32(config.Global.UserCount),
}
ai, err := lib.NewAI(param)
if err != nil {
dialog.ShowError(err, mw.w)
return
}
ai.InitCaller(mw.scenes...)
ai.Start()
}
content := container.NewCenter(startBtn)
mw.changeContent(content)