Skip to content

Commit

Permalink
debugging all functionality, cleanup, comments, more tests to come
Browse files Browse the repository at this point in the history
  • Loading branch information
George Makroglou committed Jul 25, 2024
1 parent 5757f83 commit 68fa74b
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 135 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/main.go
320 changes: 253 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# CLIENT (clientevents.go)
# JSON client for connection with a server created with github.com/G-MAKROGLOU/websocket-server

## CLIENT (clientevents.go)

<p>
Implement the events interface with the functionality you want to be implemented per event.
Expand All @@ -12,121 +14,305 @@ package main
import (
"encoding/json"
"fmt"

"golang.org/x/net/websocket"
)

// CustomEvents implements the SocketClientEvents interface
type CustomEvents struct {}
// Events implements SocketClientEvents interface
type Events struct {}

func (c CustomEvents) onConnect(ws *websocket.Conn, sessID string) {
fmt.Println("[CLIENT] Connected with session ID: ", sessID)
// OnDisconnectError event interface implementation
func (e Events) OnDisconnectError(err error){
fmt.Println("OnDisconnectError: ", err)
}

func (c CustomEvents) onConnectError(err error){
fmt.Println("[CLIENT] Failed to connect: ", err)
// OnReceive event interface implementation
func (e Events) OnReceive(data map[string]interface{}){
fmt.Println("OnReceive: ", data)
}

func (c CustomEvents) onDisconnect(){
fmt.Println("[CLIENT] Disconnected" )
// OnReceiveError event interface implementation
func (e Events) OnReceiveError(err error){
if err == io.EOF {
fmt.Println("connection closed ")
} else {
fmt.Println("some error during receive")
}
}

func (c CustomEvents) onDisconnectError(err error){
fmt.Println("[CLIENT] Failed to disconnect: ", err)
// OnJoinError event interface implementation
func (e Events) OnJoinError(roomName string, err error){
fmt.Println("OnJoinError: ", roomName, err)
}

func (c CustomEvents) onReceive(data map[string]interface{}){
b, _ := json.MarshalIndent(data, "", " ")

fmt.Println("[CLIENT] RECEIVED: ", string(b))
// OnLeaveError event interface implementation
func (e Events) OnLeaveError(roomName string, err error){
fmt.Println("OnLeaveError: ", roomName, err)
}

func (c CustomEvents) onReceiveError(err error){
fmt.Println("[CLIENT] Failed to receive: ", err)
// OnSendError event interface implementation
func (e Events) OnSendError(err error){
if err == err.(*net.OpError) {
slog.Error("server was closed")
} else {
slog.Error("unexpected send error: ", "reason", err)
}
}

func (c CustomEvents) onJoin(roomName string){
fmt.Println("[CLIENT] Joined room ", roomName)
}
```

func (c CustomEvents) onJoinError(roomName string, err error){
fmt.Println("[CLIENT] Failed to join room: ", roomName, " ", err)
}
## CLIENT (client.go)

func (c CustomEvents) onLeave(roomName string){
fmt.Println("[CLIENT] Left room: ", roomName)
}
<p>
Connect and interact with a socket server made with github.com/G-MAKROGLOU/websocket-server
</p>

func (c CustomEvents) onLeaveError(roomName string, err error){
fmt.Println("[CLIENT] Failed to leave room: ", roomName, " ", err)
}

func (c CustomEvents) onSend(data map[string]interface{}){
b, _ := json.MarshalIndent(data, "", " ")
```go
package main

fmt.Println("[CLIENT] SENT: ", string(b))
}
import (
"log/slog"
client "github.com/G-MAKROGLOU/websocket-client"
)

func main() {

// setup the client
origin := "http://localhost:3000"
server := "ws://localhost:3000/ws"

//connect
c1 := client.New(origin, server, C1Events{})
if err := c1.Connect(); err != nil {
slog.Error("failed to connect to server")
os.Exit(1)
}

// start listening for incoming messages in a goroutine
go c1.ReceiveJSON()

// broadcast a message to all connected clients
data = map[string]interface{}{
"msg": "pong",
}
c2.SendJSON(data)

// join a room
c1.Join("test")

func (c CustomEvents) onSendError(err error){
fmt.Println("[CLIENT] Failed to send: ", err)
// mutlicast a message to a room
c1.SendJSONTo("test", data)

// leave a room
c1.Leave("test")

// disconnect
c1.Disconnect()
}

```

# CLIENT (client.go)

# Plain Text client for connection with any server that sends text (e.g aisstream)

## CLIENT (clientevents.go)

<p>
Start the client. Place client.Receive() in a goroutine so you have the main thread free for other operations. Free the waitGroup when you are done.
Implement the events interface with the functionality you want to be implemented per event.
Leave empty for no actions on a specific event.
</p>


```go
package main

import (
"encoding/json"
"fmt"
client "github.com/G-MAKROGLOU/websocket-client"
"sync"
"time"
aisstream "github.com/aisstream/ais-message-models/golang/aisStream"
)

var wg sync.WaitGroup
// Events implements SocketClientEvents interface
type Events struct {}

func main() {
wg.Add(1)
// OnDisconnectError event interface implementation
func (e Events) OnDisconnectError(err error){
fmt.Println("OnDisconnectError: ", err)
}

// OnReceive event interface implementation
func (e Events) OnReceive(data map[string]interface{}){
var res aisstream.AisStreamMessage

b, _ := json.Marshal(data)

json.Unmarshal(b, &res)

switch(res.MessageType) {
case aisstream.POSITION_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.UNKNOWN_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.ADDRESSED_SAFETY_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.ADDRESSED_BINARY_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.AIDS_TO_NAVIGATION_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.ASSIGNED_MODE_COMMAND:
fmt.Println(res.MessageType)
break
case aisstream.BASE_STATION_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.BINARY_ACKNOWLEDGE:
fmt.Println(res.MessageType)
break
case aisstream.BINARY_BROADCAST_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.CHANNEL_MANAGEMENT:
fmt.Println(res.MessageType)
break
case aisstream.COORDINATED_UTC_INQUIRY:
fmt.Println(res.MessageType)
break
case aisstream.DATA_LINK_MANAGEMENT_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.DATA_LINK_MANAGEMENT_MESSAGE_DATA:
fmt.Println(res.MessageType)
break
case aisstream.EXTENDED_CLASS_B_POSITION_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.GROUP_ASSIGNMENT_COMMAND:
fmt.Println(res.MessageType)
break
case aisstream.GNSS_BROADCAST_BINARY_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.INTERROGATION:
fmt.Println(res.MessageType)
break
case aisstream.LONG_RANGE_AIS_BROADCAST_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.MULTI_SLOT_BINARY_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.SAFETY_BROADCAST_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.SHIP_STATIC_DATA:
fmt.Println(res.MessageType)
break
case aisstream.SINGLE_SLOT_BINARY_MESSAGE:
fmt.Println(res.MessageType)
break
case aisstream.STANDARD_CLASS_B_POSITION_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.STANDARD_SEARCH_AND_RESCUE_AIRCRAFT_REPORT:
fmt.Println(res.MessageType)
break
case aisstream.STATIC_DATA_REPORT:
fmt.Println(res.MessageType)
break
}
}

// OnReceiveError event interface implementation
func (e Events) OnReceiveError(err error){
if err == io.EOF {
fmt.Println("connection closed ")
} else {
fmt.Println("some error during receive")
}
}

origin := "http://localhost"
server := "ws://localhost:5000/ws"
// OnJoinError event interface implementation
func (e Events) OnJoinError(roomName string, err error){}

client := client.NewSocketClient(origin, server, CustomEvents{})
// OnLeaveError event interface implementation
func (e Events) OnLeaveError(roomName string, err error){}

client.Connect()
// OnSendError event interface implementation
func (e Events) OnSendError(err error){
if err == err.(*net.OpError) {
slog.Error("server was closed")
} else {
slog.Error("unexpected send error: ", "reason", err)
}
}

client.Join("testRoom")
```

go client.Receive()

go testMulticast(client, "CLIENT1")
## CLIENT (client.go)

wg.Wait()
}

func testMulticast(client *client.SocketClient, clientName string) {
index := 0
for {
if index == 10 {
fmt.Println("[MULTICAST] DISCONNECTING CLIENT: ", client.ID)
client.Disconnect()
break
```go
package main

import (
"sync"

client "github.com/G-MAKROGLOU/websocket-client"
aisstream "github.com/aisstream/ais-message-models/golang/aisStream"
)

var waitG sync.WaitGroup

var apiKey = "YOUR-API-KEY"

func main() {
// simulate blocking
waitG.Add(1)

// setup the client
origin := "https://stream.aisstream.io"
server := "wss://stream.aisstream.io/v0/stream"

//connect
c1 := client.New(origin, server, C1Events{})

if err := c1.Connect(); err != nil {
slog.Error("failed to connect to server")
os.Exit(1)
}
time.Sleep(5 * time.Second)

data := map[string]interface{}{
"Message": "[FROM] [" + clientName + "] " + client.ID + " TO ROOM: testRoom",
// start listening for incoming messages in a goroutine. handle incoming messages
// in OnReceive event
go c.ReceiveText()

// send the init message to start receiving text
msg := aisstream.SubscriptionMessage{
APIKey: apiKey,
BoundingBoxes: [][][]float64{{ {-90.0, -180.0}, { 90.0, 180.0 }}},
FiltersShipMMSI: []string{},
}
client.SendTo("testRoom", data)
index++
}

c.SendText(msg)

// simulate end of operations
go func() {
time.Sleep(20 * time.Second)
c.Disconnect()
waitG.Done()
}()

// simulate blocking
waitG.Wait()
}

```


### NOTES

The events are soon going to change and be reducted to a few useful events. For example, OnError(err error) instead of multiple On*Error(err error).
Loading

0 comments on commit 68fa74b

Please sign in to comment.