How to decode a Gzip Http Response in Flutter? - json

I am new to Flutter. I am making a Network Request and I am getting the correct response, but the data is Gzipped. I have decompressed the same in Swift, but with Flutter, I am unable to do that. Can anyone please help?
Here's what I have tried:
import 'dart:convert';
import 'package:http/http.dart';
import 'package:archive/archive.dart';
import 'package:flutter_app/Constants/constants.dart';
class ServiceHelper {
static final sharedInstance = ServiceHelper();
Future<Response> sendRequest({String path, Map<String,dynamic> params}) async {
final String url = Constants.testURL+path;
var body = jsonEncode(params);
Response response = await post(url, body:body);
final gZipped_data = GZipDecoder().decodeBytes(response.bodyBytes);
print(gZipped_data); //flutter: [123, 34, 115, 116, 97, 116, 117, 115, 34, 58, 50, 48, 48, 44, 34, 109, 101, 115, 115, 97, 103, 101, 34, 58, 34, 83, 105, 103, 110, 32, 105, 110, 32, 67, 111, 109, 112, 108, 101, 116, 101, 100, 32, 83, 117, 99, 99, 101, 115, 115, 102, 117, 108, 108, 121, 34, 44, 34, 100, 97, 116, 97, 34, 58, 123, 34, 117, 115, 101, 114, 95, 105, 110, 102, 111, 34, 58, 123, 34, 112, 108, 97, 121, 101, 114, 95, 105, 100, 34, 58, 49, 52, 56, 54, 57, 44, 34, 112, 108, 95, 97, 112, 112, 95, 105, 100, 34, 58, 34, 57, 90, 104, 57, 82, 66, 108, 70, 34, 44, 34, 112, 114, 111, 102, 105, 108, 101, 95, 112, 105, 99, 34, 58, 34, 104, 116, 116, 112, 115, 58, 92, 47, 92, 47, 119, 119, 119, 46, 115, 112, 111, 114, 116, 115, 113, 119, 105, 122, 122, 46, 99, 111, 109, 92, 47, 118, 51, 92, 47, 105, 109, 103, 92, 47, 112, 108, 97, 121, 101, 114, 115, 92, 47, 112, 105, 99, 92, 47, 105, 80, 45, 49, 53, 50, 51, 56, 54, 57, 50, 57, 56, 46, 112, 110, 103, 34, 44, 34, 101, 109, 97, 105, 108, 34, 58, 34, 116, 101, 99, 104, 121, <…>
//This throws an error: Unhandled Exception: FormatException: Bad UTF-8 encoding 0x8b (at offset 1)
return response;
}
}
//This is the login function and it is in a different file main.dart
Future<void> login(
{String email,
String name,
int source,
String sourceStr,
String picString,
String idToken}) async {
final String playerID = '';
final String token = await getIOSToken().then((token){
return token;
});
Map<String, dynamic> params = {
"email": email,
"name": name,
"player_id": playerID,
"source_id": source,
"profile_pic": picString,
"password": passwordController.text ?? "",
"ios_token":token,
"device_type": "I",
"language_iso": "en",
"referred_by": "loginDefault",
"firebase_id_token": idToken,
"app_version": "4.4.9"
};
Response response = await ServiceHelper.sharedInstance
.sendRequest(path: Constants.login, params: params);
if (response.statusCode == 201) {
// If server returns an OK response, parse the JSON.
return UserDetails.fromJson(json.decode(response.body));
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load post');
}
}
The expected response is JSON, but as it is Gzipped and I am unable to decompress it, I do not know how to get the JSON from it. I have tried decoding it and it gives me gzipped_data as a List of Integers as you can see above. How can I get the JSON from it?

I'm using GZipCodec from dart:io.
Try it like this to return the response as a String.
Future<String> sendRequest({String path, Map<String,dynamic> params}) async {
final String url = Constants.testURL+path;
var body = jsonEncode(params);
Response response = await post(url, body:body);
final decoded_data = GZipCodec().decode(response.bodyBytes);
return utf8.decode(decoded_data, allowMalformed: true);
}

The body of a response will be automatically uncompressed.
Visit https://api.flutter.dev/flutter/dart-io/HttpClient/autoUncompress.html

Related

How to use Service Worker WebPush in Puppeteer headless mode?

I've trying to register service worker web push in puppetter headless mode, here is my code
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch({
// headless: false,
args: [
'--user-data-dir=/tmp/chrome',
'--enable-features=NetworkService,NetworkServiceInProcess,'
],
ignoreHTTPSErrors: true,
});
const page = await browser.newPage();
const domain = 'http://127.0.0.1:3000'
await page.goto(domain);
page.on('console', msg => console.log('PAGE LOG:', msg.text()));
const token = await page.evaluate(async () => {
return await window.navigator.serviceWorker.ready.then(async (serviceWorkerRegistration) => {
// return serviceWorkerRegistration.pushManager.getSubscription()
const registration = await navigator.serviceWorker.getRegistration();
console.log(`getRegistration: ${registration}`);
try {
const subscription = await serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: new Uint8Array([4, 94, 104, 18, 141, 49, 13, 74, 96, 202, 82, 131, 78, 91, 29, 242, 150, 102, 197, 0, 53, 149, 230, 8, 54, 38, 62, 173, 43, 28, 89, 130, 191, 222, 213, 128, 147, 62, 21, 49, 187, 95, 212, 194, 196, 253, 140, 157, 234, 34, 8, 234, 143, 158, 221, 15, 83, 8, 222, 111, 100, 204, 213, 48, 75]),
});
return subscription.toJSON()
} catch (error) {
console.log(`error: ${error}`);
return null
}
})
}).catch(e => {});
console.log(`token: ${JSON.stringify(token)}`);
})();
in non-headless mode, the code is run pretty well
PAGE LOG: getRegistration: [object ServiceWorkerRegistration]
PAGE LOG: JSHandle#object
token: {"endpoint":"https://fcm.googleapis.com/fcm/send/fBqzufyQyzU:APA91bH1kHiKTzciB6KF7GqL4zV5yfeKLnlhAvyZLHRsVcStfqh7nZYbaJ7M0p6eFx24b38v-nFKy4FYFFDJtPiAgTAiaEErQ_2la9Y7S33Ok6J8rCCio5T_gK-wf8QxeF-J87Pjff_N","expirationTime":null,"keys":{"p256dh":"BGjLgRDRBlGcv9HXyg18T-4BQyKErKnzcFJhSNTziBpVHIeuBeNUiIXNjMFBKyQP6oNz9adL3wYBAIPzW106aAY","auth":"nRQCYhw96EOFMKVqoQlp-Q"}}
but if use headless: true, the puppeteer will got a error
PAGE LOG: getRegistration: [object ServiceWorkerRegistration]
PAGE LOG: error: AbortError: Registration failed - push service not available
token: null
how could i solve this problem ?
use Service Worker WebPush in Puppeteer headless mode

HTTPBuilder adds valuecount,strings, bytes into request body and the other side can't parse that JSON

I need to send request with groovy HTTPBuilder, here is code:
String authToken = "token"
def cfManager = ComponentAccessor.getCustomFieldManager()
def addressJira = "http://xxx"
def http = new HTTPBuilder("${address}")
http.setClient(HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build())
try {
http.request(POST, ContentType.JSON) {
headers.'Authorization' = "token ${authToken}"
headers.'Content-Type' = 'application/json'
headers.'cache-control' = 'no-cache'
body = [
"request": [
"token":"${authToken}",
"commonData":[
"taskId":"${issue.id.toString()}"
],
"phonesData":[
"phone":"${cfManager.getCustomFieldObject("customfield_xxx")?.getValue(issue)?.toString()}",
"phoneType": 1
],
"addData": [
"title":"${issue.summary.toString()}",
"description":"${issue.description.toString()}"
]
]
]
requestContentType = ContentType.JSON
response.success = { resp, json ->
log.info("Resp status " + resp.status.toString())
log.info("JSON ${json.toString()}")
log.info("JSON text ${json.text}")
}
response.failure = { resp ->
log.warn("response code is : " + resp.status.toString())
log.warn("response is : " + resp.getEntity().getContent().getText())
}
}
} catch (Exception e) {
log.warn("Exceptiion while request" + e)
}
I get resp code 200 but on the other side they get JSON like this and can't parse it because of "valueCount", "strings" and "bytes":
{
"request": {
"token": {
"valueCount": 1,
"strings": ["", ""],
"bytes": [85, 69, 108, 112, 108, 120, 90, 99, 113, 107, 100, 106, 71, 108, 121, 102, 199, 115, 103, 107, 33, 45, 109, 70, 37, 65, 91, 33, 47, 77, 54, 83, 111, 115, 77, 49, 77, 50, 107, 74, 65, 122],
"values": ["token"]
},
"commonData": {
"taskId": {
"valueCount": 1,
"strings": ["", ""],
"bytes": [48, 49, 55, 56, 56],
"values": ["here is issue id"]
}
},
"phonesData": {
"phone": {
"valueCount": 1,
"strings": ["", ""],
"bytes": [43, 53, 54, 55, 56, 57, 48],
"values": ["+01234567890"]
},
"phoneType": 1
},
"addData": {
"title": {
"valueCount": 1,
"strings": ["", ""],
"bytes": [84, 101, 115, 116],
"values": ["Test"]
},
"description": {
"valueCount": 1,
"strings": ["", ""],
"bytes": [-113, -48, -78, -48, -70, -48, -80, 32, -48, -76, -48, -69, -47, -113, 32, -48, -102, -48, -90, 32, -48, -98, -48, -73, -48, -66, -48, -67, 46],
"values": ["here is issue summary"]
}
}
}
}
So the question is why they get that parameters and what I have to do not to send that "valueCount", "strings" and "bytes"?
Thanks to any help
The serializer in some versions of Camel does not recognise GString type.
Hence, you would need to force conversion to string by calling toString()
def v_stringvar = "${var1} text ${var2}";
And then you use it in this way
v_stringvar?.toString()

Google Apps Script equivalent for JS typed arrays (Uint8Array and Uint16Array)

When I try to run the following code in google apps script
var numArray = [31, -117, 8, 8, -102, -124, 75, 88, 2, 0, 106, 117, 108, 121, 46, 116, 120, 116, 0, 1, 4, 0, -5, -1, 106, 117, 108, 121, -13, -113, 116, -57, 4, 0, 0, 0];
var typedArray = new Uint8Array(numArray);
...I get:
ReferenceError: "Uint8Array" is not defined.
At the same time
var numArray = [31, -117, 8, 8, -102, -124, 75, 88, 2, 0, 106, 117, 108, 121, 46, 116, 120, 116, 0, 1, 4, 0, -5, -1, 106, 117, 108, 121, -13, -113, 116, -57, 4, 0, 0, 0];
var typedArray = new Array(numArray);
...works just fine. Is there a clever workaround way to implement a Uint8Array in google apps script?
OK, so thanks to the comment from #Xepoch, here is the answer to my original question.
The equivalent to
var numArray = [31, -117, 8, 8, -102, -124, 75, 88, 2, 0, 106, 117, 108, 121, 46, 116, 120, 116, 0, 1, 4, 0, -5, -1, 106, 117, 108, 121, -13, -113, 116, -57, 4, 0, 0, 0];
var typedArray = new Uint8Array(numArray);
is (in the absence of Uint8Array):
var numArray = [31, -117, 8, 8, -102, -124, 75, 88, 2, 0, 106, 117, 108, 121, 46, 116, 120, 116, 0, 1, 4, 0, -5, -1, 106, 117, 108, 121, -13, -113, 116, -57, 4, 0, 0, 0];
var typedArray = [];
for(var i=0;i<numArray .length;i++) {
typedArray.push(numArray [i]<0?numArray [i]+256:numArray [i]);
}

Draw line chart using shapes in adobe flex

I want to draw line chart for ECG reading using Shapes component. I want graph exactly like this image.
i finished 90% code. but when i call clear() means all lines cleared.
i want to give some space between two different reading.
My code:
<fx:Script>
<![CDATA[
private var arrSPO2:Array = [33, 35, 36, 33, 28, 21,35, 36, 33, 28, 21, 13, 6,33, 28, 21, 13, 6, 0, 0, 0,28, 21, 13, 6, 0, 0, 0, 0, 0, 10,28, 21, 13, 6, 0, 0, 0, 0, 0, 10, 31, 56, 78,13, 6, 0, 0, 0, 0, 0, 10, 31, 56, 78, 93, 98, 94,6, 0, 0, 0, 0, 0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55,0, 0, 0, 0, 0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41,0, 0, 0, 0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44,0, 0, 0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32,0, 0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32, 24, 15, 7,0, 10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32, 24, 15, 7, 1, 0, 0,10, 31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32, 24, 15, 7, 1, 0, 0, 0, 2, 19,31, 56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32, 24, 15, 7, 1, 0, 0, 0, 2, 19, 43, 68, 90,56, 78, 93, 98, 94, 82, 68, 55, 45, 41, 41, 42, 44, 43, 39, 32, 24, 15, 7, 1, 0];
private var oldX:int = 0;
private var oldY:int = 0;
private var newX:int = 0;
private var newY:int = 0;
private static const TIMER_INTERVAL:int = 50;
private var timer:Timer = new Timer(TIMER_INTERVAL);
private var shapesSPO2:Shape = new Shape();
[Bindable] private var index:int = -1;
protected function init():void {
}
private function timerHandler(event:TimerEvent):void {
trace(timer.currentCount);
index = timer.currentCount - 1;
//draw SPO2
newX += 2;
newY = ((arrSPO2[index] * -1) / 2 + 120);
if (oldY == 0) {
oldY = newY;
}
shapesSPO2.graphics.moveTo(oldX, oldY);
shapesSPO2.graphics.lineTo(newX, newY);
ui1.addChild(shapesSPO2);
oldX = newX;
oldY = newY;
if (index > arrSPO2.length) {
shapesSPO2.graphics.clear();
shapesSPO2.graphics.lineStyle(2, 0x990000, .75);
oldX = newX = 0;
timer.reset();
timer.start();
}
}
protected function btnSPO2_clickHandler(event:MouseEvent):void {
oldX = newX = 0;
shapesSPO2.graphics.lineStyle(2, 0x990000, .75);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.reset();
timer.start();
}
]]>
</fx:Script>
<s:VGroup width="100%" height="100%"
horizontalAlign="center" verticalAlign="middle">
<mx:HBox width="550" height="500"
borderColor="#000000" borderVisible="true" borderStyle="solid" borderAlpha="0.2"
visible="true" includeInLayout="true">
<s:VGroup id="vgGraph" width="100%" height="100%"
horizontalAlign="center"
gap="10"
padding="10">
<s:HGroup width="100%">
<s:Label text="Current Index : {index}" fontSize="16"
fontWeight="bold" />
</s:HGroup>
<mx:UIComponent id="ui1" width="100%" height="100%" />
<!--<s:SpriteVisualElement id="spriteVis" width="100%" height="100%" />-->
<s:Button id="btnSPO2" label="Draw SPO2 Graph" click="btnSPO2_clickHandler(event)" />
</s:VGroup>
</mx:HBox>
</s:VGroup>
To do that you can change your code like this :
private const margin:int = 10;
private function timerHandler(event:TimerEvent):void {
if (index == arrSPO2.length - 1) {
// set the margin between the last chart and the new one
newX = newX + margin;
oldX = newX;
// reset index
index = 0;
timer.reset();
timer.start();
// exit if we have reached the last element of our array
return;
}
index = timer.currentCount - 1;
newX += 2;
newY = ((arrSPO2[index] * -1) / 2 + 120);
if (oldY == 0) {
oldY = newY;
}
shapesSPO2.graphics.moveTo(oldX, oldY);
shapesSPO2.graphics.lineTo(newX, newY);
ui1.addChild(shapesSPO2);
oldX = newX;
oldY = newY;
}
Which will give you something like this :
Hope that can help.
I've modified your timerHandler as below:
private function timerHandler(event:TimerEvent):void {
trace(timer.currentCount);
index = timer.currentCount - 1;
if (index > arrSPO2.length) {
//shapesSPO2.graphics.clear();
//shapesSPO2.graphics.lineStyle(2, 0x990000, .75);
newX += 10;
oldX = newX;
timer.reset();
timer.start();
return;
}
//draw SPO2
newX += 2;
if(newX > ui1.width)
{
oldX = newX = 0;
}
newY = ((arrSPO2[index] * -1) / 2 + 120);
if (oldY == 0) {
oldY = newY;
}
if(index ==0)
{
oldY = newY;
}
shapesSPO2.graphics.moveTo(oldX, oldY);
shapesSPO2.graphics.lineTo(newX, newY);
ui1.addChild(shapesSPO2);
oldX = newX;
oldY = newY;
}

Reading numeric keys from JSON file

Let's say I store a dictionary's values in JSON file. Here is the simplified code:
test = {}
for i in range(10):
for j in range(15):
test['{},{}'.format(i, j)] = i * j
with open('file1.json', 'w') as f:
json.dump(test, f)
I have hard time reading back from this file. How can I read back from this file into a dictionary with elements like key as [i,j] and value as i*j?
I use simple
with open('file1.json', 'r') as f:
data2 = json.load(f)
Do you mean something like this?
with open('file1.json', 'r') as f:
data2 = {tuple(int(x) for x in k.split(',')): v
for (k, v) in json.load(f).items()}
Your code will returns a dictionary contain unicode key and values if you want to get a dictionary contains the integer values you can use json.dumps after loading the file :
import json
test = {}
for i in range(10):
for j in range(15):
test['{},{}'.format(i, j)] = i * j
with open('file1.json', 'w') as f:
json.dump(test, f)
with open('file1.json', 'r') as f:
data2 = json.load(f)
print json.dumps(data2)
result :
{"1,8": 8, "1,9": 9, "1,6": 6, "1,7": 7, "1,4": 4, "1,5": 5, "1,2": 2, "1,3": 3, "1,0": 0, "1,1": 1, "7,6": 42, "7,7": 49, "5,8": 40, "5,9": 45, "3,8": 24, "3,9": 27, "5,2": 10, "5,3": 15, "5,0": 0, "3,7": 21, "3,0": 0, "5,7": 35, "3,2": 6, "3,3": 9, "3,14": 42, "3,12": 36, "3,13": 39, "3,10": 30, "3,11": 33, "2,8": 16, "5,14": 70, "5,10": 50, "5,11": 55, "5,12": 60, "5,13": 65, "0,8": 0, "4,8": 32, "0,13": 0, "0,12": 0, "0,11": 0, "0,10": 0, "0,14": 0, "6,9": 54, "6,8": 48, "6,1": 6, "6,0": 0, "6,3": 18, "6,2": 12, "6,5": 30, "6,4": 24, "6,7": 42, "6,6": 36, "6,14": 84, "6,11": 66, "6,10": 60, "6,13": 78, "6,12": 72, "8,9": 72, "8,8": 64, "8,7": 56, "8,6": 48, "8,5": 40, "8,4": 32, "8,3": 24, "8,2": 16, "8,1": 8, "8,0": 0, "5,1": 5, "2,13": 26, "3,4": 12, "3,5": 15, "3,6": 18, "0,7": 0, "0,6": 0, "0,5": 0, "0,4": 0, "0,3": 0, "0,2": 0, "0,1": 0, "0,0": 0, "5,6": 30, "0,9": 0, "3,1": 3, "1,10": 10, "1,11": 11, "1,12": 12, "1,13": 13, "2,9": 18, "5,4": 20, "2,5": 10, "2,4": 8, "2,7": 14, "2,6": 12, "2,1": 2, "2,0": 0, "2,3": 6, "2,2": 4, "4,3": 12, "4,2": 8, "4,1": 4, "4,0": 0, "4,7": 28, "4,6": 24, "4,5": 20, "4,4": 16, "2,11": 22, "2,10": 20, "4,9": 36, "2,12": 24, "2,14": 28, "1,14": 14, "5,5": 25, "8,13": 104, "8,12": 96, "8,11": 88, "8,10": 80, "8,14": 112, "7,12": 84, "7,13": 91, "7,10": 70, "7,11": 77, "7,14": 98, "4,14": 56, "4,13": 52, "4,12": 48, "4,11": 44, "4,10": 40, "7,8": 56, "7,9": 63, "9,4": 36, "9,5": 45, "9,2": 18, "9,3": 27, "9,0": 0, "9,1": 9, "7,0": 0, "7,1": 7, "7,2": 14, "7,3": 21, "7,4": 28, "7,5": 35, "9,8": 72, "9,9": 81, "9,6": 54, "9,7": 63, "9,10": 90, "9,11": 99, "9,12": 108, "9,13": 117, "9,14": 126}