同步配置
This commit is contained in:
parent
69c3d4deef
commit
32fcd9f691
Binary file not shown.
@ -60,6 +60,23 @@ func (at *appContainer) openApp(app appInterface) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (at *appContainer) openWelcome() (string, error) {
|
||||
var firstTab *container.TabItem
|
||||
app := &appWelcome{}
|
||||
if err := at.initApp(app); err != nil {
|
||||
return app.GetAppName(), err
|
||||
}
|
||||
tab := app.GetTabItem()
|
||||
at.Append(tab)
|
||||
if firstTab == nil {
|
||||
firstTab = tab
|
||||
}
|
||||
if firstTab != nil {
|
||||
at.Select(firstTab)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// open default app
|
||||
func (at *appContainer) openDefaultApp(appName string) (string, error) {
|
||||
var firstTab *container.TabItem
|
||||
|
@ -27,7 +27,7 @@ var (
|
||||
}
|
||||
|
||||
toolRegister = []appInterface{
|
||||
&appWelcome{},
|
||||
// &appWelcome{},
|
||||
&appGen{},
|
||||
&appPbGen{},
|
||||
&appLock{},
|
||||
@ -35,14 +35,6 @@ var (
|
||||
&appPing{},
|
||||
&appMgo{},
|
||||
}
|
||||
|
||||
perfRegister = []appInterface{
|
||||
&perfWelcome{},
|
||||
&perfConf{},
|
||||
&perfPb{},
|
||||
&perfResult{},
|
||||
&perfChoose{},
|
||||
}
|
||||
)
|
||||
|
||||
type appAdapter struct {
|
||||
|
@ -1,224 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib"
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
"go_dreamfactory/comm"
|
||||
"go_dreamfactory/pb"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/Pallinder/go-randomdata"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type perfChoose struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
conf *storage.Config
|
||||
binduids []string //账号
|
||||
handler lib.Handler
|
||||
}
|
||||
|
||||
func (app *perfChoose) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_CHOOSE, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
loginTestBtn := widget.NewButton("登陆(注册)", nil)
|
||||
loginTestBtn.OnTapped = func() {
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
var err error
|
||||
|
||||
app.handler, err = service.NewWsCli(app.conf.WsAddr, 2*time.Second)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
userCount := app.conf.UserCount
|
||||
for i := int32(0); i < userCount; i++ {
|
||||
account := randomdata.SillyName()
|
||||
app.binduids = append(app.binduids, account)
|
||||
// 登录
|
||||
rqLogin := ReqParams{
|
||||
Sid: app.conf.SId,
|
||||
Account: account,
|
||||
PbReq: &pb.UserLoginReq{Sid: app.conf.SId, Account: account},
|
||||
MainType: "user",
|
||||
SubType: "login",
|
||||
}
|
||||
b, err := app.buildReq(rqLogin)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
app.handler.SetReq(b, false)
|
||||
|
||||
}
|
||||
|
||||
param := lib.ParamMgr{
|
||||
Caller: app.handler,
|
||||
Timeout: time.Duration(app.conf.Pressure.TimeoutMs) * time.Millisecond,
|
||||
Lps: uint32(app.conf.Pressure.Concurrency),
|
||||
Duration: time.Duration(app.conf.Pressure.DurationS) * time.Second,
|
||||
ResultCh: make(chan *lib.CallResult, 50),
|
||||
}
|
||||
a, err := lib.NewAssistant(obs, param)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
a.Start()
|
||||
|
||||
a.ShowResult()
|
||||
}
|
||||
|
||||
createTestBtn := widget.NewButton("创角", func() {
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
|
||||
for _, account := range app.binduids {
|
||||
rq := ReqParams{
|
||||
Sid: app.conf.SId,
|
||||
Account: account,
|
||||
PbReq: &pb.UserCreateReq{NickName: account},
|
||||
MainType: "user",
|
||||
SubType: "create",
|
||||
}
|
||||
b, err := app.buildReq(rq)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
app.handler.SetReq(b, false)
|
||||
}
|
||||
|
||||
param := lib.ParamMgr{
|
||||
Caller: app.handler,
|
||||
Timeout: time.Duration(app.conf.Pressure.TimeoutMs) * time.Millisecond,
|
||||
Lps: uint32(app.conf.Pressure.Concurrency),
|
||||
Duration: time.Duration(app.conf.Pressure.DurationS) * time.Second,
|
||||
ResultCh: make(chan *lib.CallResult, 50),
|
||||
}
|
||||
a, err := lib.NewAssistant(obs, param)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
a.Start()
|
||||
|
||||
a.ShowResult()
|
||||
})
|
||||
|
||||
//场景
|
||||
scenBtn := widget.NewButton("其它场景", nil)
|
||||
scenBtn.OnTapped = func() {
|
||||
// defer openApp3(perfWin.tabs, common.TOOLBAR_PERF_PB)
|
||||
// closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
|
||||
// if tables, err := cfg.NewTables(common.Loader); err != nil {
|
||||
// println(err.Error())
|
||||
// } else {
|
||||
// for _, v := range tables.TestFlow.GetDataList() {
|
||||
// p, ok := pbMap[v.Route]
|
||||
// if !ok {
|
||||
// logrus.WithField("route", v.Route).Debug("未注册")
|
||||
// continue
|
||||
// }
|
||||
// routeStr := strings.SplitN(v.Route, ".", 2)
|
||||
// for _, account := range app.binduids {
|
||||
// rq := ReqParams{
|
||||
// Sid: app.conf.SId,
|
||||
// Account: account,
|
||||
// PbReq: p,
|
||||
// MainType: routeStr[0],
|
||||
// SubType: routeStr[1],
|
||||
// }
|
||||
// b, err := app.buildReq(rq)
|
||||
// if err != nil {
|
||||
// logrus.Error(err)
|
||||
// return
|
||||
// }
|
||||
// app.handler.SetReq(b, true)
|
||||
// }
|
||||
|
||||
// param := lib.ParamMgr{
|
||||
// Caller: app.handler,
|
||||
// Timeout: time.Duration(app.conf.Pressure.TimeoutMs) * time.Millisecond,
|
||||
// Lps: uint32(app.conf.Pressure.Concurrency),
|
||||
// Duration: time.Duration(app.conf.Pressure.DurationS) * time.Second,
|
||||
// ResultCh: make(chan *lib.CallResult, 50),
|
||||
// }
|
||||
// a, err := lib.NewAssistant(obs, param)
|
||||
// if err != nil {
|
||||
// logrus.Error(err)
|
||||
// }
|
||||
|
||||
// a.Start()
|
||||
|
||||
// a.ShowResult()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
//上一步
|
||||
preBtn := widget.NewButtonWithIcon("上一步", theme.NavigateBackIcon(), nil)
|
||||
preBtn.OnTapped = func() {
|
||||
defer openApp3(perfWin.tabs, common.TOOLBAR_PERF_CONF)
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
}
|
||||
btns := container.NewVBox(loginTestBtn, createTestBtn, scenBtn)
|
||||
c := container.NewBorder(nil, container.NewHBox(layout.NewSpacer(), preBtn), nil, nil, btns)
|
||||
content.Objects = append(content.Objects, c)
|
||||
app.tabItem.Content = content
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfChoose) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_CHOOSE
|
||||
}
|
||||
|
||||
func (a *perfChoose) OnClose() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *perfChoose) OnDestroy() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type ReqParams struct {
|
||||
Sid string
|
||||
Account string
|
||||
PbReq proto.Message
|
||||
MainType string
|
||||
SubType string
|
||||
}
|
||||
|
||||
func (a *perfChoose) buildReq(rp ReqParams) ([]byte, error) {
|
||||
head := &pb.UserMessage{MainType: rp.MainType, SubType: rp.SubType}
|
||||
head.Sec = common.BuildSecStr(rp.Sid, rp.Account)
|
||||
if comm.ProtoMarshal(rp.PbReq, head) {
|
||||
data, err := proto.Marshal(head)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type perfConf struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
conf *storage.Config
|
||||
}
|
||||
|
||||
func (app *perfConf) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_CONF, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
// 压测form
|
||||
wsAddrEntry := widget.NewEntry()
|
||||
wsAddrEntry.PlaceHolder = "服务地址"
|
||||
wsAddrEntry.Text = app.conf.WsAddr
|
||||
|
||||
timeoutEntry := widget.NewEntry()
|
||||
timeoutEntry.PlaceHolder = "毫秒数"
|
||||
timeoutEntry.Text = cast.ToString(app.conf.Pressure.TimeoutMs)
|
||||
|
||||
lpsEntry := widget.NewEntry()
|
||||
lpsEntry.PlaceHolder = "并发数量"
|
||||
lpsEntry.Text = cast.ToString(app.conf.Pressure.Concurrency)
|
||||
|
||||
durationEntry := widget.NewEntry()
|
||||
durationEntry.PlaceHolder = "秒数"
|
||||
durationEntry.Text = cast.ToString(app.conf.Pressure.DurationS)
|
||||
|
||||
userCountEntry := widget.NewEntry()
|
||||
userCountEntry.PlaceHolder = "自动创建的用户数"
|
||||
userCountEntry.Text = cast.ToString(app.conf.UserCount)
|
||||
|
||||
sidEntry := widget.NewEntry()
|
||||
sidEntry.PlaceHolder = "区服ID"
|
||||
sidEntry.Text = app.conf.SId
|
||||
|
||||
intervalEntry := widget.NewEntry()
|
||||
intervalEntry.PlaceHolder = "间隔时间(s)"
|
||||
intervalEntry.Text = cast.ToString(app.conf.IntervalS)
|
||||
|
||||
form := widget.NewForm(
|
||||
widget.NewFormItem("服务地址", wsAddrEntry),
|
||||
widget.NewFormItem("区服", sidEntry),
|
||||
widget.NewFormItem("用户数", userCountEntry),
|
||||
widget.NewFormItem("超时(ms)", timeoutEntry),
|
||||
widget.NewFormItem("并发量", lpsEntry),
|
||||
widget.NewFormItem("持续时间(s)", durationEntry),
|
||||
widget.NewFormItem("间隔时间(s)", intervalEntry),
|
||||
)
|
||||
// btn
|
||||
nextBtn := widget.NewButtonWithIcon("下一步", theme.NavigateNextIcon(), nil)
|
||||
nextBtn.OnTapped = func() {
|
||||
//校验表单数据
|
||||
if wsAddrEntry.Text == "" {
|
||||
common.ShowTip("服务地址必填")
|
||||
return
|
||||
}
|
||||
|
||||
if sidEntry.Text == "" {
|
||||
common.ShowTip("区服ID必填")
|
||||
return
|
||||
}
|
||||
|
||||
if timeoutEntry.Text == "" {
|
||||
common.ShowTip("超时时间必填")
|
||||
return
|
||||
}
|
||||
if lpsEntry.Text == "" {
|
||||
common.ShowTip("并发数必填")
|
||||
return
|
||||
}
|
||||
|
||||
if durationEntry.Text == "" {
|
||||
common.ShowTip("持续时间")
|
||||
return
|
||||
}
|
||||
|
||||
if userCountEntry.Text == "" {
|
||||
common.ShowTip("用户数至少是1")
|
||||
return
|
||||
}
|
||||
|
||||
pressure := app.conf.Pressure
|
||||
pressure.TimeoutMs = cast.ToInt32(timeoutEntry.Text)
|
||||
pressure.Concurrency = cast.ToInt32(lpsEntry.Text)
|
||||
pressure.DurationS = cast.ToInt32(durationEntry.Text)
|
||||
app.conf.Pressure = pressure
|
||||
app.conf.UserCount = cast.ToInt32(userCountEntry.Text)
|
||||
app.conf.WsAddr = wsAddrEntry.Text
|
||||
app.conf.SId = sidEntry.Text
|
||||
if err := perfWin.UIImpl.storage.StoreConfig(app.conf); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
//next
|
||||
defer closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CONF)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
}
|
||||
|
||||
resetBtn := widget.NewButtonWithIcon("重置", theme.ContentRedoIcon(), nil)
|
||||
resetBtn.OnTapped = func() {
|
||||
timeoutEntry.Text = ""
|
||||
lpsEntry.Text = ""
|
||||
durationEntry.Text = ""
|
||||
userCountEntry.Text = ""
|
||||
wsAddrEntry.Text = ""
|
||||
sidEntry.Text = ""
|
||||
form.Refresh()
|
||||
}
|
||||
|
||||
preBtn := widget.NewButtonWithIcon("上一步", theme.NavigateBackIcon(), nil)
|
||||
preBtn.OnTapped = func() {
|
||||
defer closeApp3(perfWin.tabs, common.TOOLBAR_PERF_CONF)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_TIP)
|
||||
}
|
||||
|
||||
c := container.NewBorder(nil, container.NewHBox(layout.NewSpacer(), preBtn, resetBtn, nextBtn), nil, nil, form)
|
||||
content.Objects = append(content.Objects, c)
|
||||
app.tabItem.Content = content
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfConf) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_CONF
|
||||
}
|
||||
|
||||
func (a *perfConf) OnClose() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *perfConf) OnDestroy() bool {
|
||||
return true
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
)
|
||||
|
||||
type perfCreate struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
conf *storage.Config
|
||||
}
|
||||
|
||||
func (app *perfCreate) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_CONF, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfCreate) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_CREATE
|
||||
}
|
||||
|
||||
func (a *perfCreate) OnClose() bool {
|
||||
return false
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type perfLogin struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
conf *storage.Config
|
||||
}
|
||||
|
||||
func (app *perfLogin) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_CONF, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
loginTestBtn := widget.NewButton("登陆/注册", func() {
|
||||
|
||||
})
|
||||
|
||||
createTestBtn := widget.NewButton("创角", func() {})
|
||||
|
||||
btns := container.NewHBox(loginTestBtn, createTestBtn)
|
||||
c := container.NewBorder(btns, nil, nil, nil)
|
||||
content.Objects = append(content.Objects, c)
|
||||
app.tabItem.Content = content
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfLogin) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_LOGIN
|
||||
}
|
||||
|
||||
func (a *perfLogin) OnClose() bool {
|
||||
return false
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib"
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
"go_dreamfactory/comm"
|
||||
"go_dreamfactory/pb"
|
||||
cfg "go_dreamfactory/sys/configure/structs"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/Pallinder/go-randomdata"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type perfPb struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
|
||||
itemList common.ItemList
|
||||
|
||||
pbList func() //协议列表
|
||||
conf *storage.Config
|
||||
}
|
||||
|
||||
func (app *perfPb) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_PB, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
app.itemList = *common.NewItemList()
|
||||
app.itemList.ItemList = app.itemList.CreateList()
|
||||
|
||||
app.pbList = func() {
|
||||
// if tables, err := cfg.NewTables(common.Loader); err != nil {
|
||||
// println(err.Error())
|
||||
// } else {
|
||||
// for _, v := range tables.TestFlow.GetDataList() {
|
||||
// item := common.Item{
|
||||
// Id: cast.ToString(v.Id),
|
||||
// Text: fmt.Sprintf("%-6d %-20s %-20s %s", v.Id, v.Msg, v.Route, v.Params),
|
||||
// Data: v,
|
||||
// }
|
||||
// app.itemList.AddItem(item)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
defer app.pbList()
|
||||
|
||||
// 刷新按钮
|
||||
refeshBtn := widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), func() {
|
||||
app.itemList.Reset()
|
||||
app.pbList()
|
||||
})
|
||||
|
||||
// next按钮
|
||||
nextBtn := widget.NewButtonWithIcon("下一步", theme.NavigateNextIcon(), nil)
|
||||
nextBtn.OnTapped = func() {
|
||||
defer closeApp3(perfWin.tabs, common.TOOLBAR_PERF_PB)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
// 根据填写的用户数创建用户
|
||||
userCount := perfWin.config.UserCount
|
||||
|
||||
// 遍历时,通过sleep 控制增加的用户数
|
||||
for i := int32(0); i < userCount; i++ {
|
||||
handler, err := service.NewWsCli(perfWin.config.WsAddr, time.Duration(perfWin.config.Pressure.TimeoutMs)*time.Millisecond)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var login *UserLogin
|
||||
login, err = app.loginReq(perfWin.config.SId)
|
||||
handler.SetReq(login.req, false)
|
||||
assist := app.createAssistantWithoutConf(handler)
|
||||
assist.Start()
|
||||
assist.ShowResult()
|
||||
|
||||
// 遍历测试的协议
|
||||
for _, item := range app.itemList.CachedList.Items {
|
||||
if data, ok := item.Data.(*cfg.GameTestFlowData); ok {
|
||||
logrus.Debugf("%v %v", data.Route, data.Params)
|
||||
var (
|
||||
reqData []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if login == nil {
|
||||
continue
|
||||
}
|
||||
if v, ok := pbMap[data.Route]; ok {
|
||||
routeStr := strings.SplitN(data.Route, ".", 2)
|
||||
head := &pb.UserMessage{MainType: routeStr[0], SubType: routeStr[1]}
|
||||
head.Sec = common.BuildSecStr(login.sid, login.account)
|
||||
if err := common.Json2Pb(data.Params, v); err != nil {
|
||||
logrus.Error(err)
|
||||
continue
|
||||
}
|
||||
if comm.ProtoMarshal(v, head) {
|
||||
reqData, err = proto.Marshal(head)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler.SetReq(reqData, false)
|
||||
assist := app.createAssistant(handler)
|
||||
assist.Start()
|
||||
assist.ShowResult()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
obs.Notify(observer.EVENT_FINISH, true)
|
||||
}
|
||||
|
||||
preBtn := widget.NewButtonWithIcon("上一步", theme.NavigateBackIcon(), nil)
|
||||
preBtn.OnTapped = func() {
|
||||
defer closeApp3(perfWin.tabs, common.TOOLBAR_PERF_PB)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_CONF)
|
||||
}
|
||||
|
||||
//layout
|
||||
c := container.NewBorder(container.NewHBox(refeshBtn), container.NewHBox(layout.NewSpacer(), preBtn, nextBtn), nil, nil, app.itemList.ItemList)
|
||||
content.Objects = append(content.Objects, c)
|
||||
app.tabItem.Content = content
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfPb) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_PB
|
||||
}
|
||||
|
||||
func (a *perfPb) OnClose() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *perfPb) createAssistantWithoutConf(handler lib.Handler) lib.Aiassistant {
|
||||
|
||||
param := lib.ParamMgr{
|
||||
Caller: handler,
|
||||
Timeout: time.Duration(a.conf.Pressure.TimeoutMs) * time.Millisecond,
|
||||
Lps: 1,
|
||||
Duration: 1,
|
||||
ResultCh: make(chan *lib.CallResult, 50),
|
||||
}
|
||||
assist, err := lib.NewAssistant(a.obs, param)
|
||||
if err != nil {
|
||||
logrus.Errorf("AI助手初始化错误: %v", err)
|
||||
return nil
|
||||
}
|
||||
return assist
|
||||
}
|
||||
|
||||
//
|
||||
func (a *perfPb) createAssistant(handler lib.Handler) lib.Aiassistant {
|
||||
|
||||
param := lib.ParamMgr{
|
||||
Caller: handler,
|
||||
Timeout: time.Duration(a.conf.Pressure.TimeoutMs) * time.Millisecond,
|
||||
Lps: uint32(a.conf.Pressure.Concurrency),
|
||||
Duration: time.Duration(a.conf.Pressure.DurationS) * time.Second,
|
||||
ResultCh: make(chan *lib.CallResult, 50),
|
||||
}
|
||||
assist, err := lib.NewAssistant(a.obs, param)
|
||||
if err != nil {
|
||||
logrus.Errorf("AI助手初始化错误: %v", err)
|
||||
return nil
|
||||
}
|
||||
return assist
|
||||
}
|
||||
|
||||
type UserLogin struct {
|
||||
req []byte
|
||||
sid string
|
||||
account string
|
||||
}
|
||||
|
||||
func (a *perfPb) loginReq(sid string) (*UserLogin, error) {
|
||||
login := &UserLogin{sid: sid}
|
||||
head := &pb.UserMessage{MainType: "user", SubType: "login"}
|
||||
account := randomdata.SillyName()
|
||||
login.account = account
|
||||
head.Sec = common.BuildSecStr(login.sid, login.account)
|
||||
if comm.ProtoMarshal(&pb.UserLoginReq{
|
||||
Sid: login.sid,
|
||||
Account: login.account,
|
||||
}, head) {
|
||||
logrus.WithField("账号", login.account).Info("登录")
|
||||
data, err := proto.Marshal(head)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
login.req = data
|
||||
|
||||
return login, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go_dreamfactory/cmd/v2/lib"
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type perfResult struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
conf *storage.Config
|
||||
|
||||
itemList common.ItemList
|
||||
|
||||
resultList func() //结果列表
|
||||
resetBtn *widget.Button
|
||||
returnBtn *widget.Button
|
||||
report *widget.Card
|
||||
layout *fyne.Container
|
||||
}
|
||||
|
||||
func (app *perfResult) LazyInit(ptService service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
app.conf = perfWin.UIImpl.config
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_RES, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
app.itemList = *common.NewItemList()
|
||||
app.itemList.ItemList = app.itemList.CreateList()
|
||||
|
||||
//重新开始
|
||||
app.resetBtn = widget.NewButtonWithIcon("再来一次", theme.ContentRedoIcon(), nil)
|
||||
app.resetBtn.Hide()
|
||||
app.resetBtn.OnTapped = func() {
|
||||
defer openApp3(perfWin.tabs, common.TOOLBAR_PERF_TIP)
|
||||
app.itemList.Reset()
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
}
|
||||
|
||||
// 返回
|
||||
app.returnBtn = widget.NewButtonWithIcon("", theme.NavigateBackIcon(), nil)
|
||||
app.returnBtn.Disable()
|
||||
app.returnBtn.OnTapped = func() {
|
||||
defer openApp3(perfWin.tabs, common.TOOLBAR_PERF_CHOOSE)
|
||||
app.itemList.Reset()
|
||||
closeApp3(perfWin.tabs, common.TOOLBAR_PERF_RES)
|
||||
}
|
||||
app.returnBtn.Text = "等待中..."
|
||||
|
||||
//统计Panel
|
||||
app.report = widget.NewCard("测试报告", "登录/创角", container.NewVBox(
|
||||
// widget.NewLabel("结果:"),
|
||||
))
|
||||
app.report.Hide()
|
||||
|
||||
//layout
|
||||
app.layout = container.NewBorder(app.report, container.NewHBox(layout.NewSpacer(), app.resetBtn, app.returnBtn), nil, nil, app.itemList.ItemList)
|
||||
content.Objects = append(content.Objects, app.layout)
|
||||
app.tabItem.Content = content
|
||||
app.listen()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *perfResult) listen() {
|
||||
app.obs.AddListener(observer.EVENT_RESULT, observer.Listener{
|
||||
OnNotify: func(data interface{}, args ...interface{}) {
|
||||
res, ok := data.(*lib.Statistics)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
item := common.Item{
|
||||
Text: fmt.Sprintf("协议名称:%s, 调用次数:%d, 总耗时:%vms, 平均耗时:%vms, 最大耗时:%vms, 最小耗时:%vms",
|
||||
res.Route, res.CallCount, res.ElapseTotal, res.AvgElapse, res.MaxElapse, res.MinElapse),
|
||||
Data: res,
|
||||
}
|
||||
app.itemList.AddItem(item)
|
||||
app.returnBtn.Text = "返回"
|
||||
app.returnBtn.Enable()
|
||||
app.returnBtn.Refresh()
|
||||
app.layout.Refresh()
|
||||
},
|
||||
})
|
||||
|
||||
app.obs.AddListener(observer.EVENT_FINISH, observer.Listener{
|
||||
OnNotify: func(data interface{}, args ...interface{}) {
|
||||
finish, ok := data.(bool)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if finish {
|
||||
app.resetBtn.Show()
|
||||
app.resetBtn.Refresh()
|
||||
app.report.Show()
|
||||
app.report.Refresh()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (app *perfResult) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_RES
|
||||
}
|
||||
|
||||
func (a *perfResult) OnClose() bool {
|
||||
return false
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/service"
|
||||
"go_dreamfactory/cmd/v2/service/observer"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type perfWelcome struct {
|
||||
appAdapter
|
||||
|
||||
obs observer.Observer
|
||||
}
|
||||
|
||||
func (app *perfWelcome) LazyInit(service service.PttService, obs observer.Observer) error {
|
||||
app.obs = obs
|
||||
|
||||
app.tabItem = container.NewTabItemWithIcon(common.TOOLBAR_PERF_TIP, theme.ContentCopyIcon(), nil)
|
||||
content := container.NewMax()
|
||||
content.Objects = []fyne.CanvasObject{}
|
||||
|
||||
wel := widget.NewRichTextFromMarkdown("# 自动化性能测试工具使用说明" +
|
||||
`
|
||||
* 基于Luban工具生成协议文件(json格式)
|
||||
`)
|
||||
for i := range wel.Segments {
|
||||
if seg, ok := wel.Segments[i].(*widget.TextSegment); ok {
|
||||
seg.Style.Alignment = fyne.TextAlignLeading
|
||||
}
|
||||
}
|
||||
|
||||
goBtn := widget.NewButton("开始测试 >>", nil)
|
||||
goBtn.OnTapped = func() {
|
||||
defer closeApp3(perfWin.tabs, common.TOOLBAR_PERF_TIP)
|
||||
openApp3(perfWin.tabs, common.TOOLBAR_PERF_CONF)
|
||||
}
|
||||
app.tabItem.Content = container.NewCenter(
|
||||
container.NewVBox(
|
||||
wel,
|
||||
goBtn,
|
||||
))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *perfWelcome) OpenDefault() string {
|
||||
return common.TOOLBAR_PERF_TIP
|
||||
}
|
||||
|
||||
func (a *perfWelcome) GetAppName() string {
|
||||
return common.TOOLBAR_PERF_TIP
|
||||
}
|
||||
|
||||
func (a *perfWelcome) OnClose() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *perfWelcome) OnDestroy() bool {
|
||||
return true
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/pb"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var perfWin *PerfWindowImpl
|
||||
|
||||
var pbMap map[string]proto.Message //pb
|
||||
|
||||
type PerfWindow interface {
|
||||
WindowInterface
|
||||
}
|
||||
|
||||
type PerfWindowImpl struct {
|
||||
UIImpl
|
||||
parent fyne.Window
|
||||
w fyne.Window
|
||||
statusbar *statusBar //状态栏
|
||||
tabs *appContainer //tabs
|
||||
toolbar *toolBar //工具条
|
||||
}
|
||||
|
||||
func NewPerfWindow(ui *UIImpl, parent fyne.Window) PerfWindow {
|
||||
|
||||
pw := &PerfWindowImpl{
|
||||
UIImpl: *ui,
|
||||
parent: parent,
|
||||
}
|
||||
|
||||
perfWin = pw
|
||||
|
||||
pbMap = make(map[string]proto.Message)
|
||||
|
||||
pw.initPb()
|
||||
return pw
|
||||
}
|
||||
|
||||
func (ui *PerfWindowImpl) CreateWindow(_ string, width, height float32, _ bool) {
|
||||
title := fmt.Sprintf(common.APP_WIN_TITLE, "自动化性能测试工具", ui.app.Metadata().Version, ui.app.Metadata().Build, common.APP_NAME)
|
||||
w := ui.app.NewWindow(title)
|
||||
ui.AddWindow("main", w)
|
||||
ui.w = w
|
||||
|
||||
w.Resize(fyne.NewSize(width, height))
|
||||
w.CenterOnScreen()
|
||||
w.SetCloseIntercept(func() {
|
||||
ui.parent.Show()
|
||||
})
|
||||
|
||||
ui.statusbar = newStatusBar()
|
||||
toolbar := widget.NewToolbar(
|
||||
// widget.NewToolbarAction(theme.MediaVideoIcon(), func() {
|
||||
// openApp(ui.tabs, common.TOOLBAR_PERF_TIP)
|
||||
// }),
|
||||
// widget.NewToolbarAction(theme.MediaVideoIcon(), func() {
|
||||
// openApp(ui.tabs, common.TOOLBAR_PERF_CONF)
|
||||
// }),
|
||||
)
|
||||
ui.toolbar = newToolBar(toolbar)
|
||||
|
||||
ui.tabs = newAppContainer(perfRegister, ui.pttService, ui.obs)
|
||||
content := container.NewBorder(ui.toolbar.toolbar, ui.statusbar.widget, nil, nil, ui.tabs)
|
||||
ui.w.SetContent(content)
|
||||
|
||||
defer func() {
|
||||
appName, err := ui.tabs.openDefaultApp(common.TOOLBAR_PERF_TIP)
|
||||
if err != nil {
|
||||
logrus.WithField("appName", appName).Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
w.SetCloseIntercept(func() {
|
||||
ui.parent.Show()
|
||||
w.Close()
|
||||
})
|
||||
w.Show()
|
||||
}
|
||||
|
||||
func (ui *PerfWindowImpl) registerPb(route string, pb proto.Message) {
|
||||
typeOf := reflect.TypeOf(pb)
|
||||
pbName := typeOf.Elem().Name()
|
||||
if strings.HasSuffix(pbName, "Req") {
|
||||
s := strings.SplitN(route, ".", 2)
|
||||
low := strings.ToLower(pbName)
|
||||
if strings.Contains(low, s[0]) &&
|
||||
strings.Contains(low, s[1]) {
|
||||
pbMap[route] = pb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ui *PerfWindowImpl) initPb() {
|
||||
ui.registerPb("user.login", &pb.UserLoginReq{})
|
||||
ui.registerPb("user.create", &pb.UserCreateReq{})
|
||||
ui.registerPb("sys.funclist", &pb.SysFuncListReq{})
|
||||
}
|
@ -42,17 +42,6 @@ func openApp2(ac *appContainer, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func openApp3(ac *appContainer, name string) {
|
||||
for _, app := range perfRegister {
|
||||
if app.GetAppName() == name {
|
||||
err := ac.openApp(app)
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Errorf("%s %v", app.GetAppName(), err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func closeApp3(ac *appContainer, name string) {
|
||||
for _, appItem := range ac.Items {
|
||||
if appItem.Text == name {
|
||||
|
53
cmd/v2/ui/tool_menu.go
Normal file
53
cmd/v2/ui/tool_menu.go
Normal file
@ -0,0 +1,53 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type toolMenu struct {
|
||||
*fyne.MainMenu
|
||||
sysMenu *fyne.Menu
|
||||
appMenus []*fyne.MenuItem
|
||||
|
||||
//退出
|
||||
quite *fyne.MenuItem
|
||||
|
||||
// 工具
|
||||
toolMenu *fyne.Menu
|
||||
//同步配置
|
||||
syncConfMenu *fyne.MenuItem
|
||||
}
|
||||
|
||||
func newToolMenu() *toolMenu {
|
||||
var mm toolMenu
|
||||
// system
|
||||
mm.appMenus = make([]*fyne.MenuItem, len(toolRegister))
|
||||
for i, app := range toolRegister {
|
||||
mm.appMenus[i] = fyne.NewMenuItem(app.GetAppName(), func() {
|
||||
err := toolWin.at.openApp(app)
|
||||
if err != nil {
|
||||
logrus.Errorf("打开 %s, err:%v", app.GetAppName(), err)
|
||||
}
|
||||
})
|
||||
mm.appMenus[i].Icon = app.Icon()
|
||||
}
|
||||
mm.quite = fyne.NewMenuItem("退出", toolWin.quiteHandle)
|
||||
mm.quite.Icon = theme.LogoutIcon()
|
||||
mm.quite.IsQuit = true
|
||||
mm.sysMenu = fyne.NewMenu("应用", mm.appMenus...)
|
||||
mm.sysMenu.Items = append(mm.sysMenu.Items, fyne.NewMenuItemSeparator(), mm.quite)
|
||||
|
||||
//tool
|
||||
mm.syncConfMenu = fyne.NewMenuItem("同步云配置", toolWin.syncConfig)
|
||||
mm.toolMenu = fyne.NewMenu("工具",
|
||||
mm.syncConfMenu,
|
||||
)
|
||||
|
||||
mm.MainMenu = fyne.NewMainMenu(
|
||||
mm.sysMenu,
|
||||
mm.toolMenu,
|
||||
)
|
||||
return &mm
|
||||
}
|
@ -1,11 +1,18 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go_dreamfactory/cmd/v2/lib/common"
|
||||
"go_dreamfactory/cmd/v2/lib/storage"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -24,6 +31,7 @@ type ToolWindowImpl struct {
|
||||
tb *toolBar //工具条
|
||||
sb *statusBar //状态栏
|
||||
at *appContainer //tabs
|
||||
mm *toolMenu //菜单
|
||||
}
|
||||
|
||||
func NewToolWindow(ui *UIImpl, parent fyne.Window) ToolWindow {
|
||||
@ -78,11 +86,13 @@ func (ui *ToolWindowImpl) CreateWindow(title string, width, height float32, _ bo
|
||||
ui.AddWindow("tool", w)
|
||||
ui.w = w
|
||||
|
||||
ui.mm = newToolMenu()
|
||||
ui.w.SetMainMenu(ui.mm.MainMenu)
|
||||
// content
|
||||
content := container.NewBorder(ui.tb.toolbar, ui.sb.widget,
|
||||
nil, nil, ui.at)
|
||||
ui.w.SetContent(content)
|
||||
appName, err := ui.at.openDefaultApp(common.TOOLBAR_WEL)
|
||||
appName, err := ui.at.openWelcome()
|
||||
if err != nil {
|
||||
logrus.WithField("appName", appName).Error(err)
|
||||
}
|
||||
@ -105,3 +115,50 @@ func (ui *ToolWindowImpl) CreateWindow(title string, width, height float32, _ bo
|
||||
})
|
||||
w.Show()
|
||||
}
|
||||
func (ui *ToolWindowImpl) quiteHandle() {
|
||||
dialog.ShowConfirm("提示", "确定退出吗", func(b bool) {
|
||||
if !b {
|
||||
return
|
||||
}
|
||||
ui.app.Quit()
|
||||
}, ui.w)
|
||||
}
|
||||
|
||||
func (ui *ToolWindowImpl) syncConfig() {
|
||||
cli := http.Client{Timeout: time.Second * 10}
|
||||
r, err := cli.Get("http://10.0.0.9:8081/prd/config.json")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
dialog.ShowError(err, ui.w)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
b, err2 := ioutil.ReadAll(r.Body)
|
||||
if err2 != nil {
|
||||
logrus.Error(err)
|
||||
dialog.ShowError(err2, ui.w)
|
||||
return
|
||||
}
|
||||
if len(b) == 0 {
|
||||
dialog.ShowError(errors.New("云配置可能不存在"), ui.w)
|
||||
return
|
||||
}
|
||||
config := &storage.Config{}
|
||||
if err := json.Unmarshal(b, config); err != nil {
|
||||
dialog.ShowError(fmt.Errorf("云配置解析错误: %s", err), ui.w)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := storage.NewOSStorage()
|
||||
s.StoreConfig(config)
|
||||
|
||||
dialog.ShowConfirm("提示", "云配置同步成功,需要重新打开窗口", func(b bool) {
|
||||
if !b {
|
||||
return
|
||||
}
|
||||
ui.parent.Show()
|
||||
ui.w.Close()
|
||||
}, ui.w)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user