@@ -23,10 +23,10 @@ const (
23
23
protocolJSON = "application/json"
24
24
protocolMsgPack = "application/x-msgpack"
25
25
26
- // restHost is the primary ably host.
27
- restHost = "rest.ably.io "
28
- // realtimeHost is the primary ably host.
29
- realtimeHost = "realtime.ably.io"
26
+ // defaultEndpoint is the default routing policy used to connect to Ably
27
+ defaultEndpoint = "main "
28
+ defaultPrimaryHost = "main.realtime. ably.net" // REC1a
29
+
30
30
Port = 80
31
31
TLSPort = 443
32
32
maxMessageSize = 65536 // 64kb, default value TO3l8
@@ -37,11 +37,12 @@ const (
37
37
)
38
38
39
39
var defaultOptions = clientOptions {
40
- RESTHost : restHost ,
41
- FallbackHosts : defaultFallbackHosts (),
40
+ Endpoint : defaultEndpoint ,
41
+ RESTHost : defaultPrimaryHost ,
42
+ FallbackHosts : getEndpointFallbackHosts (defaultEndpoint ), // REC2c1
42
43
HTTPMaxRetryCount : 3 ,
43
44
HTTPRequestTimeout : 10 * time .Second ,
44
- RealtimeHost : realtimeHost ,
45
+ RealtimeHost : defaultPrimaryHost ,
45
46
TimeoutDisconnect : 30 * time .Second ,
46
47
ConnectionStateTTL : 120 * time .Second ,
47
48
RealtimeRequestTimeout : 10 * time .Second , // DF1b
@@ -58,23 +59,31 @@ var defaultOptions = clientOptions{
58
59
LogLevel : LogWarning , // RSC2
59
60
}
60
61
61
- func defaultFallbackHosts () []string {
62
- return []string {
63
- "a.ably-realtime.com" ,
64
- "b.ably-realtime.com" ,
65
- "c.ably-realtime.com" ,
66
- "d.ably-realtime.com" ,
67
- "e.ably-realtime.com" ,
62
+ func getPrimaryHost (root string ) string {
63
+ // REC1b3
64
+ if strings .HasPrefix (root , "nonprod:" ) {
65
+ root := strings .TrimPrefix (root , "nonprod:" )
66
+ return fmt .Sprintf ("%s.realtime.ably-nonprod.net" , root )
67
+ }
68
+ return fmt .Sprintf ("%s.realtime.ably.net" , root )
69
+ }
70
+
71
+ func getEndpointFallbackHosts (endpoint string ) []string {
72
+ if strings .HasPrefix (endpoint , "nonprod:" ) { // REC2c3
73
+ root := strings .TrimPrefix (endpoint , "nonprod:" )
74
+ return endpointFallbacks (root , "ably-realtime-nonprod.com" )
68
75
}
76
+ return endpointFallbacks (endpoint , "ably-realtime.com" ) // REC2c4
69
77
}
70
78
71
- func getEnvFallbackHosts (env string ) []string {
79
+ // endpointFallbacks generates a list of fallback hosts based on the given namespace and root.
80
+ func endpointFallbacks (root , domain string ) []string {
72
81
return []string {
73
- fmt .Sprintf ("%s- %s" , env , "a-fallback.ably-realtime.com" ),
74
- fmt .Sprintf ("%s- %s" , env , "b-fallback.ably-realtime.com" ),
75
- fmt .Sprintf ("%s- %s" , env , "c-fallback.ably-realtime.com" ),
76
- fmt .Sprintf ("%s- %s" , env , "d-fallback.ably-realtime.com" ),
77
- fmt .Sprintf ("%s- %s" , env , "e-fallback.ably-realtime.com" ),
82
+ fmt .Sprintf ("%s.a.fallback. %s" , root , domain ),
83
+ fmt .Sprintf ("%s.b.fallback. %s" , root , domain ),
84
+ fmt .Sprintf ("%s.c.fallback. %s" , root , domain ),
85
+ fmt .Sprintf ("%s.d.fallback. %s" , root , domain ),
86
+ fmt .Sprintf ("%s.e.fallback. %s" , root , domain ),
78
87
}
79
88
}
80
89
@@ -244,8 +253,11 @@ type clientOptions struct {
244
253
// authOptions Embedded an [ably.authOptions] object (TO3j).
245
254
authOptions
246
255
247
- // RESTHost enables a non-default Ably host to be specified. For development environments only.
248
- // The default value is rest.ably.io (RSC12, TO3k2).
256
+ // Endpoint specifies either a routing policy name or fully qualified domain name to connect to Ably.
257
+ Endpoint string
258
+
259
+ // Deprecated: this property is deprecated and will be removed in a future version.
260
+ // If the restHost option is specified the primary domain is the value of the restHost option REC1d1).
249
261
RESTHost string
250
262
251
263
// Deprecated: this property is deprecated and will be removed in a future version.
@@ -257,12 +269,14 @@ type clientOptions struct {
257
269
// please specify them here (RSC15b, RSC15a, TO3k6).
258
270
FallbackHosts []string
259
271
260
- // RealtimeHost enables a non-default Ably host to be specified for realtime connections .
261
- // For development environments only. The default value is realtime.ably.io (RTC1d, TO3k3 ).
272
+ // Deprecated: this property is deprecated and will be removed in a future version .
273
+ // If the realtimeHost option is specified the primary domain is the value of the realtimeHost option (REC1d2 ).
262
274
RealtimeHost string
263
275
264
- // Environment enables a custom environment to be used with the Ably service.
265
- // Optional: prefixes both hostname with the environment string (RSC15b, TO3k1).
276
+ // Deprecated: this property is deprecated and will be removed in a future version.
277
+ // If the deprecated environment option is specified then it defines a production routing policy name [name] (REC1c):
278
+ // If any one of the deprecated options restHost, realtimeHost are also specified then the options as a set are invalid (REC1c1).
279
+ // Otherwise, the primary domain is [name].realtime.ably.net (REC1c2).
266
280
Environment string
267
281
268
282
// Port is used for non-TLS connections and requests
@@ -415,6 +429,14 @@ type clientOptions struct {
415
429
}
416
430
417
431
func (opts * clientOptions ) validate () error {
432
+ // REC1b1
433
+ if ! empty (opts .Endpoint ) && (! empty (opts .Environment ) || ! empty (opts .RealtimeHost ) || ! empty (opts .RESTHost ) || opts .FallbackHostsUseDefault ) {
434
+ err := errors .New ("invalid client option: cannot use endpoint with any of deprecated options environment, realtimeHost, restHost or FallbackHostsUseDefault" )
435
+ logger := opts .LogHandler
436
+ logger .Printf (LogError , "Invalid client options : %v" , err .Error ())
437
+ return err
438
+ }
439
+
418
440
_ , err := opts .getFallbackHosts ()
419
441
if err != nil {
420
442
logger := opts .LogHandler
@@ -451,16 +473,22 @@ func (opts *clientOptions) activePort() (port int, isDefault bool) {
451
473
}
452
474
453
475
func (opts * clientOptions ) getRestHost () string {
476
+ if ! empty (opts .Endpoint ) {
477
+ return opts .getHostnameFromEndpoint ()
478
+ }
454
479
if ! empty (opts .RESTHost ) {
455
480
return opts .RESTHost
456
481
}
457
482
if ! opts .isProductionEnvironment () {
458
- return opts .Environment + "-" + defaultOptions . RESTHost
483
+ return getPrimaryHost ( opts .Environment )
459
484
}
460
485
return defaultOptions .RESTHost
461
486
}
462
487
463
488
func (opts * clientOptions ) getRealtimeHost () string {
489
+ if ! empty (opts .Endpoint ) {
490
+ return opts .getHostnameFromEndpoint ()
491
+ }
464
492
if ! empty (opts .RealtimeHost ) {
465
493
return opts .RealtimeHost
466
494
}
@@ -470,11 +498,29 @@ func (opts *clientOptions) getRealtimeHost() string {
470
498
return opts .RESTHost
471
499
}
472
500
if ! opts .isProductionEnvironment () {
473
- return opts .Environment + "-" + defaultOptions . RealtimeHost
501
+ return getPrimaryHost ( opts .Environment )
474
502
}
475
503
return defaultOptions .RealtimeHost
476
504
}
477
505
506
+ // isEndpointFQDN returns true if the given endpoint is a hostname, which may
507
+ // be an IPv4 address, IPv6 address or localhost
508
+ func isEndpointFQDN (endpoint string ) bool {
509
+ return strings .Contains (endpoint , "." ) || strings .Contains (endpoint , "::" ) || endpoint == "localhost"
510
+ }
511
+
512
+ // REC1b
513
+ func (opts * clientOptions ) getHostnameFromEndpoint () string {
514
+ endpoint := opts .Endpoint
515
+ if empty (endpoint ) {
516
+ return defaultPrimaryHost
517
+ }
518
+ if isEndpointFQDN (endpoint ) { // REC1b2
519
+ return endpoint
520
+ }
521
+ return getPrimaryHost (endpoint ) // REC1b4
522
+ }
523
+
478
524
func empty (s string ) bool {
479
525
return len (strings .TrimSpace (s )) == 0
480
526
}
@@ -506,6 +552,16 @@ func (opts *clientOptions) realtimeURL(realtimeHost string) (realtimeUrl string)
506
552
}
507
553
508
554
func (opts * clientOptions ) getFallbackHosts () ([]string , error ) {
555
+ if ! empty (opts .Endpoint ) {
556
+ if opts .FallbackHosts == nil {
557
+ if isEndpointFQDN (opts .Endpoint ) { // REC2c2
558
+ return opts .FallbackHosts , nil
559
+ }
560
+ return getEndpointFallbackHosts (opts .Endpoint ), nil
561
+ }
562
+ return opts .FallbackHosts , nil //REC2a2
563
+ }
564
+
509
565
logger := opts .LogHandler
510
566
_ , isDefaultPort := opts .activePort ()
511
567
if opts .FallbackHostsUseDefault {
@@ -525,7 +581,7 @@ func (opts *clientOptions) getFallbackHosts() ([]string, error) {
525
581
if opts .isProductionEnvironment () {
526
582
return defaultOptions .FallbackHosts , nil
527
583
}
528
- return getEnvFallbackHosts (opts .Environment ), nil
584
+ return getEndpointFallbackHosts (opts .Environment ), nil // REC2c5
529
585
}
530
586
return opts .FallbackHosts , nil
531
587
}
@@ -1070,9 +1126,23 @@ func WithEchoMessages(echo bool) ClientOption {
1070
1126
}
1071
1127
}
1072
1128
1073
- // WithEnvironment is used for setting Environment using [ably.ClientOption].
1074
- // Environment enables a custom environment to be used with the Ably service.
1075
- // Optional: prefixes both hostname with the environment string (RSC15b, TO3k1).
1129
+ // WithEndpoint sets a custom endpoint for connecting to the Ably service (see
1130
+ // [Platform Customization] for more information).
1131
+ //
1132
+ // [Platform Customization]: https://ably.com/docs/platform-customization
1133
+ func WithEndpoint (env string ) ClientOption {
1134
+ return func (os * clientOptions ) {
1135
+ os .Endpoint = env
1136
+ }
1137
+ }
1138
+
1139
+ // WithEnvironment sets a custom endpoint for connecting to the Ably service
1140
+ // (see [Platform Customization] for more information).
1141
+ //
1142
+ // Deprecated: this option is deprecated and will be removed in a future
1143
+ // version.
1144
+ //
1145
+ // [Platform Customization]: https://ably.com/docs/platform-customization
1076
1146
func WithEnvironment (env string ) ClientOption {
1077
1147
return func (os * clientOptions ) {
1078
1148
os .Environment = env
@@ -1130,6 +1200,9 @@ func WithQueueMessages(queue bool) ClientOption {
1130
1200
// WithRESTHost is used for setting RESTHost using [ably.ClientOption].
1131
1201
// RESTHost enables a non-default Ably host to be specified. For development environments only.
1132
1202
// The default value is rest.ably.io (RSC12, TO3k2).
1203
+ //
1204
+ // Deprecated: this option is deprecated and will be removed in a future
1205
+ // version.
1133
1206
func WithRESTHost (host string ) ClientOption {
1134
1207
return func (os * clientOptions ) {
1135
1208
os .RESTHost = host
@@ -1149,6 +1222,9 @@ func WithHTTPRequestTimeout(timeout time.Duration) ClientOption {
1149
1222
// WithRealtimeHost is used for setting RealtimeHost using [ably.ClientOption].
1150
1223
// RealtimeHost enables a non-default Ably host to be specified for realtime connections.
1151
1224
// For development environments only. The default value is realtime.ably.io (RTC1d, TO3k3).
1225
+ //
1226
+ // Deprecated: this option is deprecated and will be removed in a future
1227
+ // version.
1152
1228
func WithRealtimeHost (host string ) ClientOption {
1153
1229
return func (os * clientOptions ) {
1154
1230
os .RealtimeHost = host
@@ -1331,6 +1407,7 @@ func WithInsecureAllowBasicAuthWithoutTLS() ClientOption {
1331
1407
func applyOptionsWithDefaults (opts ... ClientOption ) * clientOptions {
1332
1408
to := defaultOptions
1333
1409
// No need to set hosts by default
1410
+ to .Endpoint = ""
1334
1411
to .RESTHost = ""
1335
1412
to .RealtimeHost = ""
1336
1413
to .FallbackHosts = nil
0 commit comments