Flutter + AWS: It always gives broken pipe error - amazon-web-services

I'm trying to compare faces with AWS rekognition API. but somehow I'm getting "broken pipe" error all the time. There is no problem on aws keys and photos. I'm trying to get more info from http.post but It just says "broken pipe", it doesn't give any detail, unfortunately.
Scenario;
User takes 2 photos (working)
on second taken, I will parse images to bytes (working)
send bytes with standard request to aws API (doesn't work)
I changed the image quality to the lowest as well, but It didn't help.
Main.dart code
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'testa.dart';
import 'package:path_provider/path_provider.dart';
List<CameraDescription> cameras;
Future<void> main() async {
cameras = await availableCameras();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
CameraController controller;
#override
void initState() {
super.initState();
controller = CameraController(cameras[0], ResolutionPreset.low);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
Future<String> _checkImage(String filePath, String secondPath) async {
File sourceImagefile, targetImagefile; //load source and target images in those File objects
String accessKey, secretKey, region ; //load your aws account info in those variables
print(filePath);
print(secondPath);
targetImagefile = File(filePath);
sourceImagefile = File(secondPath);
print(targetImagefile.existsSync());
print(sourceImagefile.existsSync());
accessKey = '';
secretKey = '';
region = 'eu-west-1';
RekognitionHandler rekognition = new RekognitionHandler(accessKey, secretKey, region);
String labelsArray = await rekognition.compareFaces(sourceImagefile, targetImagefile);
return labelsArray;
}
Widget cameraPart() {
if (!controller.value.isInitialized) {
return Container();
}
return AspectRatio(
aspectRatio:
controller.value.aspectRatio,
child: CameraPreview(controller));
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: cameraPart(),
floatingActionButton: FloatingActionButton(
onPressed: takePhoto,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Future<String> get360PhotoFolder() async {
final Directory appFolder = await getAppFolder();
final String dirPath = '${appFolder.path}/photos360';
await Directory(dirPath).create(recursive: true);
return dirPath;
}
String firstPath = '';
String secondPath = '';
Future<bool> takePhoto() async {
final String dirPath = await get360PhotoFolder();
final String filePath = '$dirPath/${timestamp()}_test.jpg';
try {
debugPrint('photo taken - $filePath');
await controller.takePicture(filePath);
setState(() {
if (firstPath == '') {
print('a');
firstPath = filePath;
}else if (secondPath == '') {
print('b');
secondPath = filePath;
_checkImage(firstPath, secondPath).then((value) {
print(value);
}).catchError((error) {
print(error);
});
firstPath = '';
secondPath = '';
}
});
} on CameraException catch (e) {
print([e.code, e.description]);
return true;
}
return false;
}
String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();
Future<Directory> getAppFolder() async =>
await getApplicationDocumentsDirectory();
}
AWS rekognition code
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:intl/intl.dart';
import 'testb.dart';
class RekognitionHandler {
final String _accessKey, _secretKey, _region;
RekognitionHandler(this._accessKey, this._secretKey, this._region);
Future<String> _rekognitionHttp(String amzTarget, String body) async {
String endpoint = "https://rekognition.$_region.amazonaws.com/";
String host = "rekognition.$_region.amazonaws.com";
String httpMethod = "POST";
String service = "rekognition";
var now = new DateTime.now().toUtc();
var amzFormatter = new DateFormat("yyyyMMdd'T'HHmmss'Z'");
String amzDate =
amzFormatter.format(now); // format should be '20170104T233405Z"
var dateFormatter = new DateFormat('yyyyMMdd');
String dateStamp = dateFormatter.format(
now); // Date w/o time, used in credential scope. format should be "20170104"
int bodyLength = body.length;
String queryStringParamters = "";
Map<String, String> headerParamters = {
"content-length": bodyLength.toString(),
"content-type": "application/x-amz-json-1.1",
"host": host,
"x-amz-date": amzDate,
"x-amz-target": amzTarget
};
String signature = Signature.generateSignature(
endpoint,
service,
_region,
_secretKey,
httpMethod,
now,
queryStringParamters,
headerParamters,
body);
String authorization =
"AWS4-HMAC-SHA256 Credential=$_accessKey/$dateStamp/$_region/$service/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-amz-target, Signature=$signature";
headerParamters.putIfAbsent('Authorization', () => authorization);
//String labelsArray = "";
StringBuffer builder = new StringBuffer();
try {
HttpClient httpClient = new HttpClient();
httpClient.connectionTimeout = Duration(minutes: 10);
HttpClientRequest request = await httpClient.postUrl(Uri.parse(endpoint));
request.headers.set('content-length', headerParamters['content-length']);
request.headers.set('content-type', headerParamters['content-type']);
request.headers.set('host', headerParamters['host']);
request.headers.set('x-amz-date', headerParamters['x-amz-date']);
request.headers.set('x-amz-target', headerParamters['x-amz-target']);
request.headers.set('Authorization', headerParamters['Authorization']);
request.write(body);
HttpClientResponse response = await request.close();
await for (String a in response.transform(utf8.decoder)) {
builder.write(a);
}
} catch (e) {
print(e);
}
return Future.value(builder.toString());
}
Future<String> compareFaces(
File sourceImagefile, File targetImagefile) async {
try {
List<int> sourceImageBytes = sourceImagefile.readAsBytesSync();
String base64SourceImage = base64Encode(sourceImageBytes);
List<int> targetImageBytes = targetImagefile.readAsBytesSync();
String base64TargetImage = base64Encode(targetImageBytes);
String body =
'{"SourceImage":{"Bytes": "$base64SourceImage"},"TargetImage":{"Bytes": "$base64TargetImage"}}';
String amzTarget = "RekognitionService.CompareFaces";
String response = await _rekognitionHttp(amzTarget, body);
return response;
} catch (e) {
print(e);
return "{}";
}
}
}

Related

Error: A value of type 'List<String>' can't be assigned to a variable of type 'List<ChartData>', trying to create a Chart with a list of Strings,

I'm trying to create a graph and i don't know how to set values on this graph (I know how to set the values manually but i created a field in firestore that receives the value of x and y of the graph when you click on a button ), i'm using SyncFusion Flutter Chart (if you have any another idea to solve my problem feel free to say) and i'm trying to add the values ( String ) to the list and for that i Created in firestore when you click on the button (ChartData(x,y)) so all i need is add this string to the list of type ChartData, and for that i'm trying to use decode and split but now returned this error and i don't know how to solve. i'm sorry for the long text.
List<ChartData> convert(String input) {
List<ChartData> output;
try {
output = json.decode(input);
return output;
} catch (err) {
print('The input is not a string representation of a list');
return [ChartData(0, 0)];
}
}
List<ChartData> testim = testefinal.split(',');
final List<ChartData> list1 = convert(testefinal);
final List<ChartData> chartData = list1;
Error: A value of type 'List<String>' can't be assigned to a variable of type 'List<ChartData>'.
Full Code:
import 'dart:convert';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:mood3/telas/animacao.dart';
import 'package:ntp/ntp.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import '../model/GraphMood.dart';
class Graph extends StatefulWidget {
#override
State<Graph> createState() => _GraphState();
}
class _GraphState extends State<Graph> {
TooltipBehavior? _tooltipBehavior;
DateTime ntpTime = DateTime.now();
String testefinal = '';
_loadNTPTime() async {
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseFirestore db = FirebaseFirestore.instance;
setState(() async {
ntpTime = await NTP.now();
});
}
Future _recuperarNome() async {
FirebaseAuth auth2 = FirebaseAuth.instance;
User? user = auth2.currentUser;
DocumentSnapshot ds = await db.collection('usuarios')
.doc(user!.uid)
.get();
Map<String, dynamic> dss = ds.data() as Map<String, dynamic>;
setState((){
testefinal = dss["moodGraph"];
});
print(testefinal);
}
FirebaseFirestore db = FirebaseFirestore.instance;
#override
initState(){
_recuperarNome();
_tooltipBehavior = TooltipBehavior(enable: true);
super.initState();
_loadNTPTime();
}
#override
Widget build(BuildContext context) {
List<ChartData> convert(String input) {
List<ChartData> output;
try {
output = json.decode(input);
return output;
} catch (err) {
print('The input is not a string representation of a list');
return [ChartData(0, 0)];
}
}
List<ChartData> testim = testefinal.split(',');
final List<ChartData> list1 = convert(testefinal);
final List<ChartData> chartData = list1;
return Scaffold(
body: Center(
child: Container(
child: SfCartesianChart(
primaryXAxis: CategoryAxis(),
// Chart title
title: ChartTitle(text: 'Mood Chart'),
// Enable legend
legend: Legend(isVisible: true),
// Enable tooltip
tooltipBehavior: _tooltipBehavior,
series: <ChartSeries>[
// Renders line chart
LineSeries<ChartData, int>(
dataSource: chartData,
xValueMapper: (ChartData data, _) => data.x.toInt(),
yValueMapper: (ChartData data, _) => data.y
)
]
)
)
)
);
}
}
class ChartData {
ChartData(this.x, this.y);
final double x;
final double y;
}
I think, output = json.decode(input) as List();

item not removed in list when use list.remove(element) in flutter

I am having trouble removing an item in a list after adding the element.
List<CartItem> _items = [];
FirebaseFirestore? _instance;
void add(BuildContext context, CartItem item) {
_items.add(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
_items.forEach((CartItem item) {
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
});
_instance = FirebaseFirestore.instance;
_instance!
.collection('cart')
.doc(authService.getCurrentUser()) //need to get logged in account's id
.update({
'cartProduct': FieldValue.arrayUnion([cartMap])
}).then((value) {
print(_items.length);
notifyListeners();
});
}
void remove(BuildContext context, CartItem item) {
_items.remove(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
_instance = FirebaseFirestore.instance;
_instance!.collection('cart').doc(authService.getCurrentUser()).update({
'cartProduct': FieldValue.arrayRemove([cartMap]),
}).then((value) {
print(_items.length);
notifyListeners();
});
}
After I do add(context, widget.product) and print _items.length, the result is 1
However, after I do remove(context, widget.product) and print _items.length, the result is still 1.
Consumer<CartService>(
builder: (context, cart, child) {
Widget renderedButton;
if (cart.isProductAddedToCart(widget.product) == false) {
renderedButton = DefaultButton(
text: "Participate",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.add(context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
} else {
renderedButton = DefaultButton(
text: "Delete",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.remove(
context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
}
return renderedButton;
As in the code above, the remove() method is supposed to remove the same item that was added to the list using the add() method.
Just update the remove() to: (only change _items.remove(item); position)
void remove(BuildContext context, CartItem item) {
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
_instance = FirebaseFirestore.instance;
_instance!.collection('cart').doc(authService.getCurrentUser()).update({
'cartProduct': FieldValue.arrayRemove([cartMap]),
}).then((value) {
/// todo check firebase collection's deletion success first
_items.remove(item);
print(_items.length);
notifyListeners();
});
}
The item you're adding to the list may not be the same instance of the item you're removing. Make sure the item object/class have equality and hashcode implementation to compare the two items properly.
If you don't have control over the object, the following approach can be an easier alternative:
_items.removeWhere((_item) => _item.property == item.property);
^ where property can be the id of the product.

How to mock 'FirebaseAuth.instance'?

I want to start writing unit test to my flutter app that have developed using GetX pattern. In GetX pattern, the code is separated to controller and view, so all methods that I want to test is in controller.
In my app, I am using firebase to make authentication with mobile number.
This is LoginController:
class LoginController extends GetxService {
...
LoginController(this.authService);
final _auth = FirebaseAuth.instance;
String validatePhoneNumber(String phoneNumber) {
if (!phoneNumber.startsWith('+20')) {
return 'أدخل كود البلد مثل: +20 في مصر';
} else if (phoneNumber.length < 11) {
return 'أدخل رقم صحيح';
} else if (phoneNumber.isEmpty) {
return 'أدخل رقم الهاتف';
}
return null;
}
Future<void> validate() async {
await _auth.verifyPhoneNumber(
phoneNumber: phoneNumberController.text,
timeout: timeoutDuration,
codeAutoRetrievalTimeout: (String verificationId) {
verId.value = verificationId;
currentState.value = SignInPhoneWidgetState.CodeAutoRetrievalTimeout;
},
codeSent: (String verificationId, [int forceResendingToken]) {
verId.value = verificationId;
currentState.value = SignInPhoneWidgetState.CodeSent;
DialogService.to.stopLoading();
Get.toNamed(Routes.ACCEPT_SMS);
},
verificationCompleted: (AuthCredential phoneAuthCredential) async {
currentState.value = SignInPhoneWidgetState.Complete;
try {
if (authService.currentUser.value != null) {
await authService.currentUser.value
.linkWithCredential(phoneAuthCredential);
} else {
await _auth.signInWithCredential(phoneAuthCredential);
}
Get.offAllNamed(Routes.ROOTHOME);
//widget.onLoggedIn(authResult);
} on PlatformException catch (e) {
print(e);
errorCode.value = e.code;
errorMessage.value = e.message;
} catch (e) {
print(e);
} finally {
//.......
}
},
verificationFailed: (FirebaseAuthException error) {
errorCode.value = error.code;
errorMessage.value = error.message;
currentState.value = SignInPhoneWidgetState.Failed;
},
//forceResendingToken:
);
}
Future<void> validateSmsCode() async {
//_auth.
var cred = PhoneAuthProvider.credential(
verificationId: verId.value, smsCode: verifyCodeController.text);
try {
if (authService.currentUser.value != null) {
await authService.currentUser.value.linkWithCredential(cred);
} else {
await _auth.signInWithCredential(cred);
await Get.offAllNamed(Routes.ROOTHOME);
}
} on PlatformException catch (ex) {
errorCode.value = ex.code;
errorMessage.value = ex.message;
currentState.value = SignInPhoneWidgetState.Failed;
} on FirebaseAuthException catch (ex) {
errorCode.value = ex.code;
errorMessage.value = ex.message;
currentState.value = SignInPhoneWidgetState.Failed;
}
}
...
}
This is login_test.dart file:
I should mock every outside operation like firebase. But In this case I want to test validatePhoneNumber method, that checks if the phone number is valid or not. the method it self hasn't firebase operations. But, the method is called by a LoginController object, And this object it self has instance of FirebaseAuth.instance.
final _authSerive = AuthService();
main() async {
final loginController = LoginController(_authSerive);
setUp(() async {});
tearDown(() {});
group('Phone Validation', () {
test('Valid Email', () {
String result = loginController.validatePhoneNumber('+201001234567');
expect(result, null);
});
});
}
When I tried to run this test method, This error appeared.
Failed to load "D:\bdaya\ta7t-elbeet-client\test\login_test.dart":
[core/no-app] No Firebase App '[DEFAULT]' has been created - call
Firebase.initializeApp()
The reasen is:
This line in The LoginController:
final _auth = FirebaseAuth.instance;
I certainly know that I have to mock Firebase operations.
How to mock it in this case or, What should I do?

Facebook Black Screen When Signing In

I am trying to use the flutter_facebook_login and every time I click the button associated with the method I get a dimmed screen but, no facebook log in page.
I have updated to the latest version of the dependency and not sure where is the issue.
dependencies:
flutter_facebook_login: ^2.0.0
http: ^0.12.0+2
json_annotation: ^2.0.0
void initiateFacebookLogin() async {
var facebookLogin = FacebookLogin();
var facebookLoginResult = await facebookLogin
.logInWithReadPermissions(['email', 'public_profile']);
switch (facebookLoginResult.status) {
case FacebookLoginStatus.error:
print("Error");
onLoginStatusChanged(false);
break;
case FacebookLoginStatus.cancelledByUser:
print("CancelledByUser");
onLoginStatusChanged(false);
break;
case FacebookLoginStatus.loggedIn:
final token = facebookLoginResult.accessToken.token;
_token = token;
// final graphResponse = await http.get(
// 'https://graph.facebook.com/v2.12/me?fields=name,first_name,last_name,email&access_token=$token');
// final profile = jsonDecode(graphResponse.body);
// print(profile);
print(_token);
break;
}
}
void userLogin(String token) {
String grantType = '';
String clientId = '';
String clientSecret = '';
String backend = '';
String userType = '';
final Map<String, dynamic> logIn = {
'convert_token': grantType,
'fLdfosdlfaisodfjaosdnaiscalsfa': clientId,
'sdfasfasfererwa':
clientSecret,
'facebook': backend,
_token: token,
'customer': userType,
};
http
.post('http://localhost:127.0.0.1/api/social/convert-token/',
body: json.encode(logIn))
.then((http.Response response) {
final Map<String, dynamic> responseData = json.decode(response.body);
print(responseData);
});
}
void backendToken() {
setState(() {
String token;
print(token);
});
}
bool isLoggedIn = false;
void onLoginStatusChanged(bool isLoggedIn) {
setState(() {
this.isLoggedIn = isLoggedIn;
print('User is logged in');
userLogin(_token);
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => NavigationPage()));
});
}
I want to sign into facebook when the function initiateFacebookLogin is called.

My async call is returning before list is populated in forEach loop

I have a routine which gets a list of filenames from the device, then reads the file(s) to build a list. However, the calling routine always returns with zero items. I print the filenames, so I know they exist, however, it appears that the async is returning before I read the files. I used similar code when making an HTTP call. But, something here is causing the routine to return the list even though it hasn't completed. Perhaps, it is possible that I am calling it at the wrong time? I am calling retrieveItems here:
#override
void initState() {
super.initState();
retrieveItems();
}
Eventually I will have a refresh button, but for now I'd simply like the list to populate with the data from the files...
--------------------
Callee
Future<List<String>> readHeaderData() async {
List<String> l = new List();
List<String> files = await readHeaders(); // Gets filenames
files.forEach((filename) async {
final file = await File(filename);
String contents = await file.readAsString();
User usr = User.fromJson(json.decode(contents));
String name = usr.NameLast + ", " + usr.NameFirst;
print(name);
l.add(name);
}
return l;
Caller
void retrieveItems() async {
LocalStorage storage = new LocalStorage();
await storage.readHeaderData().then((item) {
try {
if ((item != null ) &&(item.length >= 1)) {
setState(() {
users.clear();
_users.addAll(item);
});
} else {
setState(() {
_users.clear();
final snackbar = new SnackBar(
content: new Text('No users found.'),
);
scaffoldKey.currentState.showSnackBar(snackbar);
});
}
} on FileNotFoundException catch (e) {
print(e.toString()); //For debug only
setState(() {
_users.clear();
});
});
}
});
This code
Future<List<String>> readHeaderData() async {
List<String> l = new List();
List<String> files = await readHeaders(); // Gets filenames
files.forEach((filename) async {
final file = await File(filename);
String contents = await file.readAsString();
User user = User.fromJson(json.decode(contents));
String name = user.NameLast + ", " + user.NameFirst;
print(name);
l.add(name);
}
return l;
}
returns the list l and then processes the asyc forEach(...) callbacks
If you change it to
Future<List<String>> readHeaderData() async {
List<String> l = new List();
List<String> files = await readHeaders(); // Gets filenames
for(var filename in files) { /// <<<<==== changed line
final file = await File(filename);
String contents = await file.readAsString();
User user = User.fromJson(json.decode(contents));
String name = user.NameLast + ", " + user.NameFirst;
print(name);
l.add(name);
}
return l;
}
the function will not return before all filenames are processed.
files.forEach((filename) async {
means that you can use await inside the callback, but forEach doesn't care about what (filename) async {...} returns.
Also possible
await Future.forEach(yourList, (T elem) async { ...async staff });
To expand on Günter's comment regarding using list.map(f), here's an example of converting a forEach call so that it works correctly.
Broken example
Incorrectly assumes forEach will wait on futures:
Future<void> brokenExample(List<String> someInput) async {
List<String> results;
someInput.forEach((input) async {
String result = await doSomethingAsync(input);
results.add(result);
});
return results;
}
Corrected example
Waits on the async functions to complete, using Future.wait and .map():
Future<void> correctedExample(List<String> someInput) async {
List<String> results;
await Future.wait(someInput.map((input) async {
String result = await doSomethingAsync(input);
results.add(result);
}));
return results;
}
I encountered the similar issue. The problem is that dart will NOT wait for "forEach" contrary to public believe. There are two solutions:
1) Convert forEach to for loop as indicated by others. Another is use Future:
2) await Future.forEach(list, (item) async {
// your code
final result = await getMyResult();
});
Another option
Future.wait(someList.map((item) => something_returns_future(item)));