Quality of Life update #4

Merged
raul merged 10 commits from testing into main 2024-05-08 08:04:46 +02:00
6 changed files with 118 additions and 28 deletions

View File

@ -1,8 +1,6 @@
name: Go audit
run-name: ${{ gitea.actor }} pushed to main! 🚀
run-name: ${{ gitea.actor }} pulled to main! 🚀
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:

View File

@ -2,10 +2,13 @@
Tiny IRC-like chat server written in Go
## Usage examples
<p align="center">
<img width="90%" height="90%" src="https://git.bulgariu.xyz/raul/mini-chat/raw/branch/testing/demo.gif"/>
</p>
## Usage examples
### Starting the server:
./mini-chat server --port 1337
./mini-chat server --port 1337 --history chat.log
### Connecting to the server:
./mini-chat client --ip 192.168.0.100 --port 1337

View File

@ -22,6 +22,12 @@ type Message struct {
Server net.Conn
}
type ProfileData struct {
Username string
}
var Profile ProfileData
func (m Message) toSend() {
m.Server.Write([]byte(m.Contents))
}
@ -93,6 +99,8 @@ func sendName(conn net.Conn) {
log.Fatalf("Error occurred sending message to server: %v\n", err)
}
Profile.Username = strings.TrimRight(message, "\n")
if _, err := conn.Write([]byte(message)); err != nil {
log.Fatalf("Error occurred writing to server: %v\n", err)
}
@ -143,50 +151,91 @@ func sendToServer(g *gocui.Gui, v *gocui.View) error {
return nil
}
func scrollView(v *gocui.View, dy int) error {
if v != nil {
v.Autoscroll = false
ox, oy := v.Origin()
if err := v.SetOrigin(ox, oy+dy); err != nil {
return err
}
}
return nil
}
func autoscroll(g *gocui.Gui, v *gocui.View) error {
chatbox, err := g.View("chatbox")
if err != nil {
log.Panicf("Error happened setting autoscroll: %v\n", err)
}
chatbox.Autoscroll = true
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 {
// if err := g.SetKeybinding("button", gocui.MouseLeft, gocui.ModNone, sendToServer); err != nil {
// log.Panicln(err)
// }
if err := g.SetKeybinding("textarea", gocui.KeyCtrlA, gocui.ModNone, autoscroll); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("textarea", gocui.KeyEnter, gocui.ModNone, sendToServer); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("chatbox", gocui.MouseWheelUp, gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
scrollView(v, -1)
return nil
}); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("chatbox", gocui.MouseWheelDown, gocui.ModNone,
func(g *gocui.Gui, v *gocui.View) error {
scrollView(v, 1)
return nil
}); 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 chatbox, err := g.SetView("chatbox", 2, 1, maxX-2, maxY-5); err != nil {
if err != gocui.ErrUnknownView {
return err
}
chatbox.Autoscroll = true
chatbox.Title = "Chat Box"
chatbox.Title = "Chat Box (Find source at https://git.bulgariu.xyz/raul/mini-chat!)"
}
if button, err := g.SetView("button", maxX/2+32, maxY-4, maxX/2+40, maxY-2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
// if button, err := g.SetView("button", maxX/2+32, maxY-4, maxX-28, maxY-2); err != nil {
// if err != gocui.ErrUnknownView {
// return err
// }
//
// button.Wrap = true
// button.Frame = true
// fmt.Fprintln(button, "Send it")
// }
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 textarea, err := g.SetView("textarea", 2, maxY-4, maxX-2, 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.Title = "(" + Profile.Username + ") " + "Send message" + " (Ctrl+A: Autoscroll)"
textarea.Wrap = true
textarea.Editable = true
}

View File

@ -37,6 +37,7 @@ func init() {
// and all subcommands, e.g.:
// serverCmd.PersistentFlags().String("foo", "", "A help for foo")
serverCmd.PersistentFlags().String("port", "1302", "port to use for listening")
serverCmd.PersistentFlags().String("history", "", "File to store and recover chat history from")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
@ -51,5 +52,13 @@ func setServerParameters(cmd *cobra.Command) error {
if parameterPort != "" {
listenPort = parameterPort
}
parameterHistory, err := cmd.Flags().GetString("history")
if err != nil {
return err
}
if parameterHistory != "" {
logLocation = parameterHistory
isLogging = true
}
return nil
}

View File

@ -9,17 +9,17 @@ import (
"fmt"
"log"
"net"
"os"
"strings"
)
var (
listenPort string = "1302"
isLogging bool = false
logLocation string
listenerList []chan string
)
type Creator interface {
CreateUser()
}
type User struct {
Username string
IP string
@ -49,8 +49,6 @@ func Server() {
}
}
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')
@ -78,6 +76,22 @@ func removeFromList(chatChan chan string) {
}
}
func populateChat(conn net.Conn) {
if isLogging == false {
return
}
file, err := os.Open(logLocation)
if err != nil {
log.Printf("Error opening file for populating: %v\n", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
conn.Write([]byte(fmt.Sprintln(scanner.Text())))
}
}
func handleConn(conn net.Conn, chatChan chan string) {
defer conn.Close()
@ -94,11 +108,13 @@ func handleConn(conn net.Conn, chatChan chan string) {
}
userIP := getIP(conn)
//////////////////////////////////
populateChat(conn)
newUserTemplate := new(User)
newUser := newUserTemplate.CreateUser(userName, userIP)
joinMessage := fmt.Sprintf("%v has joined the chat!", newUser.Username)
fmt.Println(joinMessage)
addToLog(fmt.Sprintln(joinMessage))
//conn.Write([]byte(joinMessage))
sendMessage(joinMessage)
@ -108,6 +124,7 @@ func handleConn(conn net.Conn, chatChan chan string) {
if err != nil {
quitMessage := fmt.Sprintf("%v has disconnected!", newUser.Username)
fmt.Println(quitMessage)
addToLog(fmt.Sprintln(quitMessage))
sendMessage(quitMessage)
//removeFromList(chatChan)
// if _, err := conn.Write([]byte(quitMessage)); err != nil {
@ -116,7 +133,9 @@ func handleConn(conn net.Conn, chatChan chan string) {
return
}
finalMessage := fmt.Sprintf("[%v] %v: %v", newUser.IP, newUser.Username, strings.TrimRight(message, "\n"))
fmt.Printf("%v\n", finalMessage)
fm := fmt.Sprintf("%v\n", finalMessage)
fmt.Print(fm)
addToLog(fm)
sendMessage(finalMessage)
//chatChan <- finalMessage
@ -148,3 +167,15 @@ func getIP(conn net.Conn) (IP string) {
}
return IP
}
func addToLog(s string) {
if isLogging == false {
return
}
file, err := os.OpenFile(logLocation, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0640)
if err != nil {
log.Printf("Error occurred: %v\n", err)
}
defer file.Close()
file.WriteString(s)
}

BIN
demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB