From 67d44ea967cf6e1befc5017427baf558cfee1fe6 Mon Sep 17 00:00:00 2001 From: jager Date: Wed, 20 Oct 2021 18:47:32 +0800 Subject: [PATCH] view --- cmd/wechat/main.go | 190 ++------------------------------------------- types/types.go | 19 +++++ view/editor.go | 50 ------------ view/view.go | 159 ++++++++++++++++++++++++++++--------- ws/ws.go | 110 ++++++++++++++++++++++++++ 5 files changed, 261 insertions(+), 267 deletions(-) create mode 100644 types/types.go delete mode 100644 view/editor.go create mode 100644 ws/ws.go diff --git a/cmd/wechat/main.go b/cmd/wechat/main.go index b2582e7..6bcea22 100644 --- a/cmd/wechat/main.go +++ b/cmd/wechat/main.go @@ -10,198 +10,24 @@ * */ -/** - * @Author: jager - * @Email: lhj168os@gmail.com - * @File: view - * @Date: 2021/10/15 6:27 下午 - * @package: view - * @Version: v1.0.0 - * - * @Description: - * - */ - package main import ( - "fmt" - "github.com/rocket049/gocui" "log" - "math/rand" - "time" -) - -var ( - viewArr = []string{"msg", "send"} - active = 1 + "wechat/view" ) -func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { - if _, err := g.SetCurrentView(name); err != nil { - return nil, err - } - return g.SetViewOnTop(name) -} - -func nextView(g *gocui.Gui, v *gocui.View) error { - nextIndex := (active + 1) % len(viewArr) - name := viewArr[nextIndex] - - if _, err := setCurrentViewOnTop(g, name); err != nil { - return err - } - - active = nextIndex - return nil -} - -func layout(g *gocui.Gui) error { - maxX, maxY := g.Size() - if v, err := g.SetView("msg", 0, 0, maxX/4*3-1, maxY/5*4-1); err != nil { - if err != gocui.ErrUnknownView { - return err - } - v.Title = "message" - v.Autoscroll = true - v.Wrap = true - } - - if v, err := g.SetView("send", 0, maxY/5*4, maxX/4*3-1, maxY-1); err != nil { - if err != gocui.ErrUnknownView { - return err - } - v.Title = "send" - v.Editable = true - v.Wrap = true - v.Autoscroll = true - if _, err = setCurrentViewOnTop(g, "send"); err != nil { - return err - } - } - if v, err := g.SetView("online", maxX/4*3, 0, maxX-1, maxY-1); err != nil { - if err != gocui.ErrUnknownView { - return err - } - v.Title = "online" - } - return nil -} - -func quit(g *gocui.Gui, v *gocui.View) error { - return gocui.ErrQuit -} - -func sendMsg(g *gocui.Gui, v *gocui.View) error { - byts := v.ReadEditor() - if len(byts) <= 0 { - v.Clear() - return v.SetCursor(0, 0) - } - str := string(byts) - msg, err := g.View("msg") - if err != nil { - return err - } - - flag := rand.Intn(3) - var name string - switch flag { - case 0: - name = "jager" - case 1: - name = "zhe" - case 2: - name = "lu" - } - - msgStr := fmt.Sprintf("[%d]%s(%s): %s\n", flag, name, time.Now().Format("01-02 15:04:05"), str) - _, err = msg.Write([]byte(msgStr)) - if err == nil { - v.Clear() - err = v.SetCursor(0, 0) - } - return err -} - -func arrowUp(g *gocui.Gui, v *gocui.View) error { - if v != nil { - ox, oy := v.Origin() - cx, cy := v.Cursor() - if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 { - if err := v.SetOrigin(ox, oy-1); err != nil { - return err - } - } - } - return nil -} - -func arrowDown(g *gocui.Gui, v *gocui.View) error { - if v != nil { - cx, cy := v.Cursor() - if err := v.SetCursor(cx, cy+1); err != nil { - ox, oy := v.Origin() - if err := v.SetOrigin(ox, oy+1); err != nil { - return err - } - } - } - return nil -} - -func backspace(g *gocui.Gui, v *gocui.View) error { - v.EditDelete(true) - return nil -} - func main() { - g, err := gocui.NewGui(gocui.OutputNormal) - if err != nil { - log.Panic(err) - } - defer g.Close() - - g.Highlight = true - g.Cursor = true - g.SelFgColor = gocui.ColorGreen + //ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT) + //defer cancel() - g.SetManagerFunc(layout) + view.OnMessage("dekdmkwenkwndklwenklndk\n") + view.UpdateOnline("杰(13160676597)\n哲(10086)\n文(10010)\n") + view.UpdateOnline("杰(13160676597)\n哲(10086)\n文(10010)\n") - if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("send", gocui.KeyDelete, gocui.ModNone, backspace); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("send", gocui.KeyBackspace, gocui.ModNone, backspace); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("send", gocui.KeyBackspace2, gocui.ModNone, backspace); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("send", gocui.KeyEnter, gocui.ModNone, sendMsg); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("msg", gocui.KeyArrowUp, gocui.ModNone, arrowUp); err != nil { - log.Panic(err) - } - - if err := g.SetKeybinding("msg", gocui.KeyArrowDown, gocui.ModNone, arrowDown); err != nil { - log.Panic(err) - } - err = g.MainLoop() + err := view.Run() if err != nil { - log.Println(err) + log.Fatal(err) } } diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000..d9f55b1 --- /dev/null +++ b/types/types.go @@ -0,0 +1,19 @@ +/** + * @Author: jager + * @Email: lhj168os@gmail.com + * @File: types + * @Date: 2021/10/20 5:03 下午 + * @package: types + * @Version: v1.0.0 + * + * @Description: + * + */ + +package types + +type Msg struct { + MsgID int `json:"msg_id"` + Seq int64 `json:"seq"` + Msg string `json:"msg"` +} diff --git a/view/editor.go b/view/editor.go deleted file mode 100644 index b05ec6f..0000000 --- a/view/editor.go +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @Author: jager - * @Email: lhj168os@gmail.com - * @File: editor - * @Date: 2021/10/19 6:19 下午 - * @package: view - * @Version: v1.0.0 - * - * @Description: - * - */ - -package view - -import ( - "bytes" - "github.com/jroimartin/gocui" - "github.com/mattn/go-runewidth" -) - -func modifyCJK(p []byte) []byte { - buf := bytes.NewBuffer(bytes.Trim(p, " \n\t")) - sz := len(buf.String()) - buf1 := bytes.NewBufferString("") - var r rune - var wr bool - for i := 0; i < sz; i++ { - r, _, _ = buf.ReadRune() - if r != rune(0) && wr == false { - buf1.WriteRune(r) - } else if wr == true { - if r != rune(' ') { - buf1.WriteRune(r) - } - } - wr = runewidth.RuneWidth(r) > 1 - } - return buf1.Bytes() -} - -//ReadEditor Read byte array from editor 'v', delete the auto appended blank after CJK runes. -func ReadEditor(v *gocui.View) []byte { - var b = make([]byte, 300) - n, _ := v.Read(b) - if n > 0 { - return modifyCJK(b[:n]) - } else { - return nil - } -} diff --git a/view/view.go b/view/view.go index 02063b5..70d8114 100644 --- a/view/view.go +++ b/view/view.go @@ -14,14 +14,16 @@ package view import ( "fmt" - "github.com/jageros/hawox/contextx" - "github.com/jroimartin/gocui" + "github.com/rocket049/gocui" "log" + "time" + "wechat/ws" ) var ( - viewArr = []string{"v1", "v2"} + viewArr = []string{"msg", "send"} active = 1 + gg *gocui.Gui ) func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) { @@ -35,60 +37,42 @@ func nextView(g *gocui.Gui, v *gocui.View) error { nextIndex := (active + 1) % len(viewArr) name := viewArr[nextIndex] - out, err := g.View("v2") - if err != nil { - return err - } - fmt.Fprintln(out, "\nGoing from view "+v.Name()+" to "+name) - if _, err := setCurrentViewOnTop(g, name); err != nil { return err } - if nextIndex == 1 { - fmt.Fprintln(out, "") - } - - if nextIndex == 0 || nextIndex == 3 { - g.Cursor = true - } else { - g.Cursor = false - } - active = nextIndex return nil } func layout(g *gocui.Gui) error { maxX, maxY := g.Size() - if v, err := g.SetView("v1", 0, 0, maxX/4*3-1, maxY/5*4-1); err != nil { + if v, err := g.SetView("msg", 0, 0, maxX/4*3-1, maxY/5*4-1); err != nil { if err != gocui.ErrUnknownView { return err } v.Title = "message" - //v.Editable = true + v.Autoscroll = true v.Wrap = true } - if v, err := g.SetView("v2", 0, maxY/5*4-1, maxX/4*3-1, maxY-1); err != nil { + if v, err := g.SetView("send", 0, maxY/5*4, maxX/4*3-1, maxY-1); err != nil { if err != gocui.ErrUnknownView { return err } v.Title = "send" v.Editable = true - v.Overwrite = true v.Wrap = true v.Autoscroll = true - if _, err = setCurrentViewOnTop(g, "v2"); err != nil { + if _, err = setCurrentViewOnTop(g, "send"); err != nil { return err } } - if v, err := g.SetView("v3", maxX/4*3-1, 0, maxX-1, maxY-1); err != nil { + if v, err := g.SetView("online", maxX/4*3, 0, maxX-1, maxY-1); err != nil { if err != gocui.ErrUnknownView { return err } v.Title = "online" - v.Wrap = true } return nil } @@ -97,13 +81,91 @@ func quit(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit } -func Init(ctx contextx.Context) { - g, err := gocui.NewGui(gocui.OutputNormal) +func OnMessage(msg string) { + gg.Update(func(gui *gocui.Gui) error { + v, err := gui.View("msg") + if err != nil { + return err + } + _, err = v.Write([]byte(msg)) + return err + }) +} + +func UpdateOnline(msg string) { + gg.Update(func(gui *gocui.Gui) error { + v, err := gui.View("online") + if err != nil { + return err + } + v.Clear() + _, err = v.Write([]byte(msg)) + return err + }) +} + +func sendMsg(g *gocui.Gui, v *gocui.View) error { + byts := v.ReadEditor() + if len(byts) <= 0 { + v.Clear() + return v.SetCursor(0, 0) + } + str := string(byts) + msg, err := g.View("msg") if err != nil { - log.Panicln(err) + return err + } + + n, err := ws.SendMsg(str) + if err != nil { + return err + } + + msgStr := fmt.Sprintf("[%d]%s(%s): %s\n", n, "我", time.Now().Format("15:04:05"), str) + _, err = msg.Write([]byte(msgStr)) + if err == nil { + v.Clear() + err = v.SetCursor(0, 0) } - defer g.Close() + return err +} +func arrowUp(g *gocui.Gui, v *gocui.View) error { + if v != nil { + ox, oy := v.Origin() + cx, cy := v.Cursor() + if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 { + if err := v.SetOrigin(ox, oy-1); err != nil { + return err + } + } + } + return nil +} + +func arrowDown(g *gocui.Gui, v *gocui.View) error { + if v != nil { + cx, cy := v.Cursor() + if err := v.SetCursor(cx, cy+1); err != nil { + ox, oy := v.Origin() + if err := v.SetOrigin(ox, oy+1); err != nil { + return err + } + } + } + return nil +} + +func backspace(g *gocui.Gui, v *gocui.View) error { + v.EditDelete(true) + return nil +} + +func init() { + g, err := gocui.NewGui(gocui.OutputNormal) + if err != nil { + log.Panic(err) + } g.Highlight = true g.Cursor = true g.SelFgColor = gocui.ColorGreen @@ -111,13 +173,40 @@ func Init(ctx contextx.Context) { g.SetManagerFunc(layout) if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { - log.Panicln(err) + log.Panic(err) } + if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil { - log.Panicln(err) + log.Panic(err) } - ctx.Go(func(ctx contextx.Context) error { - return g.MainLoop() - }) + if err := g.SetKeybinding("send", gocui.KeyDelete, gocui.ModNone, backspace); err != nil { + log.Panic(err) + } + + if err := g.SetKeybinding("send", gocui.KeyBackspace, gocui.ModNone, backspace); err != nil { + log.Panic(err) + } + + if err := g.SetKeybinding("send", gocui.KeyBackspace2, gocui.ModNone, backspace); err != nil { + log.Panic(err) + } + + if err := g.SetKeybinding("send", gocui.KeyEnter, gocui.ModNone, sendMsg); err != nil { + log.Panic(err) + } + + if err := g.SetKeybinding("msg", gocui.KeyArrowUp, gocui.ModNone, arrowUp); err != nil { + log.Panic(err) + } + + if err := g.SetKeybinding("msg", gocui.KeyArrowDown, gocui.ModNone, arrowDown); err != nil { + log.Panic(err) + } + gg = g +} + +func Run() error { + defer gg.Close() + return gg.MainLoop() } diff --git a/ws/ws.go b/ws/ws.go new file mode 100644 index 0000000..e72316d --- /dev/null +++ b/ws/ws.go @@ -0,0 +1,110 @@ +/** + * @Author: jager + * @Email: lhj168os@gmail.com + * @File: service + * @Date: 2021/7/8 5:30 下午 + * @package: service + * @Version: v1.0.0 + * + * @Description: + * + */ + +package ws + +import ( + "encoding/json" + "fmt" + "github.com/gin-gonic/gin" + "github.com/jageros/hawox/contextx" + "github.com/jageros/hawox/errcode" + "github.com/jageros/hawox/httpx" + "github.com/jageros/hawox/logx" + "gopkg.in/olahol/melody.v1" + "sync" + "time" + "wechat/types" +) + +var ( + seq int64 + mux sync.Mutex + names = map[string]string{ + "13160676597": "杰", + "13612225480": "文", + "13750043941": "哲", + } +) + +var ss *service + +type service struct { + ctx contextx.Context + m *melody.Melody + callTimeout time.Duration +} + +func Init(ctx contextx.Context, r *gin.RouterGroup, relativePath string) { + ss = &service{ + ctx: ctx, + m: melody.New(), + callTimeout: time.Second * 5, + } + ss.m.HandleMessageBinary(ss.handleMessage) + ss.m.HandleConnect(ss.onConnect) + ss.m.HandleDisconnect(ss.onDisconnect) + r.GET(relativePath, ss.handler) +} + +func (s *service) handler(c *gin.Context) { + uid := c.GetHeader("uid") + if _, ok := names[uid]; !ok { + httpx.ErrInterrupt(c, errcode.InvalidParam) + return + } + err := s.m.HandleRequestWithKeys(c.Writer, c.Request, map[string]interface{}{"uid": uid}) + if err != nil { + httpx.ErrInterrupt(c, errcode.WithErrcode(-1, err)) + } +} + +func (s *service) onConnect(session *melody.Session) { + +} + +func (s *service) onDisconnect(session *melody.Session) { + +} + +func (s *service) handleMessage(session *melody.Session, bytes []byte) { + start := time.Now() + uid, exist := session.Get("uid") + if !exist { + return + } + + name := names[uid.(string)] + + mux.Lock() + defer mux.Unlock() + seq += 1 + + msg := fmt.Sprintf("[%d]%s(%s): %s\n", seq, name, time.Now().Format("15:04:05"), string(bytes)) + + var resp = &types.Msg{ + MsgID: 1, + Msg: msg, + } + bty, err := json.Marshal(resp) + if err != nil { + return + } + err = s.m.Broadcast(bty) + if err != nil { + logx.Error(err) + } + take := time.Now().Sub(start) + if take > time.Millisecond*100 { + logx.Warnf("send msg take: %s", take.String()) + } +} \ No newline at end of file