From 8d7490614743e013b235644bfa2019f671522dc1a3e87a065c9af62e94f63cd8 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sun, 28 Apr 2024 18:03:43 +0300 Subject: [PATCH] Chatting ability --- cmd/client/gui.go | 69 ++++++++++++++++++++++++++++++++++++++++------ cmd/client/main.go | 15 ++++++++-- cmd/server/gui.go | 1 + cmd/server/main.go | 12 ++++++++ doc/features.texi | 3 +- doc/proto.texi | 2 +- internal/var.go | 1 + 7 files changed, 91 insertions(+), 12 deletions(-) diff --git a/cmd/client/gui.go b/cmd/client/gui.go index 4b06cac..4f4051c 100644 --- a/cmd/client/gui.go +++ b/cmd/client/gui.go @@ -17,16 +17,19 @@ package main import ( "fmt" + "log" "sort" "github.com/jroimartin/gocui" + vors "go.stargrave.org/vors/v3/internal" ) var ( - GUI *gocui.Gui - GUIReady bool - GUIReadyC = make(chan struct{}) - GUIMaxY int + GUI *gocui.Gui + GUIReady bool + GUIReadyC = make(chan struct{}) + GUIMaxY int + CurrentView = 0 ) func guiQuit(gui *gocui.Gui, v *gocui.View) error { @@ -39,19 +42,65 @@ func mute(gui *gocui.Gui, v *gocui.View) error { return nil } +func tabHandle(gui *gocui.Gui, v *gocui.View) error { + sids := make([]int, 0, len(Streams)+1) + sids = append(sids, -1) + for sid := range Streams { + sids = append(sids, int(sid)) + } + sort.Ints(sids) + if CurrentView+1 >= len(sids) { + CurrentView = 0 + } else { + CurrentView++ + } + if CurrentView == 0 { + gui.SetCurrentView("chat") + } else { + gui.SetCurrentView(Streams[byte(sids[CurrentView])].name) + } + return nil +} + +func chatEnter(gui *gocui.Gui, v *gocui.View) error { + msg := v.Buffer() + if len(msg) > 1 { + Ctrl <- vors.ArgsEncode([]byte(vors.CmdChat), []byte(msg[:len(msg)-1])) + log.Println("me:", msg[:len(msg)-1]) + } + v.Clear() + v.SetCursor(0, 0) + return nil +} + func guiLayout(gui *gocui.Gui) error { var maxX int maxX, GUIMaxY = gui.Size() prevY := 0 - v, err := gui.SetView("logs", 0, prevY, maxX-1, prevY+10+2) - prevY += 10 + 2 + v, err := gui.SetView("logs", 0, prevY, maxX-1, prevY+7+2) + prevY += 7 + 2 if err != nil { if err != gocui.ErrUnknownView { return err } v.Title = fmt.Sprintf("Logs room=%s", *Room) v.Autoscroll = true + v.Wrap = true + } + v, err = gui.SetView("chat", 0, prevY, maxX-1, prevY+2) + if err != nil { + if err != gocui.ErrUnknownView { + return err + } + v.Title = "chat" + v.Editable = true + if err := GUI.SetKeybinding( + "chat", gocui.KeyEnter, gocui.ModNone, chatEnter, + ); err != nil { + return err + } } + prevY += 3 sids := make([]int, 0, len(Streams)) for sid := range Streams { sids = append(sids, int(sid)) @@ -65,7 +114,11 @@ func guiLayout(gui *gocui.Gui) error { if err != gocui.ErrUnknownView { return err } - v.Title = stream.name + if stream.name == *Name { + v.Title = ">" + stream.name + "<" + } else { + v.Title = stream.name + } } _, err = gui.SetView(stream.name+"-vol", maxX/2, prevY, maxX-1, prevY+2) prevY += 3 @@ -78,7 +131,7 @@ func guiLayout(gui *gocui.Gui) error { if !GUIReady { close(GUIReadyC) GUIReady = true - gui.SetCurrentView(*Name) + gui.SetCurrentView("chat") } return nil } diff --git a/cmd/client/main.go b/cmd/client/main.go index 902492b..620dee6 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -312,10 +312,13 @@ func main() { GUI.SelFgColor = gocui.ColorCyan GUI.Highlight = true GUI.SetManagerFunc(guiLayout) - if err := GUI.SetKeybinding("", 'q', gocui.ModNone, guiQuit); err != nil { + if err := GUI.SetKeybinding("", gocui.KeyTab, gocui.ModNone, tabHandle); err != nil { log.Fatal(err) } - if err := GUI.SetKeybinding("", gocui.KeyEnter, gocui.ModNone, mute); err != nil { + if err := GUI.SetKeybinding("", gocui.KeyF1, gocui.ModNone, mute); err != nil { + log.Fatal(err) + } + if err := GUI.SetKeybinding("", gocui.KeyF10, gocui.ModNone, guiQuit); err != nil { log.Fatal(err) } @@ -545,6 +548,14 @@ func main() { continue } s.muted = false + case vors.CmdChat: + sid := args[1][0] + s := Streams[sid] + if s == nil { + log.Println("unknown sid:", sid) + continue + } + log.Println(s.name, ":", string(args[2])) default: log.Fatal("unexpected cmd:", cmd) } diff --git a/cmd/server/gui.go b/cmd/server/gui.go index 5d2e121..f2161c1 100644 --- a/cmd/server/gui.go +++ b/cmd/server/gui.go @@ -51,6 +51,7 @@ func guiLayout(gui *gocui.Gui) error { } v.Title = "Logs" v.Autoscroll = true + v.Wrap = true } roomNames := make([]string, 0, len(Rooms)) for n := range Rooms { diff --git a/cmd/server/main.go b/cmd/server/main.go index 9ede9f6..75d0b07 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -328,6 +328,18 @@ func newPeer(conn *net.TCPConn) { } go func(tx chan []byte) { tx <- s }(p.tx) } + case vors.CmdChat: + if len(args) != 2 { + logger.Error("wrong len(args)") + continue + } + msg := vors.ArgsEncode([]byte(vors.CmdChat), []byte{peer.sid}, args[1]) + for _, p := range room.peers { + if p.sid == peer.sid { + continue + } + go func(tx chan []byte) { tx <- msg }(p.tx) + } default: logger.Error("unknown", "cmd", cmd) } diff --git a/doc/features.texi b/doc/features.texi index 2d6c695..279c121 100644 --- a/doc/features.texi +++ b/doc/features.texi @@ -18,7 +18,8 @@ server's public key knowledge. @item Fast ChaCha20 encryption with SipHash24 message authentication. -@item Rooms, optionally password protected. +@item Rooms, optionally password protected. Peers are able to broadcast +text message to everyone in the room. @item Fancy TUI client with mute-toggle ability by external utilities. diff --git a/doc/proto.texi b/doc/proto.texi index 1e2d754..57a7a83 100644 --- a/doc/proto.texi +++ b/doc/proto.texi @@ -93,4 +93,4 @@ firewalls. Clients are notified about new peers appearance with @code{ADD} commands, telling their SIDs, usernames and keys. @code{DEL} notifies about leaving peers. @code{MUTED}, @code{UNMUTED} notifies peer's mute -toggling. +toggling. @code{CHAT} broadcasts the message in the room. diff --git a/internal/var.go b/internal/var.go index 97f6d19..2cb501d 100644 --- a/internal/var.go +++ b/internal/var.go @@ -15,6 +15,7 @@ const ( CmdDel = "DEL" CmdMuted = "MUTED" CmdUnmuted = "UNMUTED" + CmdChat = "CHAT" ) var ( -- 2.44.0