Nuclear refactoring
Go audit / audit (pull_request) Successful in 1m48s
Details
Go audit / audit (pull_request) Successful in 1m48s
Details
I've finally managed to properly rebuild the project, it's not extremely clean, but compared to before, it's infinitely more functional and expandable.
This commit is contained in:
parent
cec33907b7
commit
80da12cfcf
|
@ -1,33 +1,37 @@
|
|||
/*
|
||||
Copyright © 2024 Raul
|
||||
Copyright © 2024 Raul <raul@bulgariu.xyz>
|
||||
*/
|
||||
|
||||
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.
|
||||
Short: "Client interface for mini-chat",
|
||||
Long: `Refactored mini-chat client that properly interfaces
|
||||
with its server.
|
||||
|
||||
Example:
|
||||
./mini-chat client --ip 192.168.0.50 --port 1337`,
|
||||
./mini-chat client --ip 192.168.0.100 --port 1337`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client(cmd)
|
||||
},
|
||||
|
||||
if err := setClientParameters(cmd); err != nil {
|
||||
cmd.Help()
|
||||
fmt.Printf("\n-----------------------\n")
|
||||
fmt.Println(err)
|
||||
fmt.Printf("-----------------------\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var err error
|
||||
var conn net.Conn
|
||||
Client()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(clientCmd)
|
||||
|
@ -37,58 +41,32 @@ func init() {
|
|||
// 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")
|
||||
clientCmd.PersistentFlags().String("ip", "", "Server IP to connect to")
|
||||
clientCmd.PersistentFlags().String("port", "1302", "Server 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")
|
||||
func setClientParameters(cmd *cobra.Command) error {
|
||||
parameterPort, err := cmd.Flags().GetString("port")
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
return err
|
||||
}
|
||||
message := textarea.Buffer()
|
||||
msg := string(message)
|
||||
if msg == "" {
|
||||
return nil
|
||||
if parameterPort != "" {
|
||||
serverPort = parameterPort
|
||||
}
|
||||
|
||||
if msg == "" {
|
||||
return nil
|
||||
parameterIP, err := cmd.Flags().GetString("ip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if parameterIP == "" {
|
||||
err := fmt.Errorf("IP cannot be empty")
|
||||
return err
|
||||
}
|
||||
serverIP = parameterIP
|
||||
|
||||
fmt.Fprint(conn, msg)
|
||||
textarea.Clear()
|
||||
textarea.SetCursor(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
Copyright © 2024 Raul <raul@bulgariu.xyz>
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/jroimartin/gocui"
|
||||
"github.com/nsf/termbox-go"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Contents string
|
||||
//Date time.Time
|
||||
Server net.Conn
|
||||
}
|
||||
|
||||
func (m Message) toSend() {
|
||||
m.Server.Write([]byte(m.Contents))
|
||||
}
|
||||
|
||||
var (
|
||||
serverPort string = "1302"
|
||||
serverIP string
|
||||
data Message
|
||||
)
|
||||
|
||||
func Client() {
|
||||
conn, err := net.Dial("tcp", serverIP+":"+serverPort)
|
||||
if err != nil {
|
||||
log.Fatalf("Error occurred trying to connect to server: %v\n", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
data.Server = conn
|
||||
|
||||
nameRequest, err := receiveMessage(conn)
|
||||
if err != nil {
|
||||
log.Fatalf("Error occurred reading from server while requesting name: %v\n", err)
|
||||
}
|
||||
fmt.Print(nameRequest)
|
||||
sendName(conn)
|
||||
GUI()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// REFACTORING BELOW //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
func listenMessages(g *gocui.Gui) {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
chatbox, err := g.View("chatbox")
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
for {
|
||||
messageFromServer, err := receiveMessage(data.Server)
|
||||
if err != nil {
|
||||
// Avoid triggering an error if client quits the client
|
||||
if err == gocui.ErrQuit {
|
||||
g.Close()
|
||||
} else {
|
||||
g.Close()
|
||||
log.Fatalf("Error occurred reading from server: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
formattedMessage := strings.TrimRight(messageFromServer, "\n")
|
||||
fmt.Fprintln(chatbox, formattedMessage)
|
||||
termbox.Interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
func receiveMessage(conn net.Conn) (s string, err error) {
|
||||
serverMessage := make([]byte, 2048)
|
||||
if _, err := conn.Read(serverMessage); err != nil {
|
||||
return "", err
|
||||
}
|
||||
finalMessage := string(serverMessage)
|
||||
return finalMessage, nil
|
||||
}
|
||||
|
||||
func sendName(conn net.Conn) {
|
||||
message, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error occurred sending message to server: %v\n", err)
|
||||
}
|
||||
|
||||
if _, err := conn.Write([]byte(message)); err != nil {
|
||||
log.Fatalf("Error occurred writing to server: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func GUI() {
|
||||
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 listenMessages(g)
|
||||
|
||||
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func quit(*gocui.Gui, *gocui.View) error {
|
||||
return gocui.ErrQuit
|
||||
}
|
||||
|
||||
func sendToServer(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
|
||||
}
|
||||
|
||||
data.Contents = msg
|
||||
data.toSend()
|
||||
|
||||
textarea.Clear()
|
||||
textarea.SetCursor(0, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
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, sendToServer); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("textarea", gocui.KeyEnter, gocui.ModNone, sendToServer); 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-5); err != nil {
|
||||
if err != gocui.ErrUnknownView {
|
||||
return err
|
||||
}
|
||||
chatbox.Autoscroll = true
|
||||
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.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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
15
cmd/root.go
15
cmd/root.go
|
@ -1,25 +1,20 @@
|
|||
/*
|
||||
Copyright © 2024 Raul
|
||||
Copyright © 2024 Raul <raul@bulgariu.xyz>
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "mini-chat",
|
||||
Short: "Minimalistic chat server built using Go",
|
||||
Long: `mini-chat was originally designed to be used as a standalone server
|
||||
users could connect to using netcat, but it can be also used with the binary
|
||||
client
|
||||
Short: "Application for hosting and joining a simple chat server",
|
||||
|
||||
Examples:
|
||||
./mini-chat server --port 8080`,
|
||||
Long: `Application for hosting and joining a simple chat server`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
|
@ -39,7 +34,7 @@ func init() {
|
|||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.mini-chat.yaml)")
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.chat-tests.yaml)")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
|
|
121
cmd/server.go
121
cmd/server.go
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
Copyright © 2024 Raul
|
||||
Copyright © 2024 Raul <raul@bulgariu.xyz>
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
"log"
|
||||
)
|
||||
|
||||
// serverCmd represents the server command
|
||||
var serverCmd = &cobra.Command{
|
||||
Use: "server",
|
||||
Short: "Main chat server",
|
||||
Long: `You can connect to this server by running the following command from
|
||||
a client:
|
||||
nc $SERVER_IP $PORT
|
||||
Short: "Tiny chat server",
|
||||
Long: `Refactored mini-chat server designed to be connected to
|
||||
using a proper interface this time, not using netcat.
|
||||
|
||||
Assuming your IP is 192.168.0.30 and the server port is left on default the
|
||||
command would be as follows:
|
||||
nc 192.168.0.30 1302`,
|
||||
Example:
|
||||
./mini-chat server --port 1337`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
server(cmd)
|
||||
|
||||
if err := setServerParameters(cmd); err != nil {
|
||||
log.Fatalf("Error happened trying to set parameters: %v\n", err)
|
||||
}
|
||||
|
||||
Server()
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -37,100 +36,20 @@ func init() {
|
|||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// serverCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
serverCmd.PersistentFlags().String("port", "1302", "port to use for listening")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// serverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
serverCmd.Flags().String("port", "1302", "Port to listen on")
|
||||
}
|
||||
|
||||
var receiverIsStarted bool = false
|
||||
|
||||
type chatter struct {
|
||||
Username string
|
||||
IP string
|
||||
}
|
||||
|
||||
func server(cmd *cobra.Command) {
|
||||
var lport string
|
||||
port, _ := cmd.Flags().GetString("port")
|
||||
if port != "" {
|
||||
lport = port
|
||||
} else {
|
||||
lport = "1302"
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", ":"+lport)
|
||||
cobra.CheckErr(err)
|
||||
fmt.Printf("Listening on port %v...\n", lport)
|
||||
masterChannel := make(chan string, 20)
|
||||
|
||||
slaveChannel := make(chan string, 20)
|
||||
go masterReceiver(slaveChannel, masterChannel)
|
||||
// TODO: get channels properly working
|
||||
// receivingChannel := make(chan string)
|
||||
// sendingChannel := make(chan string)
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
cobra.CheckErr(err)
|
||||
numOfClients++
|
||||
go handleConn(conn, slaveChannel, masterChannel)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var numOfClients int = 0
|
||||
|
||||
func masterReceiver(slaveChannel chan<- string, masterChannel <-chan string) {
|
||||
for {
|
||||
message := <-masterChannel
|
||||
for i := 0; i < numOfClients; i++ {
|
||||
slaveChannel <- message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleConn(conn net.Conn, slaveChannel <-chan string, masterChannel chan<- string) {
|
||||
defer conn.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
message := <-slaveChannel
|
||||
conn.Write([]byte(message))
|
||||
}
|
||||
}()
|
||||
|
||||
IP := getIP(conn)
|
||||
t := time.Now()
|
||||
date := fmt.Sprintf("%d-%02d-%02d | %02d:%02d:%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
|
||||
final_message_connect := fmt.Sprintf("[%v] Received connection from %v!\n", date, IP)
|
||||
fmt.Print(final_message_connect)
|
||||
conn.Write([]byte("What's your name?\nName: "))
|
||||
name, err := bufio.NewReader(conn).ReadString('\n')
|
||||
func setServerParameters(cmd *cobra.Command) error {
|
||||
parameterPort, err := cmd.Flags().GetString("port")
|
||||
if err != nil {
|
||||
numOfClients--
|
||||
return
|
||||
return err
|
||||
}
|
||||
var NewUser = new(chatter)
|
||||
NewUser.Username = strings.TrimRight(name, "\n")
|
||||
NewUser.IP = IP
|
||||
for {
|
||||
message, err := bufio.NewReader(conn).ReadString('\n')
|
||||
if err != nil {
|
||||
fmt.Printf(NewUser.Username + " disconnected!\n")
|
||||
numOfClients--
|
||||
return
|
||||
if parameterPort != "" {
|
||||
listenPort = parameterPort
|
||||
}
|
||||
finalMessage := fmt.Sprint("{" + NewUser.IP + "} " + NewUser.Username + ": " + message)
|
||||
fmt.Print(finalMessage)
|
||||
masterChannel <- finalMessage
|
||||
//conn.Write([]byte(message))
|
||||
}
|
||||
}
|
||||
|
||||
func getIP(conn net.Conn) (IP string) {
|
||||
if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
|
||||
IP = fmt.Sprintf("%v", addr)
|
||||
}
|
||||
return IP
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Copyright © 2024 Raul <raul@bulgariu.xyz>
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
listenPort string = "1302"
|
||||
)
|
||||
|
||||
type Creator interface {
|
||||
CreateUser()
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
IP string
|
||||
}
|
||||
|
||||
func (u User) CreateUser(usr string, ip string) User {
|
||||
u.Username = usr
|
||||
u.IP = ip
|
||||
return u
|
||||
}
|
||||
|
||||
func Server() {
|
||||
ln, err := net.Listen("tcp", ":"+listenPort)
|
||||
if err != nil {
|
||||
log.Fatalf("Error happened trying to listen on port: %v\n", err)
|
||||
}
|
||||
defer ln.Close()
|
||||
fmt.Printf("Listening on port %v...\n", listenPort)
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatalf("Error happened trying to accept connection: %v\n", err)
|
||||
}
|
||||
chatChan := make(chan string, 10)
|
||||
listenerList = append(listenerList, chatChan)
|
||||
go handleConn(conn, chatChan)
|
||||
}
|
||||
}
|
||||
|
||||
var listenerList []chan string
|
||||
|
||||
func getUsername(conn net.Conn) (s string, err error) {
|
||||
conn.Write([]byte("What's your name?\nChoice: "))
|
||||
name, err := bufio.NewReader(conn).ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
trimmedName := strings.TrimRight(name, "\n")
|
||||
return trimmedName, nil
|
||||
}
|
||||
|
||||
func getUserInput(conn net.Conn) (s string, err error) {
|
||||
message, err := bufio.NewReader(conn).ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return message, nil
|
||||
}
|
||||
|
||||
func removeFromList(chatChan chan string) {
|
||||
for i, v := range listenerList {
|
||||
if v == chatChan {
|
||||
listenerList = append(listenerList[:i], listenerList[:i+1]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleConn(conn net.Conn, chatChan chan string) {
|
||||
defer conn.Close()
|
||||
|
||||
go receiveMessageServer(conn, chatChan)
|
||||
|
||||
//////////////////////////////////
|
||||
// Get user information
|
||||
//////////////////////////////////
|
||||
userName, err := getUsername(conn)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred getting username: %v\n", err)
|
||||
//removeFromList(chatChan)
|
||||
return
|
||||
}
|
||||
userIP := getIP(conn)
|
||||
//////////////////////////////////
|
||||
|
||||
newUserTemplate := new(User)
|
||||
newUser := newUserTemplate.CreateUser(userName, userIP)
|
||||
joinMessage := fmt.Sprintf("%v has joined the chat!", newUser.Username)
|
||||
fmt.Println(joinMessage)
|
||||
//conn.Write([]byte(joinMessage))
|
||||
sendMessage(joinMessage)
|
||||
|
||||
//////////////////////////////////
|
||||
for {
|
||||
message, err := getUserInput(conn)
|
||||
if err != nil {
|
||||
quitMessage := fmt.Sprintf("%v has disconnected!", newUser.Username)
|
||||
fmt.Println(quitMessage)
|
||||
sendMessage(quitMessage)
|
||||
//removeFromList(chatChan)
|
||||
// if _, err := conn.Write([]byte(quitMessage)); err != nil {
|
||||
// log.Printf("Error happened sending disconnect message: %v", err)
|
||||
// }
|
||||
return
|
||||
}
|
||||
finalMessage := fmt.Sprintf("[%v] %v: %v", newUser.IP, newUser.Username, strings.TrimRight(message, "\n"))
|
||||
fmt.Printf("%v\n", finalMessage)
|
||||
sendMessage(finalMessage)
|
||||
|
||||
//chatChan <- finalMessage
|
||||
// if _, err := conn.Write([]byte(finalMessage)); err != nil {
|
||||
// log.Printf("Error happened sending message: %v", err)
|
||||
// }
|
||||
}
|
||||
//////////////////////////////////
|
||||
}
|
||||
|
||||
func sendMessage(msg string) {
|
||||
for _, ch := range listenerList {
|
||||
ch <- msg
|
||||
}
|
||||
}
|
||||
|
||||
func receiveMessageServer(conn net.Conn, chatChan chan string) {
|
||||
for {
|
||||
select {
|
||||
case message := <-chatChan:
|
||||
conn.Write([]byte(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getIP(conn net.Conn) (IP string) {
|
||||
if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok {
|
||||
IP = fmt.Sprintf("%v", addr.IP)
|
||||
}
|
||||
return IP
|
||||
}
|
108
cmd/ui.go
108
cmd/ui.go
|
@ -1,108 +0,0 @@
|
|||
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
|
||||
}
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module mini-chat
|
||||
|
||||
go 1.22.1
|
||||
go 1.22.2
|
||||
|
||||
require (
|
||||
github.com/jroimartin/gocui v0.5.0
|
||||
|
|
Loading…
Reference in New Issue