Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 40a3f5a

Browse files
authored
feat(core): http proxying via setup configuration (segmentio#202)
extended the configuration API to allow directing analytics traffic through a hosted proxy (or other)
1 parent ecce14c commit 40a3f5a

File tree

8 files changed

+152
-30
lines changed

8 files changed

+152
-30
lines changed

packages/core/android/src/main/java/com/segment/analytics/reactnative/core/RNAnalyticsModule.kt

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,14 @@ package com.segment.analytics.reactnative.core
2626

2727
import android.content.pm.PackageInfo
2828
import android.content.pm.PackageManager
29+
import android.net.Uri
2930
import com.facebook.react.bridge.*
30-
import com.segment.analytics.Analytics
31-
import com.segment.analytics.Properties
32-
import com.segment.analytics.Options
33-
import com.segment.analytics.Traits
34-
import com.segment.analytics.ValueMap
3531
import com.segment.analytics.internal.Utils.getSegmentSharedPreferences
3632
import java.util.concurrent.TimeUnit
3733
import com.facebook.react.bridge.ReadableMap
34+
import com.segment.analytics.*
35+
import java.io.IOException
36+
import java.net.HttpURLConnection
3837

3938

4039

@@ -155,6 +154,37 @@ class RNAnalyticsModule(context: ReactApplicationContext): ReactContextBaseJavaM
155154
builder.trackApplicationLifecycleEvents()
156155
}
157156

157+
if(options.hasKey("proxy") && options.getType("proxy") == ReadableType.Map) {
158+
val proxyOptions = options.getMap("proxy")!!
159+
160+
builder.connectionFactory(object:ConnectionFactory() {
161+
override fun openConnection(url:String): HttpURLConnection {
162+
val uri = Uri.parse(url)
163+
val uriBuilder = uri.buildUpon();
164+
165+
if (proxyOptions.hasKey("scheme")) {
166+
uriBuilder.scheme(proxyOptions.getString("scheme"))
167+
}
168+
169+
if (proxyOptions.hasKey("host")) {
170+
var host = proxyOptions.getString("host");
171+
172+
if (proxyOptions.hasKey("port")) {
173+
host = host + ":" + proxyOptions.getInt("port");
174+
}
175+
176+
uriBuilder.encodedAuthority(host)
177+
}
178+
179+
if (proxyOptions.hasKey("path")) {
180+
uriBuilder.path(proxyOptions.getString("path") + uri.path)
181+
}
182+
183+
return super.openConnection(uriBuilder.toString())
184+
}
185+
})
186+
}
187+
158188
try {
159189
Analytics.setSingletonInstance(
160190
RNAnalytics.buildWithIntegrations(builder)

packages/core/docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
**Ƭ Integration**: *`function` \| `object`*
2626

27-
*Defined in [analytics.ts:8](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L8)*
27+
*Defined in [analytics.ts:8](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L8)*
2828

2929
___
3030

packages/core/docs/classes/analytics.client.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
**● ready**: *`false`* = false
4141

42-
*Defined in [analytics.ts:104](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L104)*
42+
*Defined in [analytics.ts:147](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L147)*
4343

4444
Whether the client is ready to send events to Segment.
4545

@@ -55,7 +55,7 @@ ___
5555

5656
**alias**(newId: *`string`*, options?: *[Options]()*): `Promise`<`void`>
5757

58-
*Defined in [analytics.ts:274](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L274)*
58+
*Defined in [analytics.ts:317](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L317)*
5959

6060
Merge two user identities, effectively connecting two sets of user data as one. This may not be supported by all integrations.
6161

@@ -77,7 +77,7 @@ ___
7777

7878
**catch**(handler: *[ErrorHandler]()*): `this`
7979

80-
*Defined in [analytics.ts:119](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L119)*
80+
*Defined in [analytics.ts:162](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L162)*
8181

8282
Catch React-Native bridge errors
8383

@@ -98,7 +98,7 @@ ___
9898

9999
**disable**(): `Promise`<`void`>
100100

101-
*Defined in [analytics.ts:313](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L313)*
101+
*Defined in [analytics.ts:356](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L356)*
102102

103103
Completely disable the sending of any analytics data.
104104

@@ -113,7 +113,7 @@ ___
113113

114114
**enable**(): `Promise`<`void`>
115115

116-
*Defined in [analytics.ts:303](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L303)*
116+
*Defined in [analytics.ts:346](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L346)*
117117

118118
Enable the sending of analytics data. Enabled by default.
119119

@@ -128,7 +128,7 @@ ___
128128

129129
**flush**(): `Promise`<`void`>
130130

131-
*Defined in [analytics.ts:294](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L294)*
131+
*Defined in [analytics.ts:337](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L337)*
132132

133133
Trigger an upload of all queued events.
134134

@@ -143,7 +143,7 @@ ___
143143

144144
**getAnonymousId**(): `Promise`<`string`>
145145

146-
*Defined in [analytics.ts:318](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L318)*
146+
*Defined in [analytics.ts:361](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L361)*
147147

148148
Retrieve the anonymousId.
149149

@@ -156,7 +156,7 @@ ___
156156

157157
**group**(groupId: *`string`*, traits?: *[JsonMap]()*, options?: *[Options]()*): `Promise`<`void`>
158158

159-
*Defined in [analytics.ts:261](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L261)*
159+
*Defined in [analytics.ts:304](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L304)*
160160

161161
Associate a user with a group, organization, company, project, or w/e _you_ call them.
162162

@@ -179,7 +179,7 @@ ___
179179

180180
**identify**(user: *`string`*, traits?: *[JsonMap]()*, options?: *[Options]()*): `Promise`<`void`>
181181

182-
*Defined in [analytics.ts:248](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L248)*
182+
*Defined in [analytics.ts:291](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L291)*
183183

184184
Associate a user with their unique ID and record traits about them.
185185

@@ -202,7 +202,7 @@ ___
202202

203203
**middleware**(middleware: *[Middleware]()*): `this`
204204

205-
*Defined in [analytics.ts:157](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L157)*
205+
*Defined in [analytics.ts:200](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L200)*
206206

207207
Append a new middleware to the middleware chain.
208208

@@ -240,7 +240,7 @@ ___
240240

241241
**reset**(): `Promise`<`void`>
242242

243-
*Defined in [analytics.ts:284](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L284)*
243+
*Defined in [analytics.ts:327](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L327)*
244244

245245
Reset any user state that is cached on the device.
246246

@@ -255,7 +255,7 @@ ___
255255

256256
**screen**(name: *`string`*, properties?: *[JsonMap]()*, options?: *[Options]()*): `Promise`<`void`>
257257

258-
*Defined in [analytics.ts:233](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L233)*
258+
*Defined in [analytics.ts:276](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L276)*
259259

260260
Record the screens or views your users see.
261261

@@ -278,7 +278,7 @@ ___
278278

279279
**setup**(writeKey: *`string`*, configuration?: *[Configuration](../interfaces/analytics.configuration.md)*): `Promise`<`void`>
280280

281-
*Defined in [analytics.ts:196](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L196)*
281+
*Defined in [analytics.ts:239](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L239)*
282282

283283
Setup the Analytics module. All calls made before are queued and only executed if the configuration was successful.
284284

@@ -308,7 +308,7 @@ ___
308308

309309
**track**(event: *`string`*, properties?: *[JsonMap]()*, options?: *[Options]()*): `Promise`<`void`>
310310

311-
*Defined in [analytics.ts:215](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L215)*
311+
*Defined in [analytics.ts:258](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L258)*
312312

313313
Record the actions your users perform.
314314

@@ -331,7 +331,7 @@ ___
331331

332332
**useNativeConfiguration**(): `this`
333333

334-
*Defined in [analytics.ts:169](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L169)*
334+
*Defined in [analytics.ts:212](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L212)*
335335

336336
Use the native configuration.
337337

packages/core/docs/interfaces/analytics.configuration.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* [defaultProjectSettings](analytics.configuration.md#defaultprojectsettings)
1616
* [flushAt](analytics.configuration.md#flushat)
1717
* [ios](analytics.configuration.md#ios)
18+
* [proxy](analytics.configuration.md#proxy)
1819
* [recordScreenViews](analytics.configuration.md#recordscreenviews)
1920
* [trackAppLifecycleEvents](analytics.configuration.md#trackapplifecycleevents)
2021
* [trackAttributionData](analytics.configuration.md#trackattributiondata)
@@ -30,7 +31,7 @@
3031

3132
**● android**: *`undefined` \| `object`*
3233

33-
*Defined in [analytics.ts:77](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L77)*
34+
*Defined in [analytics.ts:120](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L120)*
3435

3536
Android specific settings.
3637

@@ -41,7 +42,7 @@ ___
4142

4243
**● debug**: *`undefined` \| `false` \| `true`*
4344

44-
*Defined in [analytics.ts:38](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L38)*
45+
*Defined in [analytics.ts:38](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L38)*
4546

4647
___
4748
<a id="defaultprojectsettings"></a>
@@ -50,7 +51,7 @@ ___
5051

5152
**● defaultProjectSettings**: *`undefined` \| `object`*
5253

53-
*Defined in [analytics.ts:46](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L46)*
54+
*Defined in [analytics.ts:46](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L46)*
5455

5556
Default project settings to use, if Segment.com cannot be reached. An example configuration can be found here, using your write key: [](https://cdn-settings.segment.com/v1/projects/YOUR_WRITE_KEY/settings)[https://cdn-settings.segment.com/v1/projects/YOUR\_WRITE\_KEY/settings](https://cdn-settings.segment.com/v1/projects/YOUR_WRITE_KEY/settings)
5657

@@ -61,7 +62,7 @@ ___
6162

6263
**● flushAt**: *`undefined` \| `number`*
6364

64-
*Defined in [analytics.ts:54](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L54)*
65+
*Defined in [analytics.ts:54](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L54)*
6566

6667
The number of queued events that the analytics client should flush at. Setting this to `1` will not queue any events and will use more battery.
6768

@@ -74,18 +75,31 @@ ___
7475

7576
**● ios**: *`undefined` \| `object`*
7677

77-
*Defined in [analytics.ts:59](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L59)*
78+
*Defined in [analytics.ts:102](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L102)*
7879

7980
iOS specific settings.
8081

82+
___
83+
<a id="proxy"></a>
84+
85+
### `<Optional>` proxy
86+
87+
**● proxy**: *`undefined` \| `object`*
88+
89+
*Defined in [analytics.ts:72](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L72)*
90+
91+
Whether the analytics client should send all requests through your own hosted proxy rather than directly to Segment. See: iOS: [https://segment.com/docs/connections/sources/catalog/libraries/mobile/ios/#proxy-http-calls](https://segment.com/docs/connections/sources/catalog/libraries/mobile/ios/#proxy-http-calls) android: [https://segment.com/docs/connections/sources/catalog/libraries/mobile/android/#proxy-http-calls](https://segment.com/docs/connections/sources/catalog/libraries/mobile/android/#proxy-http-calls)
92+
93+
Ex. For a desired proxy through `http://localhost:64000/segment` the configuration would look like such { scheme: 'http', host: 'localhost', port: 64000, path: '/segment' }
94+
8195
___
8296
<a id="recordscreenviews"></a>
8397

8498
### `<Optional>` recordScreenViews
8599

86100
**● recordScreenViews**: *`undefined` \| `false` \| `true`*
87101

88-
*Defined in [analytics.ts:19](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L19)*
102+
*Defined in [analytics.ts:19](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L19)*
89103

90104
Whether the analytics client should automatically make a screen call when a view controller is added to a view hierarchy. Because the iOS underlying implementation uses method swizzling, we recommend initializing the analytics client as early as possible.
91105

@@ -98,7 +112,7 @@ ___
98112

99113
**● trackAppLifecycleEvents**: *`undefined` \| `false` \| `true`*
100114

101-
*Defined in [analytics.ts:26](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L26)*
115+
*Defined in [analytics.ts:26](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L26)*
102116

103117
Whether the analytics client should automatically track application lifecycle events, such as "Application Installed", "Application Updated" and "Application Opened".
104118

@@ -111,7 +125,7 @@ ___
111125

112126
**● trackAttributionData**: *`undefined` \| `false` \| `true`*
113127

114-
*Defined in [analytics.ts:32](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L32)*
128+
*Defined in [analytics.ts:32](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L32)*
115129

116130
Whether the analytics client should automatically track attribution data from enabled providers using the mobile service.
117131

@@ -124,7 +138,7 @@ ___
124138

125139
**● using**: *[Integration](../#integration)[]*
126140

127-
*Defined in [analytics.ts:37](https://github.com/segmentio/analytics-react-native/blob/master/packages/core/src/analytics.ts#L37)*
141+
*Defined in [analytics.ts:37](https://github.com/adkenyon/analytics-react-native/blob/master/packages/core/src/analytics.ts#L37)*
128142

129143
Register a set of integrations to be used with this Analytics instance.
130144

packages/core/ios/RNAnalytics/RNAnalytics.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,33 @@ +(void)initialize {
6363
config.enableAdvertisingTracking = [options[@"ios"][@"trackAdvertising"] boolValue];
6464
config.defaultSettings = options[@"defaultProjectSettings"];
6565

66+
if ([options valueForKey:@"proxy"]) {
67+
NSDictionary *proxyOptions = (NSDictionary *)[options valueForKey:@"proxy"];
68+
69+
config.requestFactory = ^(NSURL *url) {
70+
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
71+
72+
if ([proxyOptions valueForKey:@"scheme"]) {
73+
components.scheme = [proxyOptions[@"scheme"] stringValue];
74+
}
75+
76+
if ([proxyOptions valueForKey:@"host"]) {
77+
components.host = [proxyOptions[@"host"] stringValue];
78+
}
79+
80+
if ([proxyOptions valueForKey:@"port"]) {
81+
components.port = [NSNumber numberWithInt:[proxyOptions[@"port"] intValue]];
82+
}
83+
84+
if ([proxyOptions valueForKey:@"path"]) {
85+
components.path = [[proxyOptions[@"path"] stringValue] stringByAppendingString:components.path];
86+
}
87+
88+
NSURL *transformedURL = components.URL;
89+
return [NSMutableURLRequest requestWithURL:transformedURL];
90+
};
91+
}
92+
6693
for(id factory in RNAnalyticsIntegrations) {
6794
[config use:factory];
6895
}

packages/core/src/analytics.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,49 @@ export module Analytics {
5353
*/
5454
flushAt?: number
5555

56+
/**
57+
* Whether the analytics client should send all requests through your own hosted
58+
* proxy rather than directly to Segment.
59+
* See:
60+
* iOS: https://segment.com/docs/connections/sources/catalog/libraries/mobile/ios/#proxy-http-calls
61+
* android: https://segment.com/docs/connections/sources/catalog/libraries/mobile/android/#proxy-http-calls
62+
*
63+
* Ex. For a desired proxy through `http://localhost:64000/segment` the configuration would look like such
64+
* {
65+
* scheme: 'http',
66+
* host: 'localhost',
67+
* port: 64000,
68+
* path: '/segment'
69+
* }
70+
*
71+
*/
72+
proxy?: {
73+
74+
/**
75+
* The proxy scheme, ex: http, https
76+
*
77+
* `https` by default.
78+
*/
79+
scheme?: string,
80+
81+
/**
82+
* The proxy host name, ex: api.segment.io, cdn.segment.io
83+
*
84+
* Note: When using localhost with an Android device or simulator use `adb reverse tcp:<port> tcp:<port>`
85+
*/
86+
host?: string,
87+
88+
/**
89+
* The proxy port number, ex: 80
90+
*/
91+
port?: number,
92+
93+
/**
94+
* The proxy path, ex: /path/to/proxy
95+
*/
96+
path?: string,
97+
},
98+
5699
/**
57100
* iOS specific settings.
58101
*/

0 commit comments

Comments
 (0)