Final PR #1

Merged
raul merged 9 commits from testing into main 2024-04-14 10:05:00 +02:00
5 changed files with 219 additions and 15 deletions

94
cmd/client.go Normal file
View File

@ -0,0 +1,94 @@
/*
Copyright © 2024 Raul
*/
package cmd
import (
"bufio"
"fmt"
"github.com/jroimartin/gocui"
"github.com/spf13/cobra"
"log"
"net"
"os"
)
// clientCmd represents the client command
var clientCmd = &cobra.Command{
Use: "client",
Short: "Connect to a mini-chat server",
Long: `Connect to a mini-chat server.
Example:
./mini-chat client --ip 192.168.0.50 --port 1337`,
Run: func(cmd *cobra.Command, args []string) {
client(cmd)
},
}
var err error
var conn net.Conn
func init() {
rootCmd.AddCommand(clientCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// clientCmd.PersistentFlags().String("foo", "", "A help for foo")
clientCmd.Flags().String("ip", "", "Server to connect to")
clientCmd.Flags().String("port", "1302", "Port to connect to")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// clientCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
func client(cmd *cobra.Command) {
port, _ := cmd.Flags().GetString("port")
ip, _ := cmd.Flags().GetString("ip")
if ip == "" {
fmt.Println("Not enough arguments, run \"-h\" parameter to see all the parameters!")
os.Exit(0)
}
if port == "" {
port = "1302"
}
socket := ip + ":" + port
conn, err = net.Dial("tcp", socket)
cobra.CheckErr(err)
defer conn.Close()
reply := make([]byte, 1024)
conn.Read(reply)
fmt.Print(string(reply))
msg, err := bufio.NewReader(os.Stdin).ReadString('\n')
cobra.CheckErr(err)
conn.Write([]byte(msg))
ui(conn)
}
func sendmsg(g *gocui.Gui, v *gocui.View) error {
textarea, err := g.View("textarea")
if err != nil {
log.Panicln(err)
}
message := textarea.Buffer()
msg := string(message)
if msg == "" {
return nil
}
if msg == "" {
return nil
}
fmt.Fprint(conn, msg)
textarea.Clear()
textarea.SetCursor(0, 0)
return nil
}

View File

@ -90,25 +90,11 @@ func masterReceiver(slaveChannel chan<- string, masterChannel <-chan string) {
} }
} }
// func receiver(conn net.Conn, ch chan string) {
// fmt.Println("THE RECEIVER HAS BEEN STARTED, YOU CAN ONLY SEE THIS MESSAGE ONCE")
// receiverIsStarted = false
// for {
// select {
// case otherMessage := <-ch:
// conn.Write([]byte(otherMessage))
// default:
// }
// }
// }
func handleConn(conn net.Conn, slaveChannel <-chan string, masterChannel chan<- string) { func handleConn(conn net.Conn, slaveChannel <-chan string, masterChannel chan<- string) {
defer conn.Close() defer conn.Close()
//var otherMessage string
go func() { go func() {
for { for {
//select {
message := <-slaveChannel message := <-slaveChannel
conn.Write([]byte(message)) conn.Write([]byte(message))
} }

108
cmd/ui.go Normal file
View File

@ -0,0 +1,108 @@
package cmd
import (
"fmt"
"github.com/jroimartin/gocui"
"github.com/nsf/termbox-go"
"log"
"net"
"time"
)
func ui(conn net.Conn) {
g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
log.Panicln(err)
}
defer g.Close()
g.SetManagerFunc(layout)
g.Mouse = true
g.Cursor = true
initKeybindings(g)
go listener(g, conn)
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}
func listener(g *gocui.Gui, conn net.Conn) {
time.Sleep(time.Second)
chatbox, err := g.View("chatbox")
if err != nil {
log.Panicln(err)
}
for {
reply := make([]byte, 2048)
_, err := conn.Read(reply)
if err != nil {
g.Close()
log.Fatalf("Server closed connection\n")
}
fmt.Fprintln(chatbox, string(reply))
termbox.Interrupt()
}
}
func quit(*gocui.Gui, *gocui.View) error {
return gocui.ErrQuit
}
func initKeybindings(g *gocui.Gui) error {
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("button", gocui.MouseLeft, gocui.ModNone, sendmsg); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("textarea", gocui.KeyEnter, gocui.ModNone, sendmsg); err != nil {
log.Panicln(err)
}
return nil
}
func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
if chatbox, err := g.SetView("chatbox", 2, 1, maxX/2+40, maxY-6); err != nil {
if err != gocui.ErrUnknownView {
return err
}
chatbox.Title = "Chat Box"
}
if button, err := g.SetView("button", maxX/2+32, maxY-4, maxX/2+40, maxY-2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
//button.BgColor = gocui.ColorRed
button.Wrap = true
button.Frame = true
fmt.Fprintln(button, "Send it")
}
if textarea, err := g.SetView("textarea", 2, maxY-4, maxX/2+28, maxY-2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
if _, err := g.SetCurrentView("textarea"); err != nil {
log.Panicln(err)
}
textarea.Title = "Send message"
textarea.Wrap = true
textarea.Editable = true
}
// if currentUsers, err := g.SetView("currentUsers", maxX/2+42, 1, maxX-6, maxY-6); err != nil {
// if err != gocui.ErrUnknownView {
// return err
// }
// currentUsers.Title = "Connected users"
// }
return nil
}

8
go.mod
View File

@ -2,9 +2,15 @@ module mini-chat
go 1.22.1 go 1.22.1
require github.com/spf13/cobra v1.8.0 require (
github.com/jroimartin/gocui v0.5.0
github.com/nsf/termbox-go v1.1.1
github.com/spf13/cobra v1.8.0
)
require ( require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
) )

10
go.sum
View File

@ -1,6 +1,16 @@
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jroimartin/gocui v0.5.0 h1:DCZc97zY9dMnHXJSJLLmx9VqiEnAj0yh0eTNpuEtG/4=
github.com/jroimartin/gocui v0.5.0/go.mod h1:l7Hz8DoYoL6NoYnlnaX6XCNR62G7J5FfSW5jEogzaxE=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=