github.com/philippseith/signalr@v0.6.3/clientoptions.go (about) 1 package signalr 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/cenkalti/backoff/v4" 9 ) 10 11 // WithConnection sets the Connection of the Client 12 func WithConnection(connection Connection) func(party Party) error { 13 return func(party Party) error { 14 if client, ok := party.(*client); ok { 15 if client.connectionFactory != nil { 16 return errors.New("options WithConnection and WithConnector can not be used together") 17 } 18 client.conn = connection 19 return nil 20 } 21 return errors.New("option WithConnection is client only") 22 } 23 } 24 25 // WithConnector allows the Client to establish a connection 26 // using the Connection build by the connectionFactory. 27 // It is also used for auto reconnect if the connection is lost. 28 func WithConnector(connectionFactory func() (Connection, error)) func(Party) error { 29 return func(party Party) error { 30 if client, ok := party.(*client); ok { 31 if client.conn != nil { 32 return errors.New("options WithConnection and WithConnector can not be used together") 33 } 34 client.connectionFactory = connectionFactory 35 return nil 36 } 37 return errors.New("option WithConnector is client only") 38 } 39 } 40 41 // HttpConnectionFactory is a connectionFactory for WithConnector which first tries to create a connection 42 // with WebSockets (if it is allowed by the HttpConnection options) and if this fails, falls back to a SSE based connection. 43 func HttpConnectionFactory(ctx context.Context, address string, options ...func(*httpConnection) error) (Connection, error) { 44 conn := &httpConnection{} 45 for i, option := range options { 46 if err := option(conn); err != nil { 47 return nil, err 48 } 49 if conn.transports != nil { 50 // Remove the WithTransports option 51 options = append(options[:i], options[i+1:]...) 52 break 53 } 54 } 55 // If no WithTransports was given, NewHTTPConnection fallbacks to both 56 if conn.transports == nil { 57 conn.transports = []TransportType{TransportWebSockets, TransportServerSentEvents} 58 } 59 60 for _, transport := range conn.transports { 61 // If Websockets are allowed, we try to connect with these 62 if transport == TransportWebSockets { 63 wsOptions := append(options, WithTransports(TransportWebSockets)) 64 conn, err := NewHTTPConnection(ctx, address, wsOptions...) 65 // If this is ok, return the conn 66 if err == nil { 67 return conn, err 68 } 69 break 70 } 71 } 72 for _, transport := range conn.transports { 73 // If SSE is allowed, with fallback to try these 74 if transport == TransportServerSentEvents { 75 sseOptions := append(options, WithTransports(TransportServerSentEvents)) 76 return NewHTTPConnection(ctx, address, sseOptions...) 77 } 78 } 79 // None of the transports worked 80 return nil, fmt.Errorf("can not connect with supported transports: %v", conn.transports) 81 } 82 83 // WithHttpConnection first tries to create a connection 84 // with WebSockets (if it is allowed by the HttpConnection options) and if this fails, falls back to a SSE based connection. 85 // This strategy is also used for auto reconnect if this option is used. 86 // WithHttpConnection is a shortcut for WithConnector(HttpConnectionFactory(...)) 87 func WithHttpConnection(ctx context.Context, address string, options ...func(*httpConnection) error) func(Party) error { 88 return WithConnector(func() (Connection, error) { 89 return HttpConnectionFactory(ctx, address, options...) 90 }) 91 } 92 93 // WithReceiver sets the object which will receive server side calls to client methods (e.g. callbacks) 94 func WithReceiver(receiver interface{}) func(Party) error { 95 return func(party Party) error { 96 if client, ok := party.(*client); ok { 97 client.receiver = receiver 98 if receiver, ok := receiver.(ReceiverInterface); ok { 99 receiver.Init(client) 100 } 101 return nil 102 } 103 return errors.New("option WithReceiver is client only") 104 } 105 } 106 107 // WithBackoff sets the backoff.BackOff used for repeated connection attempts in the client. 108 // See https://pkg.go.dev/github.com/cenkalti/backoff for configuration options. 109 // If the option is not set, backoff.NewExponentialBackOff() without any further configuration will be used. 110 func WithBackoff(backoffFactory func() backoff.BackOff) func(party Party) error { 111 return func(party Party) error { 112 if client, ok := party.(*client); ok { 113 client.backoffFactory = backoffFactory 114 return nil 115 } 116 return errors.New("option WithBackoff is client only") 117 } 118 } 119 120 // TransferFormat sets the transfer format used on the transport. Allowed values are "Text" and "Binary" 121 func TransferFormat(format TransferFormatType) func(Party) error { 122 return func(p Party) error { 123 if c, ok := p.(*client); ok { 124 switch format { 125 case "Text": 126 c.format = "json" 127 case "Binary": 128 c.format = "messagepack" 129 default: 130 return fmt.Errorf("invalid transferformat %v", format) 131 } 132 return nil 133 } 134 return errors.New("option TransferFormat is client only") 135 } 136 }