Add MessageEndRune and MessageSplitRune with default and customizable ServerHandlerFunc

This commit is contained in:
qowevisa 2024-10-22 21:02:14 +03:00
parent 7338bc69fa
commit 6e244be880
2 changed files with 100 additions and 27 deletions

View File

@ -6,15 +6,26 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"strings"
"git.qowevisa.me/Qowevisa/tcpmachine/tcpcommand"
) )
type ClientConfiguration struct { type ClientConfiguration struct {
MessageEndRune rune
MessageSplitRune rune
//
Status uint32 Status uint32
ErrorResolver func(chan error) ErrorResolver func(chan error)
//
ServerHandlerFunc func(server net.Conn)
//
} }
func GetDefaultConfig() *ClientConfiguration { func GetDefaultConfig() *ClientConfiguration {
return &ClientConfiguration{ return &ClientConfiguration{
MessageEndRune: '\n',
MessageSplitRune: ' ',
ErrorResolver: func(c chan error) { ErrorResolver: func(c chan error) {
for err := range c { for err := range c {
fmt.Printf("DefConfig:Error: %v\n", err) fmt.Printf("DefConfig:Error: %v\n", err)
@ -26,15 +37,21 @@ func GetDefaultConfig() *ClientConfiguration {
type ErrorResolverFunc func(errors chan error) type ErrorResolverFunc func(errors chan error)
type Client struct { type Client struct {
MessageEndRune rune
MessageSplitRune rune
//
addr string addr string
Status uint32 Status uint32
exit chan bool exit chan bool
Server net.Conn Server net.Conn
IsConnected bool IsConnected bool
// //
Messages chan []byte ServerHandlerFunc func(server net.Conn)
//
ErrorsChannel chan error ErrorsChannel chan error
ErrorResolver ErrorResolverFunc ErrorResolver ErrorResolverFunc
//
Commands []tcpcommand.Command
} }
func CreateClient(addr string, options ...ClientOption) *Client { func CreateClient(addr string, options ...ClientOption) *Client {
@ -43,21 +60,68 @@ func CreateClient(addr string, options ...ClientOption) *Client {
for _, opt := range options { for _, opt := range options {
opt(conf) opt(conf)
} }
c := &Client{
return &Client{ MessageEndRune: conf.MessageEndRune,
MessageSplitRune: conf.MessageSplitRune,
addr: addr, addr: addr,
Messages: make(chan []byte, 16),
ErrorResolver: conf.ErrorResolver, ErrorResolver: conf.ErrorResolver,
ErrorsChannel: make(chan error, 8), ErrorsChannel: make(chan error, 8),
exit: make(chan bool, 1), exit: make(chan bool, 1),
ServerHandlerFunc: conf.ServerHandlerFunc,
} }
if c.ServerHandlerFunc == nil {
c.ServerHandlerFunc = GetDefaultServerHandlerFunc(c)
}
return c
} }
var ( var (
ERROR_CLIENT_ERRRSL_NIL = errors.New("Error Resolver is nil") ERROR_CLIENT_ERRRSL_NIL = errors.New("Error Resolver is nil")
ERROR_CLIENT_ERRCHL_NIL = errors.New("Error Channel 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 { func (c *Client) StartClient() error {
if c.Status&statusBitCustomErrorHandling == 0 { if c.Status&statusBitCustomErrorHandling == 0 {
if c.ErrorResolver == nil { if c.ErrorResolver == nil {
@ -68,30 +132,31 @@ func (c *Client) StartClient() error {
} }
go c.ErrorResolver(c.ErrorsChannel) 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) server, err := net.Dial("tcp", c.addr)
if err != nil { if err != nil {
return fmt.Errorf("net.Dial: %w", err) return fmt.Errorf("net.Dial: %w", err)
} }
serverReader := bufio.NewReader(server)
c.IsConnected = true c.IsConnected = true
c.Server = server c.Server = server
loop: c.ServerHandlerFunc(server)
for { return nil
select { }
case <-c.exit:
break loop var commandDuplicateError = errors.New("Command already exists in server")
default: var commandNotHandledError = errors.New("Command was not handled")
msg, err := serverReader.ReadString('\n')
if err != nil { func (c *Client) On(command string, action func(args []string, server net.Conn)) error {
if errors.Is(err, io.EOF) { for _, cmd := range c.Commands {
c.exit <- true if cmd.Command == command {
break return fmt.Errorf("Failed addding command %s: %w ", command, commandDuplicateError)
} }
c.ErrorsChannel <- fmt.Errorf("serverReader.ReadString: %w", err) }
} c.Commands = append(c.Commands, tcpcommand.Command{
fmt.Printf("Server send us a message: %s", msg) Command: command,
c.Messages <- []byte(msg) Action: action,
} })
}
return nil return nil
} }

View File

@ -1,5 +1,7 @@
package tcpclient package tcpclient
import "net"
type ClientOption func(conf *ClientConfiguration) type ClientOption func(conf *ClientConfiguration)
const ( const (
@ -13,3 +15,9 @@ func WithCustomErrorHandling(fun ErrorResolverFunc) ClientOption {
conf.ErrorResolver = fun conf.ErrorResolver = fun
} }
} }
func WithServerHandler(fun func(server net.Conn)) ClientOption {
return func(conf *ClientConfiguration) {
conf.ServerHandlerFunc = fun
}
}