diff --git a/agwpe.go b/agwpe.go index 61e2372..0ac13ad 100644 --- a/agwpe.go +++ b/agwpe.go @@ -1,33 +1,98 @@ -package main +package agwpe -import "encoding/binary" +import ( + "fmt" + "net" + "sync" + "time" +) -type Frame struct { - Port byte - Reserved0 [3]byte - DataKind byte - Reserved1 byte - PID byte - Reserved2 byte - CallFrom [10]byte - CallTo [10]byte - DataLen uint32 - User [4]byte +type Config struct { + Timeout time.Duration } -func (f *Frame) Serialize() []byte { - buf := make([]byte, 36) +type Option func(*Config) - buf[0] = f.Port - // Ignore reserved bytes 1 to 3 - buf[4] = f.DataKind - // Ignore reserved byte 5 - buf[6] = f.PID - // Ignore reserved byte 7 - copy(buf[8:18], f.CallFrom[:]) - copy(buf[18:28], f.CallTo[:]) - binary.LittleEndian.PutUint32(buf[28:32], f.DataLen) - copy(buf[32:36], f.User[:]) - - return buf +type PacketEngine struct { + address string + cfg Config + Ready bool + conn net.Conn + mu sync.Mutex } + +func WithTimeout(d time.Duration) Option { + return func(c *Config) { + c.Timeout = d + } +} + +func NewPacketEngine(address string, opts ...Option) (*PacketEngine, error) { + defaultCfg := Config{ + Timeout: 5 * time.Second, + } + + for _, opt := range opts { + opt(&defaultCfg) + } + + return &PacketEngine{ + address: address, + cfg: defaultCfg, + Ready: false, + }, nil +} + +func (pe *PacketEngine) Connect() error { + conn, err := net.DialTimeout("tcp", pe.address, pe.cfg.Timeout) + if err != nil { + return err + } + pe.conn = conn + fmt.Println("Connected to", pe.address) + + return nil +} + +func (pe *PacketEngine) Disconnect() error { + if pe.conn == nil { + return fmt.Errorf("Not connected!") + } + pe.conn.Close() + pe.conn = nil + fmt.Println("Disonnected from", pe.address) + + return nil +} + +// import "encoding/binary" + +// type Frame struct { +// Port byte +// Reserved0 [3]byte +// DataKind byte +// Reserved1 byte +// PID byte +// Reserved2 byte +// CallFrom [10]byte +// CallTo [10]byte +// DataLen uint32 +// User [4]byte +// } + +// func (f *Frame) Serialize() []byte { +// buf := make([]byte, 36) + +// buf[0] = f.Port +// // Ignore reserved bytes 1 to 3 +// buf[4] = f.DataKind +// // Ignore reserved byte 5 +// buf[6] = f.PID +// // Ignore reserved byte 7 +// copy(buf[8:18], f.CallFrom[:]) +// copy(buf[18:28], f.CallTo[:]) +// binary.LittleEndian.PutUint32(buf[28:32], f.DataLen) +// copy(buf[32:36], f.User[:]) + +// return buf +// } diff --git a/agwpe_test.go b/agwpe_test.go index f52728f..2620df1 100644 --- a/agwpe_test.go +++ b/agwpe_test.go @@ -1 +1,105 @@ -agwpe_test.go +package agwpe + +import ( + "testing" + "time" +) + +func TestNewPacketEngine(t *testing.T) { + tests := []struct { + name string + address string + options []Option + expectedError bool + expectedTimeout time.Duration + }{ + { + name: "Default configuration", + address: "localhost:1234", + options: []Option{}, + expectedError: false, + expectedTimeout: 5 * time.Second, + }, + { + name: "Custom timeout", + address: "localhost:1234", + options: []Option{WithTimeout(30 * time.Second)}, + expectedError: false, + expectedTimeout: 30 * time.Second, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine, err := NewPacketEngine(tt.address, tt.options...) + + if (err != nil) != tt.expectedError { + t.Errorf("Expected error: %v, got: %v", tt.expectedError, err) + } + + if !tt.expectedError { + if engine == nil { + t.Fatal("Expected non-nil engine") + } + if engine.Ready { + t.Fatal("Expected engine that is not ready") + } + if engine.cfg.Timeout != tt.expectedTimeout { + t.Errorf("Expected timeout %v, got %v", tt.expectedTimeout, engine.cfg.Timeout) + } + } + + }) + } +} + +func TestConnect(t *testing.T) { + tests := []struct { + name string + address string + options []Option + expectedError bool + }{ + { + name: "Successful connection", + address: "localhost:1234", + expectedError: false, + }, + { + name: "Invalid address", + address: "invalid-address", + expectedError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine, _ := NewPacketEngine(tt.address, tt.options...) + err := engine.Connect() + + if tt.expectedError && (err == nil) { + t.Errorf("Expected error: %v, got: %v", tt.expectedError, err) + } + + if !tt.expectedError && (err != nil) { + t.Errorf("Did not expect error: %v", err) + } + }) + } +} + +func TestDisconnect(t *testing.T) { + engine, _ := NewPacketEngine("localhost:1234") + engine.Connect() + + err := engine.Disconnect() + if err != nil { + t.Errorf("Did not expect error: %v", err) + } + + // Call to Disconnect() on disconnected packet engine should return an error + err = engine.Disconnect() + if err == nil { + t.Error("Expected an error, but got", nil) + } +} diff --git a/go.mod b/go.mod index 41052f3..312a711 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module go-agwpe/agwpe +module git.smith.eu/m/go-agwpe go 1.24.5 diff --git a/main.go b/main.go deleted file mode 100644 index b7405b4..0000000 --- a/main.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "bytes" - "encoding/binary" - "fmt" - "net" - "time" -) - -func main() { - address := "172.16.0.4:8000" - timeout := 5 * time.Second - send_buf := new(bytes.Buffer) - recv_buf := make([]byte, 1024) - - conn, err := net.DialTimeout("tcp", address, timeout) - if err != nil { - fmt.Printf("Failed to connect: %v\n", err) - return - } - defer conn.Close() - - fmt.Printf("Connected to %s\n", address) - - rFrame := Frame{ - Port: 0x01, - DataKind: 0x52, - } - - err = binary.Write(send_buf, binary.LittleEndian, rFrame) - if err != nil { - fmt.Println("Binary write error:", err) - } - - byteSlice := send_buf.Bytes() - - _, err = conn.Write(byteSlice) - if err != nil { - fmt.Println("Error sending frame to server:", err) - return - } - - n, err := conn.Read(recv_buf) - if err != nil { - fmt.Println("Error reading:", err) - return - } - fmt.Printf("Received %d bytes:\n", n) - - reader := bytes.NewReader(recv_buf) - var f Frame - err = binary.Read(reader, binary.LittleEndian, &f) - if err != nil { - fmt.Println("Error decoding:", err) - return - } - fmt.Println("Response frame:") - fmt.Printf("Port: %d\n", f.Port) - fmt.Printf("DataKind: %c\n", f.DataKind) - fmt.Printf("PID: 0x%02X\n", f.PID) - fmt.Printf("CallFrom: %s\n", f.CallFrom) - fmt.Printf("CallTo: %s\n", f.CallTo) - fmt.Printf("DataLen: %d\n", f.DataLen) - major_verion := (uint16(recv_buf[37]) << 8) | uint16(recv_buf[36]) - minor_verion := (uint16(recv_buf[41]) << 8) | uint16(recv_buf[40]) - fmt.Printf("AGWPE version: %d.%d\n", major_verion, minor_verion) -}