2024-10-10 07:17:51 +02:00
|
|
|
package tcpclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
2024-10-22 20:02:14 +02:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.qowevisa.me/Qowevisa/tcpmachine/tcpcommand"
|
2024-10-10 07:17:51 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type ClientConfiguration struct {
|
2024-10-22 20:02:14 +02:00
|
|
|
MessageEndRune rune
|
|
|
|
MessageSplitRune rune
|
|
|
|
//
|
2024-10-12 11:34:47 +02:00
|
|
|
Status uint32
|
2024-10-10 07:17:51 +02:00
|
|
|
ErrorResolver func(chan error)
|
2024-10-22 20:02:14 +02:00
|
|
|
//
|
|
|
|
ServerHandlerFunc func(server net.Conn)
|
|
|
|
//
|
2024-10-10 07:17:51 +02:00
|
|
|
}
|
|
|
|
|
2024-10-12 11:33:54 +02:00
|
|
|
func GetDefaultConfig() *ClientConfiguration {
|
|
|
|
return &ClientConfiguration{
|
2024-10-22 20:02:14 +02:00
|
|
|
MessageEndRune: '\n',
|
|
|
|
MessageSplitRune: ' ',
|
2024-10-10 07:17:51 +02:00
|
|
|
ErrorResolver: func(c chan error) {
|
|
|
|
for err := range c {
|
|
|
|
fmt.Printf("DefConfig:Error: %v\n", err)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-12 11:34:24 +02:00
|
|
|
type ErrorResolverFunc func(errors chan error)
|
|
|
|
|
2024-10-10 07:17:51 +02:00
|
|
|
type Client struct {
|
2024-10-22 20:02:14 +02:00
|
|
|
MessageEndRune rune
|
|
|
|
MessageSplitRune rune
|
|
|
|
//
|
2024-10-12 11:32:38 +02:00
|
|
|
addr string
|
2024-10-12 11:34:47 +02:00
|
|
|
Status uint32
|
2024-10-10 07:17:51 +02:00
|
|
|
exit chan bool
|
|
|
|
Server net.Conn
|
|
|
|
IsConnected bool
|
|
|
|
//
|
2024-10-22 20:02:14 +02:00
|
|
|
ServerHandlerFunc func(server net.Conn)
|
|
|
|
//
|
2024-10-10 07:17:51 +02:00
|
|
|
ErrorsChannel chan error
|
2024-10-12 11:34:24 +02:00
|
|
|
ErrorResolver ErrorResolverFunc
|
2024-10-22 20:02:14 +02:00
|
|
|
//
|
|
|
|
Commands []tcpcommand.Command
|
2024-10-10 07:17:51 +02:00
|
|
|
}
|
|
|
|
|
2024-10-12 11:32:38 +02:00
|
|
|
func CreateClient(addr string, options ...ClientOption) *Client {
|
|
|
|
conf := GetDefaultConfig()
|
|
|
|
|
|
|
|
for _, opt := range options {
|
|
|
|
opt(conf)
|
|
|
|
}
|
2024-10-22 20:02:14 +02:00
|
|
|
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)
|
2024-10-10 07:17:51 +02:00
|
|
|
}
|
2024-10-22 20:02:14 +02:00
|
|
|
|
|
|
|
return c
|
2024-10-10 07:17:51 +02:00
|
|
|
}
|
|
|
|
|
2024-10-12 11:35:14 +02:00
|
|
|
var (
|
|
|
|
ERROR_CLIENT_ERRRSL_NIL = errors.New("Error Resolver is nil")
|
|
|
|
ERROR_CLIENT_ERRCHL_NIL = errors.New("Error Channel is nil")
|
2024-10-22 20:02:14 +02:00
|
|
|
ERROR_CLIENT_SRVHND_NIL = errors.New("Server Handler Func is nil")
|
2024-10-12 11:35:14 +02:00
|
|
|
)
|
|
|
|
|
2024-10-22 20:02:14 +02:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-12 11:32:38 +02:00
|
|
|
func (c *Client) StartClient() error {
|
2024-10-12 11:35:14 +02:00
|
|
|
if c.Status&statusBitCustomErrorHandling == 0 {
|
|
|
|
if c.ErrorResolver == nil {
|
|
|
|
return fmt.Errorf("Can't start client: %w", ERROR_CLIENT_ERRRSL_NIL)
|
|
|
|
}
|
|
|
|
if c.ErrorResolver == nil {
|
|
|
|
return fmt.Errorf("Can't start client: %w", ERROR_CLIENT_ERRCHL_NIL)
|
|
|
|
}
|
|
|
|
go c.ErrorResolver(c.ErrorsChannel)
|
|
|
|
}
|
2024-10-22 20:02:14 +02:00
|
|
|
if c.ServerHandlerFunc == nil {
|
|
|
|
return fmt.Errorf("Can't start client: %w", ERROR_CLIENT_SRVHND_NIL)
|
|
|
|
}
|
2024-10-12 11:32:38 +02:00
|
|
|
server, err := net.Dial("tcp", c.addr)
|
2024-10-10 07:17:51 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("net.Dial: %w", err)
|
|
|
|
}
|
|
|
|
c.IsConnected = true
|
|
|
|
c.Server = server
|
2024-10-22 20:02:14 +02:00
|
|
|
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)
|
2024-10-10 07:17:51 +02:00
|
|
|
}
|
|
|
|
}
|
2024-10-22 20:02:14 +02:00
|
|
|
c.Commands = append(c.Commands, tcpcommand.Command{
|
|
|
|
Command: command,
|
|
|
|
Action: action,
|
|
|
|
})
|
2024-10-10 07:17:51 +02:00
|
|
|
return nil
|
|
|
|
}
|