feat: initial commit
This commit is contained in:
137
reach/client/socketio/client.go
Normal file
137
reach/client/socketio/client.go
Normal file
@ -0,0 +1,137 @@
|
||||
package socketio
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
gosocketio "forge.cadoles.com/Pyxis/golang-socketio"
|
||||
"forge.cadoles.com/Pyxis/golang-socketio/transport"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Channel = gosocketio.Channel
|
||||
|
||||
const (
|
||||
OnDisconnection = gosocketio.OnDisconnection
|
||||
OnConnection = gosocketio.OnConnection
|
||||
OnError = gosocketio.OnError
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conn *gosocketio.Client
|
||||
mutex sync.RWMutex
|
||||
endpoint string
|
||||
opts *Options
|
||||
}
|
||||
|
||||
func (c *Client) Connect() error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
var err error
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
transport := &transport.WebsocketTransport{
|
||||
PingInterval: c.opts.PingInterval,
|
||||
PingTimeout: c.opts.PingTimeout,
|
||||
ReceiveTimeout: c.opts.ReceiveTimeout,
|
||||
SendTimeout: c.opts.SendTimeout,
|
||||
BufferSize: c.opts.BufferSize,
|
||||
}
|
||||
|
||||
conn, err := gosocketio.Dial(c.endpoint, transport)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while connecting to endpoint")
|
||||
}
|
||||
|
||||
c.conn = nil
|
||||
|
||||
cleanup := func() {
|
||||
conn.Off(gosocketio.OnError)
|
||||
conn.Off(gosocketio.OnConnection)
|
||||
}
|
||||
|
||||
err = conn.On(gosocketio.OnConnection, func(h *Channel) {
|
||||
cleanup()
|
||||
wg.Done()
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while attaching to connection event")
|
||||
}
|
||||
|
||||
err = conn.On(gosocketio.OnError, func(h *Channel) {
|
||||
cleanup()
|
||||
err = errors.Errorf("an unknown error occured")
|
||||
wg.Done()
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while attaching to error event")
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
c.conn = conn
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) Close() {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if c.conn == nil {
|
||||
return
|
||||
}
|
||||
c.conn.Close()
|
||||
c.conn = nil
|
||||
}
|
||||
|
||||
func (c *Client) Alive() bool {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
|
||||
if c.conn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return c.conn.IsAlive()
|
||||
}
|
||||
|
||||
// Emit a new event with the given data
|
||||
func (c *Client) Emit(event string, data any) error {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
|
||||
if err := c.conn.Emit(event, data); err != nil {
|
||||
return errors.Wrapf(err, "error while emitting '%s' event", event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Handler func(ch *Channel, data any)
|
||||
|
||||
// On binds and event handler to the given event
|
||||
func (c *Client) On(event string, handler Handler) error {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
|
||||
return c.conn.On(event, handler)
|
||||
}
|
||||
|
||||
// Off remove the handler bound to the given event
|
||||
func (c *Client) Off(event string) {
|
||||
c.mutex.RLock()
|
||||
defer c.mutex.RUnlock()
|
||||
|
||||
c.conn.Off(event)
|
||||
}
|
||||
|
||||
func NewClient(endpoint string, funcs ...OptionFunc) *Client {
|
||||
opts := NewOptions(funcs...)
|
||||
client := &Client{
|
||||
endpoint: endpoint,
|
||||
opts: opts,
|
||||
}
|
||||
return client
|
||||
}
|
38
reach/client/socketio/endpoint.go
Normal file
38
reach/client/socketio/endpoint.go
Normal file
@ -0,0 +1,38 @@
|
||||
package socketio
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
gosocketio "forge.cadoles.com/Pyxis/golang-socketio"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func EndpointFromHAddr(addr string) (string, error) {
|
||||
host, rawPort, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
var addrErr *net.AddrError
|
||||
if !errors.As(err, &addrErr) || !strings.Contains(addrErr.Error(), "missing port in address") {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
host = addr
|
||||
}
|
||||
|
||||
port := int64(80)
|
||||
if rawPort != "" {
|
||||
port, err = strconv.ParseInt(rawPort, 10, 32)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
endpoint := Endpoint(host, int(port), false)
|
||||
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
func Endpoint(host string, port int, secure bool) string {
|
||||
return gosocketio.GetUrl(host, port, false)
|
||||
}
|
62
reach/client/socketio/options.go
Normal file
62
reach/client/socketio/options.go
Normal file
@ -0,0 +1,62 @@
|
||||
package socketio
|
||||
|
||||
import "time"
|
||||
|
||||
type Options struct {
|
||||
PingInterval time.Duration
|
||||
PingTimeout time.Duration
|
||||
ReceiveTimeout time.Duration
|
||||
SendTimeout time.Duration
|
||||
BufferSize int
|
||||
}
|
||||
|
||||
type OptionFunc func(opts *Options)
|
||||
|
||||
func NewOptions(funcs ...OptionFunc) *Options {
|
||||
opts := &Options{
|
||||
PingInterval: 5 * time.Second,
|
||||
PingTimeout: 60 * time.Second,
|
||||
ReceiveTimeout: 60 * time.Second,
|
||||
SendTimeout: 60 * time.Second,
|
||||
BufferSize: 1024 * 32,
|
||||
}
|
||||
for _, fn := range funcs {
|
||||
fn(opts)
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
// WithPingInterval configures the client to use the given ping interval
|
||||
func WithPingInterval(interval time.Duration) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.PingInterval = interval
|
||||
}
|
||||
}
|
||||
|
||||
// WithPingTimeout configures the client to use the given ping timeout
|
||||
func WithPingTimeout(timeout time.Duration) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.PingTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithReceiveTimeout configures the client to use the given receive timeout
|
||||
func WithReceiveTimeout(timeout time.Duration) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.ReceiveTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithSendTimeout configures the client to use the given send timeout
|
||||
func WithSendTimeout(timeout time.Duration) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.SendTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithBufferSize configures the client to use the given buffer size
|
||||
func WithBufferSize(size int) OptionFunc {
|
||||
return func(opts *Options) {
|
||||
opts.BufferSize = size
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user