I need to call dart function do something and return data back to aqueduct controller. So, Can I call any dart function inside aqueduct response controller? If yes, how?
class NtmsApiController extends Controller {
#override
Future<RequestOrResponse> handle(Request request) async {
try {
if (request.path.remainingPath != null) {
_requestValue = request.path.remainingPath;
…
… can I go from here to dart function and get data back???? If yes, how?
UPDATE CODE:
I have global variable and it prints in null. Once the socket gets the data the void _printResponse(String _response) prints the data and from there I assign the data to global variable. But in Future handle data become null so I cannot return the as a response object. Any idea?
#override
Future<RequestOrResponse> handle(Request request) async {
_stopWatch = Stopwatch() //Global
..start();
_response = ""; // Global
if (request.path.remainingPath != null) {
final _requestValue = request.path.remainingPath;
await _getData(_requestValue);
}
print(_secureResponse); // It prints null, _secureResponse is Global variable
return Response.ok("$_secureResponse")
..contentType = ContentType.json;
}
//TODO: GET DATA FROM CSBINS
Future<Null> _getData(String _request) async {
await Socket.connect("192.168.22.120", 3000).then((Socket sock) {
_socket = sock;
_socket.write('$_request\r\n');
_socket.listen (dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: true);
}).catchError((AsyncError e) {
_response = "Server_Error";
});
}
void dataHandler(data) {
final List<int> byteArray = data;
_response = String.fromCharCodes(byteArray).trim();
}
void errorHandler(error, StackTrace trace) {
_response = "Server_Error";
}
void doneHandler() {
_socket.destroy();
}
void _printResponse(String _response) {
// prints succefully ***************************
print("$_response ... (${_stopWatch.elapsedMilliseconds} ms)");
_secureResponse = _response;
_stopWatch..stop();
if (_stopWatch.isRunning == false) {
_socket.flush();
_socket.close();
print("Socket Closed.");
}
}
Related
I'm currently migrating an App's logic code from C# to Dart and I'm looking for a similiar collection type in Dart to C#s BlockingCollection. I basically want a queue where i can iterate infinitely. If the queue is empty it just waits until a new element is added.
Is that possible in Dart?
Best
You can use a StreamController.
Here I translated the first C# example for BlockingCollection
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
class BlockingCollectionDemo
{
static async Task Main()
{
await AddTakeDemo.BC_AddTakeCompleteAdding();
}
}
class AddTakeDemo
{
// Demonstrates:
// BlockingCollection<T>.Add()
// BlockingCollection<T>.Take()
// BlockingCollection<T>.CompleteAdding()
public static async Task BC_AddTakeCompleteAdding()
{
using (BlockingCollection<int> bc = new BlockingCollection<int>())
{
// Spin up a Task to populate the BlockingCollection
Task t1 = Task.Run(() =>
{
bc.Add(1);
bc.Add(2);
bc.Add(3);
bc.CompleteAdding();
});
// Spin up a Task to consume the BlockingCollection
Task t2 = Task.Run(() =>
{
try
{
// Consume consume the BlockingCollection
while (true) Console.WriteLine(bc.Take());
}
catch (InvalidOperationException)
{
// An InvalidOperationException means that Take() was called on a completed collection
Console.WriteLine("That's All!");
}
});
await Task.WhenAll(t1, t2);
}
}
}
to dart using a StreamController instead of BlockingCollection, and Future instead of Task.
import 'dart:async';
Future<void> main() async {
await addTakeCompleteAdding();
}
// Demonstrates:
// StreamController<T>.add()
// StreamController<T>.stream
// StreamController<T>.close()
Future<void> addTakeCompleteAdding() async {
StreamController<int> bc = StreamController<int>();
// Spin up a Future to populate the StreamController
Future<void> t1 = Future(() {
bc.add(1);
bc.add(2);
bc.add(3);
bc.close();
});
// Spin up a Future to consume the StreamController
Future<void> t2 = Future(() async {
// Consume consume the StreamController
await for (final element in bc.stream) {
print(element);
}
// Exits the loop when the stream is completed/closed
print("That's All!");
});
await Future.wait([t1, t2]);
}
That said, the StreamController differs a bit from BlockingCollection in that it is not a queue. A Stream in dart by default, can only have one subscription, unless you create a broadcast stream. Stream is more like an async enumerable in C#.
If you really need a queue data structure you can use the async package, which has a StreamQueue class that you can use to wrap the stream from the StreamController.
Here is the above code modified to use a StreamQueue:
import 'dart:async';
import 'package:async/async.dart';
Future<void> main() async {
await addTakeCompleteAdding();
}
// Demonstrates:
// StreamController<T>.add()
// StreamController<T>.stream
// StreamController<T>.close()
// StreamQueue<T>.next
Future<void> addTakeCompleteAdding() async {
StreamController<int> bc = StreamController<int>();
StreamQueue<int> queue = StreamQueue<int>(bc.stream);
// Spin up a Future to populate the StreamController
Future<void> t1 = Future(() {
bc.add(1);
bc.add(2);
bc.add(3);
bc.close();
});
// Spin up a Future to consume the StreamQueue
Future<void> t2 = Future(() async {
try {
while (true) {
// Consume consume the StreamQueue
print(await queue.next);
}
} on StateError catch (e) {
// A StateError means that next was called on a completed collection
print("That's all!");
}
});
await Future.wait([t1, t2]);
}
You can also write your own queue, based on futures instead of a stream:
import "dart:async" show Completer;
import "dart:collection" show Queue;
abstract class BlockingQueue<T> {
factory BlockingQueue() = _BlockingQueue;
Future<T> removeNext();
void add(T value);
}
class _BlockingQueue<T> implements BlockingQueue<T> {
final Queue<T> _writes = Queue();
final Queue<Completer<T>> _reads = Queue();
Future<T> removeNext() {
if (_writes.isNotEmpty) return Future.value(_writes.removeFirst());
var completer = Completer<T>();
_reads.add(completer);
return completer.future;
}
void add(T value) {
if (_reads.isNotEmpty) {
_reads.removeFirst().complete(value);
} else {
_writes.add(value);
}
}
}
You can also consider a double-blocking queue, where the add method also "blocks" if there is no-one to accept the value yet. It's not even that hard,.
import "dart:async" show Completer;
import "dart:collection" show Queue;
abstract class BlockingQueue<T> {
factory BlockingQueue() = _BlockingQueue;
Future<T> removeNext();
Future<void> add(T value);
}
class _BlockingQueue<T> implements BlockingQueue<T> {
final Queue<T> _writes = Queue();
final Queue<Completer<T>> _completers = Queue();
Future<T> removeNext() {
if (_writes.isNotEmpty) {
assert(_completers.isNotEmpty);
var completer = _completers.removeFirst();
completer.complete(_writes.removeFirst());
return completer.future;
}
var completer = Completer<T>();
_completers.add(completer);
return completer.future;
}
Future<void> add(T value) {
if (_writes.isEmpty && _completers.isNotEmpty) {
var completer = _completers.removeFirst();
completer.complete(value);
return completer.future;
}
var completer = Completer<T>();
_completers.add(completer);
_writes.add(value);
return completer.future;
}
}
That said, if you want to use a for (... in ...)-like loop, you probably do want to go with a Stream and use await for (... in theStream).
I am having trouble understanding why one piece of code prints the future is null
void main() async {
task1();
String str = await task2();
task3(str);
}
void task1() {
print('ring');
}
Future<String> task2() async {
Duration dur = Duration(seconds: 3);
String res;
await Future.delayed(dur, () {
res = 'a bright one!';
return res; // return statement inside the callback.
});
}
void task3(String str) {
print('the future is $str');
}
while this works properly and has the expected behavior of printing 'the future is a bright one'
void main() async {
task1();
String str = await task2();
task3(str);
}
void task1() {
print('ring');
}
Future<String> task2() async {
Duration dur = Duration(seconds: 3);
String res;
await Future.delayed(dur, () {
res = 'a bright one!';
});
return res;
}
void task3(String str) {
print('the future is $str');
}
I am new to asynchronous programming but my understanding is that the callback that is the second argument in Future.delayed is executed after a delay what I don't understand why the placement of the return statement here breaks the code. I tried to run the code in debug mode to trace the code but I didn't understand what is exactly happening. All help is greatly appreciated
Disk Cache with Generics
I am a programmer who comes from JavaScript and PHP, and am developing an App on Flutter, and am having difficulty implementing a cache on the phone's internal storage.
I would like to understand and know if it is possible to create a Generic type class with serialization for JSON so that it can be stored on file.
I've done the Cache implementation in memory and it works fine, plus the implementation of Cache on Disk I'm having difficulty.
Code for Memory cache
class MemCache<T> extends Cache<T> {
Duration cacheValidDuration = Duration(minutes: 30);
DateTime lastFetchTime = DateTime.fromMillisecondsSinceEpoch(0);
RList<T> allRecords = RList<T>();
//is updade cache
bool isShouldRefresh() {
return (null == allRecords ||
allRecords.isEmpty ||
null == lastFetchTime ||
lastFetchTime.isBefore(DateTime.now().subtract(cacheValidDuration)));
}
#override
Future<RList<T>> getAll() {
return Future.value(allRecords);
}
#override
Future<void> putAll(RList<T> objects) {
allRecords.addAll(objects);
lastFetchTime = DateTime.now();
}
#override
Future<void> putAllAsync(Future<RList<T>> objects) async {
allRecords = await objects;
}
}
Code for Disk Cache
How to call the serialization method from a Generic
class DiskCache<T> extends Cache<T> {
Duration cacheValidDuration = Duration(minutes: 30);
DateTime lastFetchTime = DateTime.fromMillisecondsSinceEpoch(0);
RList<T> allRecords = RList<T>();
//is update the cache
bool isShouldRefresh() {
return (null == allRecords ||
allRecords.isEmpty ||
null == lastFetchTime ||
lastFetchTime.isBefore(DateTime.now().subtract(cacheValidDuration)));
}
#override
Future<RList<T>> getAll() async {
await _readFromDisk();
return Future.value(allRecords);
}
#override
Future<void> putAll(RList<T> objects) async {
allRecords.addAll(objects);
lastFetchTime = DateTime.now();
await _writeToDisk();
}
#override
Future<void> putAllAsync(Future<RList<T>> objects) async {
allRecords = await objects;
lastFetchTime = DateTime.now();
await _writeToDisk();
}
//parth
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
//file pointer
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/allRecords.json');
}
//write to file
Future<File> _writeToDisk() async {
try {
File recordedFile;
if (allRecords != null) {
var map = allRecords.map((c) {
var item = c as ISerialization;
return item.toJson();
}).toList();
var jsonString = jsonEncode(map);
final file = await _localFile;
// Write the file
recordedFile = await file.writeAsString(jsonString);
}
return recordedFile;
} catch (e) {
print("writeToDisk: " + e.toString());
return null;
}
}
// ************************** issues on this part ******************
Future<RList<T>> _readFromDisk() async {
try {
final file = await _localFile;
// Read the file
String contents = await file.readAsString();
var parsedJson = jsonDecode(contents);
if (allRecords == null) {
allRecords = RList<T>();
}
allRecords.clear();
for (var item in parsedJson) {
// ************************** issues on this part ******************
print(T.fromMap(item));
allRecords.add(T.fromMap(item));
}
return allRecords;
} catch (e) {
print("readFromDisk: " + e.toString());
return null;
}
}
}
Error: The method 'fromMap' isn't defined for the class 'Type'.
- 'Type' is from 'dart:core'.
Try correcting the name to the name of an existing method, or defining a method named 'fromMap'.
allRecords.add(T.fromMap(item));
^^^^^^^
I am trying to make a way to read a file with data saved in a specific format, parse it to JSON then convert it to an object so that I can use dot notation.
The problem here is using dot notation as it just returns null
CoreData.dart
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
#proxy
class CoreObject {
Map _data;
CoreObject([String source]) {
Map json = (source == null) ? new Map() : JSON.decode(source);
_data = new Map.from(json);
json.forEach((k, v) {
print(k);
_data[k] = v;
});
}
static encode(List<CoreObject> list) {
String result = "";
for (CoreObject item in list) {
result += "${item.toString()};";
}
return result;
}
#override toString() {
print(this._data);
return JSON.encode(this._data);
}
#override
noSuchMethod(Invocation invocation) {
var name = invocation.memberName.toString().replaceFirst('Symbol(\"', "");
print("_data.keys ${_data.keys}");
print("_data.values ${_data.values}");
if (invocation.isGetter) {
print("name ${name.replaceAll("\")", "")}");
var ret = _data[name.replaceAll("\")", "")];
print("ret $ret");
print(ret.toString());
return ret;
}
if (invocation.isSetter) {
_data[name.replaceAll("=\")", "")] = invocation.positionalArguments.first;
} else {
super.noSuchMethod(invocation);
}
}
}
class Person extends CoreObject {
Person([source]): super(source);
#override noSuchMethod(Invocation invocation) {
super.noSuchMethod(invocation);
}
}
class CoreContainer {
String _object;
var returnNew;
var path;
_map(String source) {
var result = [];
for (var line in source.split(";")) {
// print("line $line");
if (line != "") result.add(returnNew(line));
}
print("result $result");
return result;
}
encode(List<CoreObject> list) {
// print("list $list");
String result = "";
list.forEach((CoreObject item) {
// print("item ${item.toString()}");
result += "${item};";
});
// print("result $result");
return result;
}
CoreContainer(this._object, this.returnNew);
Future<File> _getFile() async {
String dir = path ?? (await getApplicationDocumentsDirectory()).path;
this.path = dir;
return new File('$dir/$_object.txt');
}
Future<List<CoreObject>> getAll() async {
return _getFile().then((File file) {
String contents = file.readAsStringSync();
print("contents $contents");
return this._map(contents);
})
.catchError((Error error) {
print('error: $error');
_getFile().then((File file) {
file.writeAsStringSync("");
});
return [];
});
}
save(List<CoreObject> data) async {
_getFile().then((file) {
try {
file.writeAsStringSync(this.encode(data));
}
catch (error) {
print("error: $error");
}
}).catchError((Error error) {
print("error: $error");
});
}
clear() async {
return _getFile().then((file) {
file.writeAsStringSync("");
}).catchError((Error error) {
print("error: $error");
});
}
Future<List<CoreObject>> get(query) async {
return this.getAll().then((List data) {
data.retainWhere(query);
return data;
}).catchError((error) {
print("error: $error");
});
}
Future<List<CoreObject>> remove(query) async {
return this.getAll().then((List data) {
// print(data);
data.removeWhere(query);
save(data);
return data;
}).catchError((error) {
print("error: $error");
});
}
Future<List<CoreObject>> add(obj) async {
return this.getAll().then((data) {
data.add(obj);
return save(data).then(() {
return data;
})
.catchError((Error error) {
throw error;
});
}).catchError((Error error) {
print("error: $error");
});
}
}
Using it:
CoreContainer corePerson = new CoreContainer("Person", (source) => new Person(source));
corePerson.getAll().then((List<CoreObject> array) {
var tempItems = [];
var i = 0;
print("array $array");
while (i < array.length) {
Person person = array[i];
print(person); //{"name":"<whatever 'i' is>"}
print(person.name); //null
tempItems.add(new ListTile(
title: new Text("$i"),
subtitle: new Text("${person.name}"),
));
i++;
}
print(tempItems.length);
count = tempItems.length;
setState(() {
items = tempItems;
});
}).catchError((Error error) {
print("error: $error, ${error.stackTrace}");
});
Code is hard to read because of a lot of print debugging.
But I suppose you need a way to convert JSON data into a Dart class.
You should use library like jaguar_serializer that do the job for you.
https://pub.dartlang.org/packages/jaguar_serializer
Dart doesn't use dot notation like dynamic languages (Python, JavaScript). In Python and JavaScript, for example, every single object is actually internally a HashMap, and . is actually a hash lookup of the property name:
a.bar // Loosely the same as a.lookup('bar')
The Python/JS VM though can "see" that a.bar is used like a property on a class-like object a, and optimize it to use a true property/field access - this is part of the "optimization" phase of a JIT (just-in-time compiler).
It is features like this that make it almost impossible to ahead-of-time compile either Python or JS - they require runtime profile information to generate fast code. Dart (and specifically Dart 2.0) is implementing a sound type system where a.bar, when a is known, is always a property accessor, not a hash lookup.
That means at runtime you can't take an arbitrary hash map and force it to act like an object, which is why your code seems awkward. I'd recommend using code generation if you need a typed object with . notation, or settling for a HashMap [] if you do not.
Check also mapping json into class objects answers for example of clean basic way of json -> dart class mapping.
I'm trying to create a server-side Dart class that performs various data-related tasks. All of these tasks rely on the database having been first initialized. The problem is that the init of the database happens asynchronously (returns a Future). I first tried to put the init code into the constructor, but have given up on this approach as it seems to not be viable.
I am now attempting to figure out how to force the DB initialization as a first step in any method call that accesses data. So in other words, when attemptLogin() is called below, I'd like to first check if the DB has been initialized and initialize it if necessary.
However, there are two obstacles. If the database hasn't been initialized, the code is straightforward - initialize the db, then use the then() method of the returned future to do the rest of the function. If the db is not yet initialized, what do I attach my then() method to?
Second related question is what happens when a database is currently being initialized but this process is not yet complete? How can I pull in and return this "in-progress" Future?
This is the basic gist of the code I'm trying to wrangle:
class DataManager {
bool DbIsReady = false;
bool InitializingDb = false;
Db _db;
Future InitMongoDB() {
print("Initializing MongoDB");
InitializingDb = true;
_db = new Db("mongodb://127.0.0.1/test");
return _db.open().then((_) {
DbIsReady = true;
InitializingDb = false;
});
}
Future<List> attemptLogin(String username, String password) {
Future firstStep;
if ((!DbIsReady) && (!InitializingDb) {
Future firstStep = InitMongoDB()
}
else if (InitializingDb) {
// Need to return the InitMongoDB() Future that's currently running, but how?
}
else {
// How do I create a blank firstStep here?
}
return firstStep.then((_) {
users = _db.collection("users");
return // ... rest of code cut out for clarity
});
}
}
Thanks in advance for your help,
Greg
Just return
return new Future<bool>.value(true);
// or any other value instead of `true` you want to return.
// or none
// return new Future.value();
Just keep the future alive:
class DataManager {
Future _initializedDb;
Future initMongoDb() { ... }
Future<List> attemptLogin(String username, String password) {
if (_initializedDb == null) {
_initializedDb = initMongoDB();
}
return _initializedDb.then((db) {
users = db.collection("users");
return // ... rest of code cut out for clarity
});
}
}
You might need to pay attention for the error-case. It's up to you if you want to deal with errors in the initMongoDB or after it.
One of the possible solutions:
import "dart:async";
void main() {
var dm = new DataManager();
var selectOne = dm.execute("SELECT 1");
var selectUsers = dm.execute("SELECT * FROM users");
var users = selectOne.then((result) {
print(result);
return selectUsers.then((result) {
print(result);
});
});
users.then((result) {
print("Goodbye");
});
}
class Event {
List<Function> _actions = new List<Function>();
bool _raised = false;
void add(Function action) {
if (_raised) {
action();
} else {
_actions.add(action);
}
}
void raise() {
_raised = true;
_notify();
}
void _notify() {
if (_actions.isEmpty) {
return;
}
var actions = _actions.toList();
_actions.clear();
for (var action in actions) {
action();
}
}
}
class DataManager {
static const int _STATE_NOT_INITIALIZED = 1;
static const int _STATE_INITIALIZING = 2;
static const int _STATE_READY = 3;
Event _initEvent = new Event();
int _state = _STATE_NOT_INITIALIZED;
Future _init() {
if (_state == _STATE_NOT_INITIALIZED) {
_state = _STATE_INITIALIZING;
print("Initializing...");
return new Future(() {
print("Initialized");
_state = _STATE_READY;
_initEvent.raise();
});
} else if (_state == _STATE_INITIALIZING) {
print("Waiting until initialized");
var completer = new Completer();
_initEvent.add(() => completer.complete());
return completer.future;
}
return new Future.value();
}
Future execute(String query, [Map arguments]) {
return _init().then((result) {
return _execute(query, arguments);
});
}
Future _execute(String query, Map arguments) {
return new Future.value("query: $query");
}
}
Output:
Initializing...
Waiting until initialized
Initialized
query: SELECT 1
query: SELECT * FROM users
Goodbye
I think that exist better solution but this just an attempt to answer on your question (if I correctly understand you).
P.S. EDITED at 11 July 2014
Slightly modified (with error handling) example.
import "dart:async";
void main() {
var dm = new DataManager();
var selectOne = dm.execute("SELECT 1");
var selectUsers = dm.execute("SELECT * FROM users");
var users = selectOne.then((result) {
print(result);
return selectUsers.then((result) {
print(result);
});
});
users.then((result) {
print("Goodbye");
});
}
class DataManager {
static const int _STATE_NOT_INITIALIZED = 1;
static const int _STATE_INITIALIZING = 2;
static const int _STATE_READY = 3;
static const int _STATE_FAILURE = 4;
Completer _initEvent = new Completer();
int _state = _STATE_NOT_INITIALIZED;
Future _ensureInitialized() {
switch (_state) {
case _STATE_NOT_INITIALIZED:
_state = _STATE_INITIALIZING;
print("Initializing...");
new Future(() {
print("Initialized");
_state = _STATE_READY;
// throw null;
_initEvent.complete();
}).catchError((e, s) {
print("Failure");
_initEvent.completeError(e, s);
});
break;
case _STATE_INITIALIZING:
print("Waiting until initialized");
break;
case _STATE_FAILURE:
print("Failure detected");
break;
default:
print("Aleady intialized");
break;
}
return _initEvent.future;
}
Future execute(String query, [Map arguments]) {
return _ensureInitialized().then((result) {
return _execute(query, arguments);
});
}
Future _execute(String query, Map arguments) {
return new Future.value("query: $query");
}
}
For those that are still wondering how to create a blank Future in Dart and later complete them, you should use the Completer class like in the next example.
class AsyncOperation {
final Completer _completer = new Completer();
Future<T> doOperation() {
_startOperation();
return _completer.future; // Send future object back to client.
}
// Something calls this when the value is ready.
void finishOperation(T result) {
_completer.complete(result);
}
// If something goes wrong, call this.
void _errorHappened(error) {
_completer.completeError(error);
}
}
Future<Type> is non nullable in Dart, meaning that you have to initialize it to a value. If you don't, Dart throws the following error:
Error: Field should be initialized because its type 'Future<Type>' doesn't allow null.
To initialize a Future<Type>, see the following example:
Future<String> myFutureString = Future(() => "Future String");
Here "Future String" is a String and so the code above returns an instance of Future<String>.
So coming to the question of how to create a blank/empty Future, I used the following code for initializing an empty Future List.
Future<List> myFutureList = Future(() => []);
I found this link to be quite useful in understanding Futures in Flutter and Dart: https://meysam-mahfouzi.medium.com/understanding-future-in-dart-3c3eea5a22fb