TCP server works

This commit is contained in:
Miroslav Vasilev 2025-06-19 16:22:55 +03:00
parent 82082b128f
commit e6da93f48f
17 changed files with 226 additions and 108 deletions

2
.vscode/launch.json vendored
View file

@ -9,7 +9,7 @@
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/src/Server/main.go"
"program": "${workspaceFolder}/cmd/lastmudserver/main.go"
},
]
}

37
cmd/lastmudserver/main.go Normal file
View file

@ -0,0 +1,37 @@
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"code.haedhutner.dev/mvv/LastMUD/internal/server"
)
func main() {
fmt.Println(`\\\\---------------------////`)
fmt.Println(`|||| LastMUD Server ||||`)
fmt.Println(`////---------------------\\\\`)
lastMudServer, err := server.CreateServer(":8000")
if err != nil {
log.Fatal(err)
}
go lastMudServer.Listen()
reader := bufio.NewReader(os.Stdin)
for {
text, _ := reader.ReadString('\n')
text = strings.ReplaceAll(text, "\n", "")
if strings.Compare("exit", text) == 0 {
lastMudServer.Stop()
return
}
}
}

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module code.haedhutner.dev/mvv/LastMUD
go 1.24.4
require github.com/google/uuid v1.6.0

2
go.sum Normal file
View file

@ -0,0 +1,2 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

View file

@ -1,4 +1,4 @@
package commandlib
package command
type Command struct {
commandDefinition CommandDefinition

View file

@ -1,4 +1,4 @@
package commandlib
package command
import "fmt"

View file

@ -1,4 +1,4 @@
package commandlib
package command
import "strconv"

View file

@ -1,4 +1,4 @@
package commandlib
package command
import "log"

View file

@ -1,4 +1,4 @@
package commandlib
package command
import (
"fmt"

View file

@ -0,0 +1,75 @@
package server
import (
"bufio"
"fmt"
"net"
"time"
"github.com/google/uuid"
)
type Connection struct {
identity uuid.UUID
conn net.Conn
inputChannel chan string
closeChannel chan struct{}
}
func CreateConnection(conn net.Conn) *Connection {
return &Connection{
identity: uuid.New(),
conn: conn,
inputChannel: make(chan string),
closeChannel: make(chan struct{}),
}
}
func (c *Connection) listen() (err error) {
defer c.conn.Close()
c.conn.SetReadDeadline(time.Time{})
for {
if c.shouldClose() {
break
}
message, err := bufio.NewReader(c.conn).ReadString('\n')
if err != nil {
fmt.Println(err)
return err
}
c.inputChannel <- message
c.conn.Write([]byte(message))
}
return
}
func (c *Connection) shouldClose() bool {
select {
case <-c.closeChannel:
return true
default:
return false
}
}
func (c *Connection) Close() {
c.closeChannel <- struct{}{}
}
func (c *Connection) NextInput() (next string, err error) {
select {
case val := <-c.inputChannel:
return val, nil
default:
return "", newInputEmptyError()
}
}

15
internal/server/error.go Normal file
View file

@ -0,0 +1,15 @@
package server
type inputEmptyError struct {
msg string
}
func newInputEmptyError() *inputEmptyError {
return &inputEmptyError{
msg: "No input available at this moment",
}
}
func (err *inputEmptyError) Error() string {
return err.msg
}

86
internal/server/server.go Normal file
View file

@ -0,0 +1,86 @@
package server
import (
"fmt"
"net"
"time"
)
type Server struct {
listener *net.TCPListener
connections []*Connection
stopChannel chan struct{}
}
func CreateServer(port string) (srv *Server, err error) {
addr, err := net.ResolveTCPAddr("tcp", port)
if err != nil {
fmt.Println(err)
return nil, err
}
ln, err := net.ListenTCP("tcp", addr)
if err != nil {
fmt.Println(err)
return nil, err
}
fmt.Println("Listening on port", port)
srv = &Server{
listener: ln,
connections: []*Connection{},
stopChannel: make(chan struct{}),
}
return
}
func (srv *Server) Listen() {
// Wait for 200 millis for a new connection, and loop if none found in that time
srv.listener.SetDeadline(time.Now().Add(1 * time.Second))
for {
if srv.shouldStop() {
break
}
conn, err := srv.listener.Accept()
if err != nil {
continue
}
c := CreateConnection(conn)
srv.connections = append(srv.connections, c)
go c.listen()
}
for _, v := range srv.connections {
v.Close()
}
err := srv.listener.Close()
if err != nil {
fmt.Println(err)
}
}
func (srv *Server) shouldStop() bool {
select {
case <-srv.stopChannel:
return true
default:
return false
}
}
func (srv *Server) Stop() {
srv.stopChannel <- struct{}{}
}

View file

@ -1,3 +0,0 @@
module code.haedhutner.dev/mvv/LastMUD/CommandLib
go 1.24.4

View file

@ -1,6 +0,0 @@
module code.haedhutner.dev/mvv/LastMUD/CoreLib
require code.haedhutner.dev/mvv/LastMUD/CommandLib v0.0.0
replace code.haedhutner.dev/mvv/LastMUD/CommandLib => ../CommandLib
go 1.24.4

View file

@ -1,13 +0,0 @@
module code.haedhutner.dev/mvv/LastMUD/Server
require (
code.haedhutner.dev/mvv/LastMUD/CommandLib v0.0.0
code.haedhutner.dev/mvv/LastMUD/CoreLib v0.0.0
)
replace (
code.haedhutner.dev/mvv/LastMUD/CommandLib => ../CommandLib
code.haedhutner.dev/mvv/LastMUD/CoreLib => ../CoreLib
)
go 1.24.4

View file

@ -1,80 +0,0 @@
package main
import (
"bufio"
"fmt"
"log"
"net"
)
type Command interface {
Name() string
}
func main() {
ln, err := net.Listen("tcp", ":8000")
if err != nil {
log.Fatal(err)
}
fmt.Println("Listening on port 8000")
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
// cmdRegistry := commandlib.CreateCommandRegistry(
// commandlib.CreateCommandDefinition(
// "exit",
// func(tokens []commandlib.Token) bool {
// return tokens[0].Lexeme() == "exit"
// },
// func(tokens []commandlib.Token) []commandlib.Parameter {
// return nil
// },
// func(parameters ...commandlib.Parameter) (err error) {
// err = conn.Close()
// return
// },
// ),
// )
for {
message, _ := bufio.NewReader(conn).ReadString('\n')
response := ""
// if err != nil {
// if err == io.EOF {
// fmt.Println("Client disconnected")
// break
// }
// log.Println("Read error:", err)
// continue
// }
conn.Write([]byte(message + "\n"))
// cmdContext, err := commandlib.CreateCommandContext(cmdRegistry, message)
// if err != nil {
// log.Println(err)
// response = err.Error()
// } else {
// // err = cmdContext.ExecuteCommand()
// // if err != nil {
// // log.Println(err)
// // response = err.Error()
// // }
// }
conn.Write([]byte(response + "\n> "))
}
}