Update tcpserver API

This commit is contained in:
qowevisa 2024-10-11 09:24:32 +03:00
parent 78b04e2f0c
commit 64e6494ff8
3 changed files with 132 additions and 41 deletions

View File

@ -5,35 +5,17 @@ import (
"net" "net"
"time" "time"
"git.qowevisa.me/Qowevisa/tcpmachine/tcpcommand"
"git.qowevisa.me/Qowevisa/tcpmachine/tcpserver" "git.qowevisa.me/Qowevisa/tcpmachine/tcpserver"
) )
func main() { func main() {
bundle, err := tcpcommand.CreateCommandBundle([]tcpcommand.Command{ server := tcpserver.CreateServer("127.0.0.1:10000")
{ server.On("PING", func(args []string, client net.Conn) {
Command: "PING",
Action: func(s []string, client net.Conn) {
fmt.Printf("todo..\n")
client.Write([]byte("PONG\n")) client.Write([]byte("PONG\n"))
},
},
}) })
time.Sleep(time.Second)
err := server.StartServer()
if err != nil { if err != nil {
panic(err) fmt.Printf("Error: server.StartServer: %v\n", err)
} }
conf := tcpserver.GetDefaultConfig()
handler, errorChannel := tcpserver.CreateHandleClientFuncFromCommands(bundle, conf)
go func() {
for err := range errorChannel {
fmt.Printf("Error:1: %v\n", err)
}
}()
conf.HandleClientFunc = handler
server := tcpserver.CreateServer(conf)
go func() {
time.Sleep(time.Minute)
server.Exit <- true
}()
server.StartServer("127.0.0.1:10000")
} }

33
tcpserver/options.go Normal file
View File

@ -0,0 +1,33 @@
package tcpserver
import "net"
type ServerOption func(*ServerConfiguration)
// WithMessageEndRune sets the MessageEndRune in the server configuration.
func WithMessageEndRune(r rune) ServerOption {
return func(conf *ServerConfiguration) {
conf.MessageEndRune = r
}
}
// WithMessageSplitRune sets the MessageSplitRune in the server configuration.
func WithMessageSplitRune(r rune) ServerOption {
return func(conf *ServerConfiguration) {
conf.MessageSplitRune = r
}
}
// WithErrorResolver sets a custom error resolver function.
func WithErrorResolver(resolver func(chan error)) ServerOption {
return func(conf *ServerConfiguration) {
conf.ErrorResolver = resolver
}
}
// WithHandleClientFunc sets the HandleClientFunc in the server configuration.
func WithHandleClientFunc(handler func(client net.Conn)) ServerOption {
return func(conf *ServerConfiguration) {
conf.HandleClientFunc = handler
}
}

View File

@ -23,6 +23,7 @@ type ServerConfiguration struct {
func CreateHandleClientFuncFromCommands(bundle *tcpcommand.CommandBundle, conf ServerConfiguration) (func(client net.Conn), chan error) { func CreateHandleClientFuncFromCommands(bundle *tcpcommand.CommandBundle, conf ServerConfiguration) (func(client net.Conn), chan error) {
clientErrors := make(chan error, 16) clientErrors := make(chan error, 16)
return func(client net.Conn) { return func(client net.Conn) {
defer client.Close()
connReader := bufio.NewReader(client) connReader := bufio.NewReader(client)
for { for {
msg, err := connReader.ReadString(byte(conf.MessageEndRune)) msg, err := connReader.ReadString(byte(conf.MessageEndRune))
@ -45,17 +46,53 @@ func CreateHandleClientFuncFromCommands(bundle *tcpcommand.CommandBundle, conf S
} }
type Server struct { type Server struct {
addr string
HandleClientFunc func(client net.Conn) HandleClientFunc func(client net.Conn)
Exit chan bool Exit chan bool
// //
MessageEndRune rune
MessageSplitRune rune
ErrorsChannel chan error ErrorsChannel chan error
ErrorResolver func(chan error) ErrorResolver func(chan error)
//
Commands []tcpcommand.Command
}
func defaultHandleClientFunc(server *Server) func(net.Conn) {
return func(client net.Conn) {
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
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)
}
}
}
} }
// HandleClientFunc is NOT created by this function // HandleClientFunc is NOT created by this function
// see: CreateHandleClientFuncFromCommands(bundle) // see: CreateHandleClientFuncFromCommands(bundle)
func GetDefaultConfig() ServerConfiguration { func GetDefaultConfig() ServerConfiguration {
return ServerConfiguration{ return ServerConfiguration{
MessageEndRune: '\n',
MessageSplitRune: ' ',
ErrorResolver: func(c chan error) { ErrorResolver: func(c chan error) {
for err := range c { for err := range c {
log.Printf("DefConfig:Error: %v\n", err) log.Printf("DefConfig:Error: %v\n", err)
@ -64,33 +101,56 @@ func GetDefaultConfig() ServerConfiguration {
} }
} }
func CreateServer(conf ServerConfiguration) *Server { func CreateServer(addr string, options ...ServerOption) *Server {
return &Server{ conf := GetDefaultConfig()
HandleClientFunc: conf.HandleClientFunc,
for _, opt := range options {
opt(&conf)
}
var cmds []tcpcommand.Command
server := &Server{
addr: addr,
Exit: make(chan bool, 1), Exit: make(chan bool, 1),
HandleClientFunc: conf.HandleClientFunc,
// //
MessageEndRune: conf.MessageEndRune,
MessageSplitRune: conf.MessageSplitRune,
ErrorsChannel: make(chan error, 8), ErrorsChannel: make(chan error, 8),
ErrorResolver: conf.ErrorResolver, ErrorResolver: conf.ErrorResolver,
//
Commands: cmds,
} }
if conf.HandleClientFunc == nil {
server.HandleClientFunc = defaultHandleClientFunc(server)
}
return server
} }
func (s *Server) StartServer(address string) error { func (s *Server) StartServer() error {
if s.Exit == nil { if s.Exit == nil {
return fmt.Errorf("server's Exit channel is nil. Can't start server\n") return fmt.Errorf("server's Exit channel is nil. Can't start server")
} }
listener, err := net.Listen("tcp", address) 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)
if err != nil { if err != nil {
return fmt.Errorf("net.Listen: %w", err) return fmt.Errorf("net.Listen: %w", err)
} }
defer listener.Close() defer listener.Close()
if s.ErrorsChannel == nil {
return fmt.Errorf("server's ErrorsChannel is nil. Can't start server\n")
}
if s.ErrorResolver == nil { if s.ErrorResolver == nil {
return fmt.Errorf("server's ErrorResolver is nil. Can't start server\n") return fmt.Errorf("server's ErrorResolver is nil. Can't start server")
} }
go s.ErrorResolver(s.ErrorsChannel) go s.ErrorResolver(s.ErrorsChannel)
log.Printf("Server started listening on %s\n", address) log.Printf("Server started listening on %s\n", s.addr)
loop: loop:
for { for {
@ -108,3 +168,19 @@ loop:
} }
return nil return nil
} }
var commandDuplicateError = errors.New("Command already exists in server")
var commandNotHandledError = errors.New("Command was not handled")
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
}