tcpmachine/tcpserver/server.go

195 lines
5.1 KiB
Go
Raw Normal View History

2024-10-10 07:17:51 +02:00
package tcpserver
import (
"bufio"
"errors"
"fmt"
"io"
"log"
"net"
"strings"
2024-11-27 12:32:31 +01:00
"git.qowevisa.me/qowevisa/tcpmachine/tcpcommand"
2024-10-10 07:17:51 +02:00
)
2024-10-19 21:55:35 +02:00
const (
LogLevel_Nothing = 0
LogLevel_Connection = 1 << iota
LogLevel_Messages
)
const (
LogLevel_ALL = LogLevel_Connection | LogLevel_Messages
)
2024-10-10 07:17:51 +02:00
func CreateHandleClientFuncFromCommands(bundle *tcpcommand.CommandBundle, conf ServerConfiguration) (func(client net.Conn), chan error) {
clientErrors := make(chan error, 16)
return func(client net.Conn) {
2024-10-11 08:24:32 +02:00
defer client.Close()
2024-10-10 07:17:51 +02:00
connReader := bufio.NewReader(client)
for {
msg, err := connReader.ReadString(byte(conf.MessageEndRune))
if err != nil {
if errors.Is(err, io.EOF) {
break
}
clientErrors <- err
}
msgWoNl := strings.Trim(msg, string(conf.MessageEndRune))
parts := strings.Split(msgWoNl, string(conf.MessageSplitRune))
for _, cmd := range bundle.Commands {
if cmd.Command == parts[0] {
cmd.Action(parts[1:], client)
break
}
}
}
}, clientErrors
}
2024-10-11 08:24:32 +02:00
func defaultHandleClientFunc(server *Server) func(net.Conn) {
return func(client net.Conn) {
if server.PostHandlerClientFunc != nil {
defer server.PostHandlerClientFunc(client)
}
2024-10-11 08:24:32 +02:00
defer client.Close()
connReader := bufio.NewReader(client)
for {
msg, err := connReader.ReadString(byte(server.MessageEndRune))
if err != nil {
if errors.Is(err, io.EOF) {
break
}
server.ErrorsChannel <- err
}
msgWoNl := strings.Trim(msg, string(server.MessageEndRune))
parts := strings.Split(msgWoNl, string(server.MessageSplitRune))
commandFound := false
2024-10-19 21:55:35 +02:00
if server.LogLevel&LogLevel_Messages > 0 {
log.Printf("Message received from %s : %s\n", client.RemoteAddr(), msgWoNl)
}
2024-10-11 08:24:32 +02:00
for _, cmd := range server.Commands {
if cmd.Command == parts[0] {
cmd.Action(parts[1:], client)
commandFound = true
break
}
}
if !commandFound {
server.ErrorsChannel <- fmt.Errorf("WARN: Command %s error: %w", parts[0], commandNotHandledError)
}
}
}
2024-10-10 07:17:51 +02:00
}
2024-10-19 21:55:35 +02:00
// NOTE: HandleClientFunc is NOT created by this function
2024-10-10 07:17:51 +02:00
// see: CreateHandleClientFuncFromCommands(bundle)
func GetDefaultConfig() ServerConfiguration {
return ServerConfiguration{
2024-10-11 08:24:32 +02:00
MessageEndRune: '\n',
MessageSplitRune: ' ',
2024-10-10 07:17:51 +02:00
ErrorResolver: func(c chan error) {
for err := range c {
log.Printf("DefConfig:Error: %v\n", err)
}
},
}
}
2024-10-11 08:24:32 +02:00
func CreateServer(addr string, options ...ServerOption) *Server {
conf := GetDefaultConfig()
for _, opt := range options {
opt(&conf)
}
var cmds []tcpcommand.Command
server := &Server{
addr: addr,
2024-10-10 07:17:51 +02:00
Exit: make(chan bool, 1),
2024-10-11 08:24:32 +02:00
HandleClientFunc: conf.HandleClientFunc,
2024-10-10 07:17:51 +02:00
//
2024-10-11 08:24:32 +02:00
MessageEndRune: conf.MessageEndRune,
MessageSplitRune: conf.MessageSplitRune,
ErrorsChannel: make(chan error, 8),
ErrorResolver: conf.ErrorResolver,
2024-10-19 21:55:35 +02:00
LogLevel: conf.LogLevel,
2024-10-11 08:24:32 +02:00
//
Commands: cmds,
}
if conf.HandleClientFunc == nil {
server.HandleClientFunc = defaultHandleClientFunc(server)
2024-10-10 07:17:51 +02:00
}
2024-10-11 08:24:32 +02:00
return server
2024-10-10 07:17:51 +02:00
}
2024-10-11 08:24:32 +02:00
func (s *Server) StartServer() error {
2024-10-10 07:17:51 +02:00
if s.Exit == nil {
2024-10-11 08:24:32 +02:00
return fmt.Errorf("server's Exit channel is nil. Can't start server")
2024-10-10 07:17:51 +02:00
}
2024-10-11 08:24:32 +02:00
if s.HandleClientFunc == nil {
return fmt.Errorf("server's HandleClientFunc is nil. Can't start server")
}
if s.ErrorsChannel == nil {
return fmt.Errorf("server's ErrorsChannel is nil. Can't start server")
}
if len(s.Commands) == 0 {
s.ErrorsChannel <- fmt.Errorf("WARN: len(s.Commands) == 0! Server is running without commands")
}
listener, err := net.Listen("tcp", s.addr)
2024-10-10 07:17:51 +02:00
if err != nil {
return fmt.Errorf("net.Listen: %w", err)
}
defer listener.Close()
if s.ErrorResolver == nil {
2024-10-11 08:24:32 +02:00
return fmt.Errorf("server's ErrorResolver is nil. Can't start server")
2024-10-10 07:17:51 +02:00
}
go s.ErrorResolver(s.ErrorsChannel)
2024-10-11 08:24:32 +02:00
log.Printf("Server started listening on %s\n", s.addr)
2024-10-10 07:17:51 +02:00
loop:
for {
select {
case <-s.Exit:
break loop
default:
2024-10-22 16:42:30 +02:00
newClient, err := listener.Accept()
2024-10-10 07:17:51 +02:00
if err != nil {
s.ErrorsChannel <- fmt.Errorf("listener.Accept: %w", err)
break
}
2024-10-19 21:55:35 +02:00
if s.LogLevel&LogLevel_Connection > 0 {
2024-10-22 16:42:30 +02:00
fmt.Printf("New Connection from %s is accepted\n", newClient.RemoteAddr())
2024-10-19 21:55:35 +02:00
}
if s.PreHandlerClientFunc != nil {
s.PreHandlerClientFunc(newClient)
}
2024-10-22 16:42:30 +02:00
go s.HandleClientFunc(newClient)
2024-10-10 07:17:51 +02:00
}
}
return nil
}
2024-10-11 08:24:32 +02:00
var commandDuplicateError = errors.New("Command already exists in server")
var commandNotHandledError = errors.New("Command was not handled")
2024-10-19 21:55:35 +02:00
// On registers an action for a specific command. The action will be executed
// when the command is received from a client. For example, given the input
// string `TEST 1 2 3 4`, the command would be `TEST`, and the args would be
// []string{"1", "2", "3", "4"}.
//
// NOTE: This behavior applies only if `MessageSplitRune` is set to the default value (' ').
2024-10-11 08:24:32 +02:00
func (s *Server) On(command string, action func(args []string, client net.Conn)) error {
for _, cmd := range s.Commands {
if cmd.Command == command {
return fmt.Errorf("Failed addding command %s: %w ", command, commandDuplicateError)
}
}
s.Commands = append(s.Commands, tcpcommand.Command{
Command: command,
Action: action,
})
return nil
}