Firestore taking too much time to update from flutter app - flutter

I want to update a field of a particular document in firestore while listening to any change in its value. So basically, when the field 'call' is found to be 1, we will update it again back to 0 after printing a message. However, it takes too much time to update. On the other hand, updating the same field using python is way quicker. Please advise me what should be done.
FirebaseFirestore.instance
.collection('joystick')
.snapshots()
.listen((QuerySnapshot querySnapshot) {
var firestoreList = querySnapshot.docs;
var data = firestoreList.first.data();
var callval = firestoreList.first.get('call');
print("call value while listening ${callval}");
if(callval == 1){
print("call value is 1 ");
//makecall();
FirebaseFirestore.instance.collection('joystick').doc('data').update({'call':0});
call = firestoreList.first.get('call');
print("Next call value is ${call}");
if(call == 0){
print("updated!");
callval = 0;
}
}
}).onError((e) => print(e));

Document writing takes as long as it takes and depends on network connection speed. But you can speed up uploading data by compressing them. Dart has a useful tool as GZip. GZip can compress String data up to 99% You can decode/encode data in many ways even HttpClient can autoUncompress it :).
import 'dart:io';
// Send compressed data.
Future<void> sendCompressed() async {
final gzip = GZipCodec();
// You can convert any data to JSON string with `dart:convert`.
const String jsonToSend = '{"field": "Some JSON to send to the server."}';
// Original Data.
final List<int> original = utf8.encode(jsonToSend);
// Compress data.
final List<int> compressed = gzip.encode(original);
// Send compressed to db.
print(compressed);
}
// Get compressed data.
Future<void> getCompressed() async {
final gzip = GZipCodec();
// Get compressed data from the data base.
final List<int> compressed = await http.get('https://data.com');
// Decompress
final List<int> decompress = gzip.decode(compressed);
// Decode back to String (JSON)
final String decoded = utf8.decode(decompress);
// Do what you want with decoded data.
print(decoded);
}

Related

Convert raw http POST to data, write to file in Flutter

I'm running a web server instance in my Flutter app in order to run an image conversion tool, written in JavaScript. The JS code sends a POST command along with a body which contains the raw image data.
Using httpServer and VirtualDirectory, I'm serving all of the required files if JS calls GET, and now when it calls the POST command, I need to convert the POST request to raw data and save it to a file, as it contains the image data I need.
The current web server logic is written in Python. It uses rfile.read in order to write the data from the request into a file.
contentLength = int(self.headers['Content-Length'])
open("output_files/output.%03d.jpg"%frame,"wb").write(self.rfile.read(contentLength))
This is what I'm trying to recreate in Flutter. Here's my code so far.
_startServer({required String basePath}) async {
var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
virDir = VirtualDirectory('$tempDir/converter/')
..allowDirectoryListing = true;
debugPrint(
"Server running on IP : ${server.address} On Port : ${server.port}");
await for (var request in server) {
switch (request.method) {
case 'GET':
String path = request.uri.toString();
if (!path.contains(basePath)) {
path = basePath + request.uri.toString();
}
debugPrint('request uri: $path');
final File file = File(path);
if (await file.exists()) {
request.response.statusCode = HttpStatus.ok;
virDir?.serveFile(file, request);
} else {
debugPrint('Could not find: $file');
request.response.statusCode = HttpStatus.notFound;
}
break;
case 'POST':
debugPrint('Content Length: ${request.headers.contentLength}');
debugPrint('Content Type: ${request.headers.contentType}');
final File image =
File('$basePath/videos/frame.${intFixed(frame, 3)}.jpg');
if (!image.existsSync()) {
request.response.statusCode = HttpStatus.ok;
request.response.write('Finished');
request.response.headers.contentType = ContentType.text;
request.response.headers.contentLength = 'Finished'.length;
await request.response.close();
return;
}
final File newImage =
File('$basePath/output_files/output.${intFixed(frame, 3)}.jpg');
ByteData data = ByteData(request.headers.contentLength);
final buffer = data.buffer;
await newImage.writeAsBytes(
buffer.asUint8List(0, request.headers.contentLength));
frame++;
debugPrint('$frame');
request.response.statusCode = HttpStatus.ok;
request.response.headers.contentType = ContentType.text;
request.response.headers.contentLength = "Success".length;
request.response.write("Success");
await request.response.close();
}
}
}
Specifically, this part:
ByteData data = ByteData(request.headers.contentLength);
final buffer = data.buffer;
await newImage.writeAsBytes(
buffer.asUint8List(0, request.headers.contentLength));
When I set a breakpoint and check data, there's no data per-se. Just a list of zeros.
How do I convert the POST request to raw in order to save it to a file? The content length and the content type is correct (image/jpeg), but getting it to data is really stumping me.
After a lot of trial and error, the solution is to use await request.single which outputs a Uint8List, then write that to file as it's a stream of the HTTPRequest object itself.
https://api.flutter.dev/flutter/dart-async/Stream/single.html
final data = await request.single;
final file = File('$basePath/output_files/output.${intFixed(frame, 3)}.jpg');
file.writeAsBytesSync(data);

Upload CSV file Flutter Web

I am using the file_picker plugin to pick a CSV file in Flutter Web. Although I am able to pick the file it is converting the file into bytes (Uint8List). Is there any way I can get the original CSV file or if I can convert these bytes to CSV maybe I can get the path of the file?
Code:
void pickCSV() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.custom, allowedExtensions: ['csv']);
if (result != null) {
var fileBytes = result.files.first.bytes;
csfFileName.value = result.files.first.name;
} else {
// User canceled the picker
}
}
I know it's a bit late but you have a couple of choices and maybe it helps others out aswell.
Both of the choices requires server-side processing, so you will need to read on how to do that.
Get the content of the CSV file send it to the server and make a new file on the server with that content. You can use String.fromCharCodes to read the content, in the web, after you select the file.
Convert the Uint8List into a base64 string, using base64Encode function, send it to the server, process it there.
Alternatively, if you use Firebase Storage you can use putData like so:
final metaData = SettableMetadata(contentType: mimeType);
final task = await _storage.ref().child(cloudPath).putData(fileData, metaData);
/// Get the URL
await task.ref.getDownloadURL()
Storing the mimeType ensures proper handling of the file when used after download
cloudPath means the location in FirebaseStorage, such as: storageDirectory/filename.extension
fileData is the Uint8List you provided

How to retrieve/decode json/map from downloaded ByteStream?

I have a ByteStream downloaded from a Server, namely datas regarding the user.
Its in MySql server as
"username":"Neor","totalCoins":"350"
The truncated part of .php file that gives-away this data, is as follows:
$data = $stmt->fetchColumn();
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public");
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-Length:".strlen($data));
echo $data;
I use ths Flutter code to download the data:
Future<void> downloadData() async {
var url = Uri.parse("https://example.com/mycloud.php");
var request = http.MultipartRequest('POST', url)
..fields["user"] = "Dia";
var response = await request.send();
var stream = response.stream; }
On checking if the downloaded ByteStream contains anything, I've used print(stream.length), which prints out as 137.
How can I get the information I want from the ByteStream?
(If my question lacks in any way, please let me know.)
There shouldn't be any need to use a multipart request for a simple POST. Instead use the simpler http.post method.
Future<void> downloadData() async {
final response = await http.post(
Uri.parse('https://example.com/mycloud.php'),
body: <String, String>{
'user': 'Dia',
},
);
final decodedJson = json.decode(response.body);
// if you want to ensure the character set used, replace this with:
// json.decode(utf8.decode(response.bodyBytes));
}
If you do stick with the stream way, you have a Stream<List<int>> that you want to turn initially into a List<int>. Use the toList() method on stream for that. Then you have to decode that into characters. JSON is always encoded in utf8, so you could:
json.decode(utf8.decode(await stream.toList()));
(Under the hood, http is basically doing that for you; collecting the stream together and doing the character decoding and presenting that as body.)
First
import 'dart:convert' show utf8;
String foo = utf8.decode(bytes);
Then
Map valueMap = json.decode(foo );

How to save and retrieve a List<Map> with Get Storage

I am trying to persist a simple List<Map<String,dynamic>> with GetStorage.
The documentation says:
When to use GetStorage:
simple Maps storage.
cache of http requests
storage of simple user information.
simple and persistent state
storage any situation you currently use sharedPreferences.
So, I did not encoded/decoded to json String.
In the end, getting error
type 'List<dynamic>' is not a subtype of type 'List<Map<String, dynamic>>?' in type cast
Here is my code, and error is thrown at box.read() method:
final box = GetStorage();
var payments = <Payment>[].obs;
Future<void> savePaymentsToDB() async {
var paymentsAsMap = payments.map((payment) => payment.toJson()).toList();
await box.write('payments', paymentsAsMap);
}
void getPaymentsFromDB() {
var result = box.read<List<Map<String, dynamic>>>('payments');
if (result != null) {
payments =
result.map((payment) => Payment.fromJson(payment)).toList().obs;
}
}
You need to encode paymentsAsMap to json string. The toJson method on your model, only coverts that model to json object (key,value pair). To store that in shared preferences or getStorage you should convert that json object to string.
import 'dart:covert';
// Storing data
...
var paymentsAsMap = payments.map((payment) => payment.toJson()).toList();
String jsonString = jsonEncode(paymentsAsMap);
await box.write('payments', jsonString);
// fetching data
var result = box.read('payments');
dynamic jsonData = jsonDecode(result);
payments = jsonData.map((payment) => Payment.fromJson(payment)).toList().obs;

How do I capture an endless network stream and filter out metadata in dart?

I'm writing an app for a radio station in Germany and I want to get the audio stream title informations from their Icecast server. How do I receive the audio stream in Flutter/Dart and filter out the audio metadata for displaying the song name?
I've already got the code for getting the icy-metaint number, needed to count the bytes (mp3 audio data) up to the byte showing how long the metadata string is. (In my case, it's 16000)
My code for getting the icy-metaint integer:
Future<Map> getInfoDataFromIceCastStream(String url) async {
var request = http.Request('GET', Uri.parse(url));
request.headers['Icy-MetaData'] = '1';
var response = await request.send();
var headers = response.headers;
return headers;
}
Future<int> getIcyMetaInt(String url) async {
Map metaData = await getInfoDataFromIceCastStream(url);
print(metaData['icy-metaint']);
return int.parse(metaData['icy-metaint']);
}
In the end, I expect to get a string like:
StreamTitle='Gong 96.3 - Mark Forster - Chöre';StreamUrl='';