From 6e244be880fe28105b2e55cc52703eef7cd83381 Mon Sep 17 00:00:00 2001 From: qowevisa Date: Tue, 22 Oct 2024 21:02:14 +0300 Subject: [PATCH] Add MessageEndRune and MessageSplitRune with default and customizable ServerHandlerFunc --- tcpclient/client.go | 119 +++++++++++++++++++++++++++++++++---------- tcpclient/options.go | 8 +++ 2 files changed, 100 insertions(+), 27 deletions(-) diff --git a/tcpclient/client.go b/tcpclient/client.go index 82fc1f9..7c8972a 100644 --- a/tcpclient/client.go +++ b/tcpclient/client.go @@ -6,15 +6,26 @@ import ( "fmt" "io" "net" + "strings" + + "git.qowevisa.me/Qowevisa/tcpmachine/tcpcommand" ) type ClientConfiguration struct { + MessageEndRune rune + MessageSplitRune rune + // Status uint32 ErrorResolver func(chan error) + // + ServerHandlerFunc func(server net.Conn) + // } func GetDefaultConfig() *ClientConfiguration { return &ClientConfiguration{ + MessageEndRune: '\n', + MessageSplitRune: ' ', ErrorResolver: func(c chan error) { for err := range c { fmt.Printf("DefConfig:Error: %v\n", err) @@ -26,15 +37,21 @@ func GetDefaultConfig() *ClientConfiguration { type ErrorResolverFunc func(errors chan error) type Client struct { + MessageEndRune rune + MessageSplitRune rune + // addr string Status uint32 exit chan bool Server net.Conn IsConnected bool // - Messages chan []byte + ServerHandlerFunc func(server net.Conn) + // ErrorsChannel chan error ErrorResolver ErrorResolverFunc + // + Commands []tcpcommand.Command } func CreateClient(addr string, options ...ClientOption) *Client { @@ -43,21 +60,68 @@ func CreateClient(addr string, options ...ClientOption) *Client { for _, opt := range options { opt(conf) } - - return &Client{ - addr: addr, - Messages: make(chan []byte, 16), - ErrorResolver: conf.ErrorResolver, - ErrorsChannel: make(chan error, 8), - exit: make(chan bool, 1), + c := &Client{ + MessageEndRune: conf.MessageEndRune, + MessageSplitRune: conf.MessageSplitRune, + addr: addr, + ErrorResolver: conf.ErrorResolver, + ErrorsChannel: make(chan error, 8), + exit: make(chan bool, 1), + ServerHandlerFunc: conf.ServerHandlerFunc, } + if c.ServerHandlerFunc == nil { + c.ServerHandlerFunc = GetDefaultServerHandlerFunc(c) + } + + return c } var ( ERROR_CLIENT_ERRRSL_NIL = errors.New("Error Resolver is nil") ERROR_CLIENT_ERRCHL_NIL = errors.New("Error Channel is nil") + ERROR_CLIENT_SRVHND_NIL = errors.New("Server Handler Func is nil") ) +func GetDefaultServerHandlerFunc(c *Client) func(server net.Conn) { + return func(server net.Conn) { + serverReader := bufio.NewReader(server) + for { + select { + case <-c.exit: + return + default: + rawMsg, err := serverReader.ReadString(byte(c.MessageEndRune)) + if err != nil { + if errors.Is(err, io.EOF) { + c.exit <- true + break + } + c.ErrorsChannel <- fmt.Errorf("serverReader.ReadString: %w", err) + } + fmt.Printf("Server send us a message: %s", rawMsg) + msg := strings.TrimRight(rawMsg, string(c.MessageEndRune)) + parts := strings.Split(msg, string(c.MessageSplitRune)) + // ??? + if len(parts) == 0 { + continue + } + cmd := parts[0] + found := false + for _, _cmd := range c.Commands { + if cmd == _cmd.Command { + found = true + _cmd.Action(parts[1:], server) + break + } + } + if !found { + fmt.Printf("Command %s was not handled\n", cmd) + } + } + } + } +} + func (c *Client) StartClient() error { if c.Status&statusBitCustomErrorHandling == 0 { if c.ErrorResolver == nil { @@ -68,30 +132,31 @@ func (c *Client) StartClient() error { } go c.ErrorResolver(c.ErrorsChannel) } + if c.ServerHandlerFunc == nil { + return fmt.Errorf("Can't start client: %w", ERROR_CLIENT_SRVHND_NIL) + } server, err := net.Dial("tcp", c.addr) if err != nil { return fmt.Errorf("net.Dial: %w", err) } - serverReader := bufio.NewReader(server) c.IsConnected = true c.Server = server -loop: - for { - select { - case <-c.exit: - break loop - default: - msg, err := serverReader.ReadString('\n') - if err != nil { - if errors.Is(err, io.EOF) { - c.exit <- true - break - } - c.ErrorsChannel <- fmt.Errorf("serverReader.ReadString: %w", err) - } - fmt.Printf("Server send us a message: %s", msg) - c.Messages <- []byte(msg) - } - } + c.ServerHandlerFunc(server) + return nil +} + +var commandDuplicateError = errors.New("Command already exists in server") +var commandNotHandledError = errors.New("Command was not handled") + +func (c *Client) On(command string, action func(args []string, server net.Conn)) error { + for _, cmd := range c.Commands { + if cmd.Command == command { + return fmt.Errorf("Failed addding command %s: %w ", command, commandDuplicateError) + } + } + c.Commands = append(c.Commands, tcpcommand.Command{ + Command: command, + Action: action, + }) return nil } diff --git a/tcpclient/options.go b/tcpclient/options.go index 88b607a..226000e 100644 --- a/tcpclient/options.go +++ b/tcpclient/options.go @@ -1,5 +1,7 @@ package tcpclient +import "net" + type ClientOption func(conf *ClientConfiguration) const ( @@ -13,3 +15,9 @@ func WithCustomErrorHandling(fun ErrorResolverFunc) ClientOption { conf.ErrorResolver = fun } } + +func WithServerHandler(fun func(server net.Conn)) ClientOption { + return func(conf *ClientConfiguration) { + conf.ServerHandlerFunc = fun + } +}