github.com/anycable/anycable-go@v1.5.1/cli/runner_options.go (about) 1 package cli 2 3 import ( 4 "log/slog" 5 "os" 6 "strings" 7 8 "github.com/anycable/anycable-go/broadcast" 9 "github.com/anycable/anycable-go/broker" 10 "github.com/anycable/anycable-go/config" 11 "github.com/anycable/anycable-go/metrics" 12 "github.com/anycable/anycable-go/node" 13 "github.com/anycable/anycable-go/pubsub" 14 "github.com/anycable/anycable-go/rpc" 15 "github.com/joomcode/errorx" 16 ) 17 18 // Option represents a Runner configuration function 19 type Option func(*Runner) error 20 21 // WithName is an Option to set Runner name 22 func WithName(name string) Option { 23 return func(r *Runner) error { 24 r.name = name 25 return nil 26 } 27 } 28 29 // WithController is an Option to set Runner controller 30 func WithController(fn controllerFactory) Option { 31 return func(r *Runner) error { 32 if r.controllerFactory != nil { 33 return errorx.IllegalArgument.New("Controller has been already assigned") 34 } 35 r.controllerFactory = fn 36 return nil 37 } 38 } 39 40 // WithDefaultRPCController is an Option to set Runner controller to default rpc.Controller 41 func WithDefaultRPCController() Option { 42 return WithController(func(m *metrics.Metrics, c *config.Config, l *slog.Logger) (node.Controller, error) { 43 if c.RPC.Implementation == "none" { 44 return node.NewNullController(l), nil 45 } 46 47 return rpc.NewController(m, &c.RPC, l) 48 }) 49 } 50 51 // WithDisconnector is a an Option to set Runner disconnector 52 func WithDisconnector(fn disconnectorFactory) Option { 53 return func(r *Runner) error { 54 r.disconnectorFactory = fn 55 return nil 56 } 57 } 58 59 // WithBroadcaster is an Option to set Runner broadaster 60 func WithBroadcasters(fn broadcastersFactory) Option { 61 return func(r *Runner) error { 62 r.broadcastersFactory = fn 63 return nil 64 } 65 } 66 67 // WithDefaultBroadcaster is an Option to set Runner subscriber to default broadcaster from config 68 func WithDefaultBroadcaster() Option { 69 return WithBroadcasters(func(h broadcast.Handler, c *config.Config, l *slog.Logger) ([]broadcast.Broadcaster, error) { 70 broadcasters := []broadcast.Broadcaster{} 71 adapters := strings.Split(c.BroadcastAdapter, ",") 72 73 for _, adapter := range adapters { 74 switch adapter { 75 case "http": 76 hb := broadcast.NewHTTPBroadcaster(h, &c.HTTPBroadcast, l) 77 broadcasters = append(broadcasters, hb) 78 case "redis": 79 rb := broadcast.NewLegacyRedisBroadcaster(h, &c.Redis, l) 80 broadcasters = append(broadcasters, rb) 81 case "redisx": 82 rb := broadcast.NewRedisBroadcaster(h, &c.Redis, l) 83 broadcasters = append(broadcasters, rb) 84 case "nats": 85 nb := broadcast.NewLegacyNATSBroadcaster(h, &c.NATS, l) 86 broadcasters = append(broadcasters, nb) 87 default: 88 return broadcasters, errorx.IllegalArgument.New("Unsupported broadcast adapter: %s", adapter) 89 } 90 } 91 92 return broadcasters, nil 93 }) 94 } 95 96 // WithSubscriber is an Option to set Runner subscriber 97 func WithSubscriber(fn subscriberFactory) Option { 98 return func(r *Runner) error { 99 if r.subscriberFactory != nil { 100 return errorx.IllegalArgument.New("Subscriber has been already assigned") 101 } 102 r.subscriberFactory = fn 103 return nil 104 } 105 } 106 107 // WithDefaultSubscriber is an Option to set Runner subscriber to pubsub.NewSubscriber 108 func WithDefaultSubscriber() Option { 109 return WithSubscriber(func(h pubsub.Handler, c *config.Config, l *slog.Logger) (pubsub.Subscriber, error) { 110 switch c.PubSubAdapter { 111 case "": 112 return pubsub.NewLegacySubscriber(h), nil 113 case "redis": 114 return pubsub.NewRedisSubscriber(h, &c.Redis, l) 115 case "nats": 116 return pubsub.NewNATSSubscriber(h, &c.NATS, l) 117 } 118 119 return nil, errorx.IllegalArgument.New("Unsupported subscriber adapter: %s", c.PubSubAdapter) 120 }) 121 } 122 123 // WithShutdowable adds a new shutdownable instance to be shutdown at server stop 124 func WithShutdownable(instance Shutdownable) Option { 125 return func(r *Runner) error { 126 r.shutdownables = append(r.shutdownables, instance) 127 return nil 128 } 129 } 130 131 // WithBroker is an Option to set Runner broker 132 func WithBroker(fn brokerFactory) Option { 133 return func(r *Runner) error { 134 if r.brokerFactory != nil { 135 return errorx.IllegalArgument.New("Broker has been already assigned") 136 } 137 r.brokerFactory = fn 138 return nil 139 } 140 } 141 142 // WithWebSocketHandler is an Option to set a custom websocket handler 143 func WithWebSocketHandler(fn websocketHandler) Option { 144 return func(r *Runner) error { 145 r.websocketHandlerFactory = fn 146 return nil 147 } 148 } 149 150 // WithWebSocketEndpoint is an Option to set a custom websocket handler at 151 // the specified path 152 func WithWebSocketEndpoint(path string, fn websocketHandler) Option { 153 return func(r *Runner) error { 154 r.websocketEndpoints[path] = fn 155 return nil 156 } 157 } 158 159 // WithDefaultBroker is an Option to set Runner broker to default broker from config 160 func WithDefaultBroker() Option { 161 return WithBroker(func(br broker.Broadcaster, c *config.Config, l *slog.Logger) (broker.Broker, error) { 162 if c.BrokerAdapter == "" { 163 return broker.NewLegacyBroker(br), nil 164 } 165 166 switch c.BrokerAdapter { 167 case "memory": 168 b := broker.NewMemoryBroker(br, &c.Broker) 169 return b, nil 170 case "nats": 171 // TODO: Figure out a better place for this hack. 172 // We don't want to enable JetStream by default (if NATS is used only for pub/sub), 173 // currently, we only need it when NATS is used as a broker. 174 c.EmbeddedNats.JetStream = true 175 b := broker.NewNATSBroker(br, &c.Broker, &c.NATS, l) 176 return b, nil 177 default: 178 return nil, errorx.IllegalArgument.New("Unsupported broker adapter: %s", c.BrokerAdapter) 179 } 180 }) 181 } 182 183 // WithTelemetry enables AnyCable telemetry unless ANYCABLE_DISABLE_TELEMETRY is set 184 func WithTelemetry() Option { 185 return func(r *Runner) error { 186 r.telemetryEnabled = os.Getenv("ANYCABLE_DISABLE_TELEMETRY") != "true" 187 return nil 188 } 189 } 190 191 // WithLogger set ups a logger for the AnyCable app 192 func WithLogger(logger *slog.Logger) Option { 193 return func(r *Runner) error { 194 r.log = logger 195 return nil 196 } 197 }