Get handset change events
Prerequisites
Required scope
subscription.handset_details:read
Code
TIP
You can test our APIs without authorization by targetting sandbox.api.wgtwo.com
instead of api.wgtwo.com
and removing any authorization from the request/code sample.
Download proto definitions
curl -sL 'https://github.com/working-group-two/wgtwoapis/blob/master/image.bin?raw=true' -o wgtwo.bin
1
export ACCESS_TOKEN="my_client_access_token"
grpcurl -protoset wgtwo.bin \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '
{
"stream_configuration": {
"regular": {},
"disable_explicit_ack": {}
}
}
' \
api.wgtwo.com:443 \
wgtwo.subscription.v1.SubscriptionEventService/StreamHandsetChangeEvents
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
About stream_configuration
For testing purposes, we include the config:
"stream_configuration": {
"regular": {}, Reading position will not be stored in the server and load is not spread between your clients
"disable_explicit_ack": {} Let events be automatically acked
}
1
2
3
4
2
3
4
By default, load will automatically be spread between all connections using the same OAuth 2.0 client and you will need to reply with a ack once your service has handled the message. This is also what we would recommend for real production usage.
See configuring event streaming for details.
Example result
{
"metadata": {
"timestamp": "2021-09-30T14:27:55.468Z",
"identifier": {
"subscriptionIdentifier": {
"value": "ce78..."
}
},
"ackInfo": {
"value": "Ch5..."
}
},
"handsetChangeEvent": {
"previous": {
"imeiSv": {
"imei": "867...",
"softwareVersion": "64"
}
},
"current": {
"imeiSv": {
"imei": "867...",
"softwareVersion": "65"
}
},
"imsi": {
"value": "Rn..."
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Install dependencies
Maven
<dependency>
<groupId>com.wgtwo.api.v1.grpc</groupId>
<artifactId>subscription</artifactId>
<version>1.10.1</version>
</dependency>
package com.example.handsetchange
import com.wgtwo.api.v1.subscription.SubscriptionEventServiceGrpc
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.AckHandsetChangeEventRequest
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.StreamHandsetChangeEventsRequest
import com.wgtwo.api.v1.subscription.SubscriptionEventsProto.StreamHandsetChangeEventsResponse
import com.wgtwo.auth.BearerTokenCallCredentials
import io.grpc.ManagedChannelBuilder
import io.grpc.StatusRuntimeException
import java.util.concurrent.Executors
private const val MAX_IN_FLIGHT = 10
private val environment = Environment.SANDBOX
private val endpoint = when (environment) {
Environment.SANDBOX -> "sandbox.api.wgtwo.com"
Environment.PRODUCTION -> "api.wgtwo.com"
}
private val channel = ManagedChannelBuilder.forAddress(endpoint, 443).build()
private val stub = SubscriptionEventServiceGrpc.newBlockingStub(channel).apply {
/**
* If you are not using the sandbox, you need to add credentials.
* The BearerTokenCallCredentials class can be found in our auth library.
*/
if (environment == Environment.PRODUCTION) {
this.withCallCredentials(BearerTokenCallCredentials { "MY_CLIENT_ACCESS_TOKEN" })
}
}
private val executor = Executors.newFixedThreadPool(MAX_IN_FLIGHT)
fun main() {
while (!channel.isShutdown) {
try {
subscribe()
} catch (e: StatusRuntimeException) {
println("Got exception: ${e.status} - Reconnecting in 1 second")
Thread.sleep(1000)
}
}
}
private fun subscribe() {
println("Starting subscription")
val request = StreamHandsetChangeEventsRequest.newBuilder().apply {
streamConfigurationBuilder.maxInFlight = MAX_IN_FLIGHT
}.build()
stub.streamHandsetChangeEvents(request).forEach { response ->
// Using an executor to handle up to MAX_IN_FLIGHT messages in parallel
executor.submit {
handleResponse(response)
ack(response)
}
}
}
private fun handleResponse(response: StreamHandsetChangeEventsResponse) {
println("Got response:\n$response")
}
private fun ack(response: StreamHandsetChangeEventsResponse) {
val ackInfo = response.metadata.ackInfo
val request = AckHandsetChangeEventRequest.newBuilder().setAckInfo(ackInfo).build()
stub.ackHandsetChangeEvent(request)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Example result
metadata {
timestamp {
seconds: 1635326429
nanos: 93000000
}
identifier {
subscription_identifier {
value: "dummy:se:0"
}
}
}
handset_change_event {
previous {
imei_sv {
imei: "359237066557492"
software_version: "00"
}
}
current {
imei_sv {
imei: "353752084447134"
software_version: "00"
}
}
imsi {
value: "33"
}
}
# Ack success
metadata {
timestamp {
seconds: 1635326429
nanos: 193000000
}
identifier {
subscription_identifier {
value: "dummy:se:0"
}
}
}
handset_change_event {
previous {
imei_sv {
imei: "353752084447134"
software_version: "00"
}
}
current {
imei_sv {
imei: "355330105977849"
software_version: "00"
}
}
imsi {
value: "33"
}
}
# Ack success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60