Access http response body from outside - dart

import 'package:http/http.dart' as http;
main() {
String esearch = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=nucleotide&term=Paenibacillus";
var uidList = [];
http.get(esearch).then((response) {
var pattern = new RegExp(r"<Id>(.*?)</Id>");
var hits = pattern.allMatches(response.body);
hits.forEach((hit) {
print("whole match: " + hit[0] + " first match " + hit[1]);
uidList.add(hit[1]);
});
});
print(uidList.length); // empty, because main thread is faster than query
}
Hello everyone,
I'm playing around with Dart since one day to figure out, whether it's suitable for my needs. In the code I have attached, I want to access the result of the body outside of the http query block. This isn't possible. In another question here, someone writes this is because of Darts async concept.
Is there a way to get access to from outside. This is import because I have to trigger several htttp requests with the resulting data and don't wont to nest them all within the http block.
Or any other suggestions?
Thank you very much.

This doesn't work this way because an async call (http.get()) is scheduled for later execution and than execution proceeds with the next line. Your print is executed before http.get() even started to connect. You need to chain all successive calls with then.
If you have a recent Dart version you can use async/await which makes using async calls easier.
import 'package:http/http.dart' as http;
main() {
String esearch = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=nucleotide&term=Paenibacillus";
var uidList = [];
return http.get(esearch).then((response) {
var pattern = new RegExp(r"<Id>(.*?)</Id>");
var hits = pattern.allMatches(response.body);
hits.forEach((hit) {
print("whole match: " + hit[0] + " first match " + hit[1]);
uidList.add(hit[1]);
});
return uidList;
}).then((uidList) {
print(uidList.length);
});
}
async/await
import 'package:http/http.dart' as http;
main() async {
String esearch = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=nucleotide&term=Paenibacillus";
var uidList = [];
var response = await http.get(esearch);
var pattern = new RegExp(r"<Id>(.*?)</Id>");
var hits = pattern.allMatches(response.body);
hits.forEach((hit) {
print("whole match: " + hit[0] + " first match " + hit[1]);
uidList.add(hit[1]);
});
print(uidList.length);
}

Related

How to run 2 process and exchange input/output between them multiple times?

I'm trying to do something like this:
Future<String> getOutAndAnswer(testcase) async {
Process python = await Process.start('python', ['tasks/histogram/run.py']);
Process java = await Process.start('java', ['solutions/Histogram.java']);
String results = "";
for(int i = 0; i < testcase; i++){
final String out = await python.stdout.transform(utf8.decoder).first;
java.stdin.writeln(out);
final String answer = await java.stdout.transform(utf8.decoder).first;
python.stdin.writeln(answer);
results += "($out, $answer)";
}
return results;
}
Basically, the python program is responsible for generating the input of each test case, then the java program will take the input and return the answer, which is sent to the python program to check if it's correct or not, and so on for every test case.
But when I try to use the above code I get an error saying I've already listened to the stream once:
Exception has occurred.
StateError (Bad state: Stream has already been listened to.)
Python program:
import os
CASE_DIR = os.path.join(os.path.dirname(__file__), "cases")
test_cases = next(os.walk(CASE_DIR))[2]
print(len(test_cases))
for case in sorted(test_cases):
with open(os.path.join(CASE_DIR, case), 'r') as f:
print(f.readline(), end='', flush=True)
f.readline()
expected_output = f.readline()
user_output = input()
if expected_output != user_output:
raise ValueError("Wrong answer!")
print("EXIT", flush=True)
Java program:
public class Histogram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt();
for (int i = 0; i < t; i++) {
String input = scanner.nextLine();
String answer = calculateAnswer(input);
System.out.println(answer);
}
}
}
Your issue is with .first which is going to listen to the stream, get the first element, and then immediately stop listening to the stream. See the documentation here: https://api.dart.dev/stable/2.17.3/dart-async/Stream/first.html
You should instead listen once and define an onData method to perform the steps. See the documentation for .listen() here: https://api.dart.dev/stable/2.17.3/dart-async/Stream/listen.html
You could try wrapping the stdout streams in StreamIterator<String>. You will have to give it a try to verify, but I think this is what you are looking for.
Future<String> getOutAndAnswer(int testcase) async {
Process python = await Process.start('python', ['tasks/histogram/run.py']);
Process java = await Process.start('java', ['solutions/Histogram.java']);
String results = "";
StreamIterator<String> pythonIterator = StreamIterator(
python.stdout.transform(utf8.decoder).transform(LineSplitter()));
StreamIterator<String> javaIterator = StreamIterator(
java.stdout.transform(utf8.decoder).transform(LineSplitter()));
for (int i = 0; i < testcase; i++) {
if (await pythonIterator.moveNext()) {
final String out = pythonIterator.current;
if (out == 'EXIT') {
break;
}
java.stdin.writeln(out);
if (await javaIterator.moveNext()) {
final String answer = javaIterator.current;
python.stdin.writeln(answer);
results += "($out, $answer)";
}
}
}
await pythonIterator.cancel();
await javaIterator.cancel();
return results;
}
You may need to add the following imports:
import 'dart:async';
import 'dart:convert';

Mirth HTTP POST request with Parameters using Javascript

The following code by #Nick Rupley works well, but, I need also to pass parameters as POST. How do we pass POST parameters?
from java.net.URL
var url = new java.net.URL('http://localhost/myphpscript.php');
var conn = url.openConnection();
var is = conn.getInputStream();
try {
var result = org.apache.commons.io.IOUtils.toString(is, 'UTF-8');
} finally {
is.close();
}
2 Parameters to pass: firstname="John" and lastname="Smith"
Thanks
This will POST with MIME type application/x-www-form-urlencoded. It is using apache httpclient, which is already included with mirth, as it is used internally by the HTTP Sender connector, as well as some other functionality. Other solutions may require you to download jars and add library resources.
Closer is part of Google Guava, which is also already included with mirth.
Check comments where Rhino javascript allows for simplified code compared to direct Java conversion.
It wouldn't be a bad idea to wrap all of this up in a code template function.
var result;
// Using block level Java class imports
with (JavaImporter(
org.apache.commons.io.IOUtils,
org.apache.http.client.methods.HttpPost,
org.apache.http.client.entity.UrlEncodedFormEntity,
org.apache.http.impl.client.HttpClients,
org.apache.http.message.BasicNameValuePair,
com.google.common.io.Closer))
{
var closer = Closer.create();
try {
var httpclient = closer.register(HttpClients.createDefault());
var httpPost = new HttpPost('http://localhost:9919/myphpscript.php');
// javascript array as java List
var postParameters = [
new BasicNameValuePair("firstname", "John"),
new BasicNameValuePair("lastname", "Smith")
];
// Rhino JavaBean access to set property
// Same as httpPost.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
httpPost.entity = new UrlEncodedFormEntity(postParameters, "UTF-8");
var response = closer.register(httpclient.execute(httpPost));
// Rhino JavaBean access to get properties
// Same as var is = response.getEntity().getContent();
var is = closer.register(response.entity.content);
result = IOUtils.toString(is, 'UTF-8');
} finally {
closer.close();
}
}
logger.info(result);
Following is a complete working HTTP POST request solution tested in Mirth 3.9.1
importPackage(Packages.org.apache.http.client);
importPackage(Packages.org.apache.http.client.methods);
importPackage(Packages.org.apache.http.impl.client);
importPackage(Packages.org.apache.http.message);
importPackage(Packages.org.apache.http.client.entity);
importPackage(Packages.org.apache.http.entity);
importPackage(Packages.org.apache.http.util);
var httpclient = HttpClients.createDefault();
var httpPost = new HttpPost("http://localhost/test/");
var httpGet = new HttpGet("http://httpbin.org/get");
// FIll in each of the fields below by entering your values between the ""'s
var authJSON = {
"userName": "username",
"password": "password",
};
var contentStr =JSON.stringify(authJSON);
//logger.info("JSON String: "+contentStr);
httpPost.setEntity(new StringEntity(contentStr,ContentType.APPLICATION_JSON,"UTF-8"));
httpPost.setHeader('Content-Type', 'application/json');
httpPost.setHeader("Accept", "application/json");
// Execute the HTTP POST
var resp;
try {
// Get the response
resp = httpclient.execute(httpPost);
var statusCode = resp.getStatusLine().getStatusCode();
var entity = resp.getEntity();
var responseString = EntityUtils.toString(entity, "UTF-8");
var authHeader = resp.getFirstHeader("Authorization");
// logger.info("Key : " + authHeader.getName()+" ,Value : " + authHeader.getValue());
// Save off the response and status code to Channel Maps for any potential troubleshooting
channelMap.put("responseString", responseString);
channelMap.put("statusCode", statusCode);
// Parse the JSON response
var responseJson = JSON.parse(responseString);
// If an error is returned, manually throw an exception
// Else save the token to a channel map for use later in the processing
if (statusCode >= 300) {
throw(responseString);
} else {
logger.info("Token: "+ authHeader.getValue());
channelMap.put("token", authHeader.getValue());
}
} catch (err) {
logger.debug(err)
throw(err);
} finally {
resp.close();
}
This linke + above answers helped me to come up with a solution
https://help.datica.com/hc/en-us/articles/115005322946-Advanced-Mirth-Functionality
There are plenty of libraries that can help you with URI building in Java. You can find them below. But if you want to stay in Javascript just add your parameters manually than create it.
function addParam(uri, appendQuery) {
if (appendQuery != null) {
uri += "?" + appendQuery;
}
return uri;
}
var newUri = addParam('http://localhost/myphpscript.php', 'firstname="John"');
var url = new java.net.URL(newUri);
Java EE 7
import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();
org.apache.httpcomponents:httpclient:4.5.2
import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();
org.springframework:spring-web:4.2.5.RELEASE
import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();
There are multiple ways to provide http client connection with java. Since your question is specific to java.net.URL I will stick to that.
Basically you can pass parameters as POST, GET, PUT, DELETE using .setRequestMethod this will be used along with new java.net.URL(ur-destination-url).openConnection();
Here is the complete code I've using javascript in Mirth using the same java.net.URL use this it will be helpful. It worked well for me.
do {
try {
// Assuming your writing this in the destination Javascript writer
var data = connectorMessage.getEncodedData();
//Destination URL
destURL = “https://Your-api-that-needs-to-be-connected.com”;
//URL
var url = new java.net.URL(destURL);
var conn = url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
enter code here
conn.setRequestProperty (“Authorization”, globalMap.get(‘UniversalToken’));
conn.setRequestMethod(“DELETE”); // this can be post or put or get or patch
conn.setRequestProperty(“Content-length”, data.length());
conn.setRequestProperty(“Content-type”, “application/json”);
var outStream = conn.getOutputStream();
var outWriter = new java.io.OutputStreamWriter(outStream);
outWriter.write(data);
outWriter.close();
// Get response Code (200, 500 etc.)
var respCode = conn.getResponseCode();
if (respCode != 200) {
// Write error to error folder
var stringData = response.toString() + “\n”;
FileUtil.write(“C:/Outbox/Errors/” + $(“originalFilename”) + “.ERROR_RESPONSE”, false, stringData);
// Return Error to Mirth to move the file to the error folder
return ERROR;
}
errorCond = “false”;
break;
}
catch(err) {
channelMap.put(“RESPONSE”, err);
responseMap.put(“WEBSVC”, ResponseFactory.getErrorResponse(err))
throw(err);
// Can return ERROR, QUEUED, SENT
// This re-queues the message on a fatal error. I”m doing this since any fatal message may be
// caused by HTTPS connect errors etc. The message will be re-queued
return QUEUED; // Re-queue the message
java.lang.Thread.sleep(6000); // 6 seconds * 10
errorCond = “true”;
}
}
while (errorCond == “true”);

Why my md-autoComplete is not displaying return values

I am using Angular Material for the first time. I am stuck with an issue with autocomplete. Below is my template:
<md-autocomplete class="flex"
md-no-cache="true"
md-selected-item="c.receipt"
md-item-text="item.name"
md-search-text="SearchText"
md-items="item in querySearch(SearchText)"
md-floating-label="search">
<md-item-template>
<span><span class="search-result-type">{{item.GEOType}}</span><span md-highlight-text="SearchText">{{item.GEOName+(item.country?' / '+item.country:'')}}</span></span>
</md-item-template>
<md-not-found>No matches found.</md-not-found>
</md-autocomplete>
And in ctrl I have:
$scope.querySearch = function (query) {
var GeoDataAPIUrl = '/api/TargetSettings/RetrieveCorridorLeverValues';
if (query.length < 5)
return;
else {
var GeoDataSearchUrl = GeoDataAPIUrl + '?' + 'strGeoName=' + query;
$http
.get(GeoDataSearchUrl)
.then(function (geoAPIResponse) {
console.log("GeoAPIResponse was ", geoAPIResponse);
return geoAPIResponse.data;
},
function (geoAPIError) {
console.log("GeoAPI call failed ", geoAPIError);
});
}
};
With above code, I am getting nothing as suggestions, only my not-found text is displayed, while my http call return an array which is printed in console too. Am I missing something??
I saw at many places, people have used some filters with autocomplete, I dont think that is something essential.
Pls advice how to make above work.
$http returns promise and md-autocomplete uses same promise to display the result. In your case you are returning result but not promise. Your code should be
$scope.querySearch = function (query) {
var GeoDataAPIUrl = '/api/TargetSettings/RetrieveCorridorLeverValues';
if (query.length < 5)
return;
else {
var GeoDataSearchUrl = GeoDataAPIUrl + '?' + 'strGeoName=' + query;
var promise = $http.get(GeoDataSearchUrl).then(function (geoAPIResponse) {
console.log("GeoAPIResponse was ", geoAPIResponse);
return geoAPIResponse.data;
},
function (geoAPIError) {
console.log("GeoAPI call failed ", geoAPIError);
});
return promise;
}
};
It will work now.

create a circular stream in Dart

I try to write a chat application to chat with a computer. The user can write a message and gets a response of the computer. A chat history might look like this:
user: Hi
computer: Hello
user: What's your name?
computer: Bot
...
My circular stream based design is inspired by the ideas of Cycle.js. I've got a stream of user messages, which get transformed to a stream of computer messages, which are in turn the input of the user message stream:
|----> user message stream ---->|
| |
transform transform
| |
|<-- computer message stream <--|
This code already works:
import 'dart:io';
import 'dart:async';
void main() {
cycle(computer, user);
}
typedef Stream<T> Transform<T>(Stream<T> input);
void cycle(Transform aToB, Transform bToA) {
var aProxy = new StreamController.broadcast();
var b = aToB(aProxy.stream);
var a = bToA(b);
aProxy.add('start'); // start with user
aProxy.addStream(a);
}
Stream<String> user(Stream<String> computerMessages) {
computerMessages = computerMessages.asBroadcastStream();
computerMessages.listen((message) => print('computer: $message'));
return computerMessages.map((message) {
stdout.write('user: ');
return stdin.readLineSync();
});
}
Stream<String> computer(Stream<String> userMessages) {
var messages = <String, String>{
"Hi": "Hello",
"What's your name?": "Bot"
};
return userMessages.map((m) => messages.containsKey(m) ? messages[m] : 'What?');
}
There is only one problem. You need a start value to get a circular stream running. Therefore, I put this line in my function cycle:
aProxy.add('start'); // start with user
Actually, this logic belongs into my function user, since cycle shouldn't know the initial value(s). Moreover, I don't like to print the initial value. It should only trigger the user input stream. Thus, I changed cycle and user:
void cycle(Transform aToB, Transform bToA) {
var aProxy = new StreamController.broadcast();
var b = aToB(aProxy.stream);
var a = bToA(b);
aProxy.addStream(a);
}
Stream<String> user(Stream<String> computerMessages) {
computerMessages = computerMessages.asBroadcastStream();
computerMessages.listen((message) => print('computer: $message'));
var requestInput = new StreamController<String>.broadcast();
requestInput.add('start'); // start with user
requestInput.addStream(computerMessages); // continue on computer response
return requestInput.stream.map((message) {
stdout.write('user: ');
return stdin.readLineSync();
});
}
But with this change my application terminates immediately with no message in stdout. What's wrong?
I found a solution. Create a normal instead of a broadcast StreamController in user:
Stream<String> user(Stream<String> computerMessages) {
computerMessages = computerMessages.asBroadcastStream();
computerMessages.listen((message) => print('computer: $message'));
var requestInput = new StreamController<String>();
requestInput.add('start'); // start with user
requestInput.addStream(computerMessages); // continue on computer response
return requestInput.stream.map((message) {
stdout.write('user: ');
return stdin.readLineSync();
});
}
Even though I found a solution, I sadly can not really explain what's the problem with a broadcast StreamController. null is successfully added by requestInput.add(null); but strangely neither requestInput.addStream(computerMessages); completes nor events of computerMessages are added to requestInput. Thus, requestInput is closed and the application terminates. I would appreciate if someone could provide further explanation.

JS-Interop : Attempting to use salesforce proxy

I'm trying to use Salesforce's sforce library to place an Ajax call to salesforce. Here is the example javascript that is working:
function setupPage() {
var state = { //state that you need when the callback is called
output : document.getElementById("output"),
startTime : new Date().getTime()};
var callback = {
//call layoutResult if the request is successful
onSuccess: layoutResults,
//call queryFailed if the api request fails
onFailure: queryFailed,
source: state};
sforce.connection.query(
"Select Id, Name, Industry From Account order by Industry",
callback);
}
function queryFailed(error, source) {
// not shown function code
}
function layoutResults(queryResult, source) {
// not shown function code
}
Here's my dart implementation:
import 'dart:html';
import 'package:js/js.dart' as js;
import 'dart:json';
void main() {
js.scoped(() {
var sforce = js.context.sforce;
var callbackSuccess = new js.Callback.once(success);
var callbackFailed = new js.Callback.once(failure);
var sfdc = new js.Proxy(sforce.connection.query("Select Id, Name, Industry From Account order by Industry"),
js.map({"onSuccess" : callbackSuccess, "onFailure" : callbackFailed}));
});
}
void success(queryResult) {
print("queryResult is: " + queryResult);
}
void failure(error) {
print("error is: " + error);
}
The Ajax call is being placed, as I see the POST request being made and returning data. However, I always seem to get this error (and I've tried countless different combinations):
Uncaught TypeError: object is not a function (program):370
construct (program):370
ReceivePortSync.dispatchCall darttest:178
$$._JsSendPortSync.callSync$1 minidartjs:4929
$.Proxy_Proxy$withArgList minidartjs:8194
$.Proxy_Proxy minidartjs:8183
$$.main_anon.call$0 minidartjs:6057
$.scoped minidartjs:8136
$.main minidartjs:8066
$$._IsolateContext.eval$1 minidartjs:276
$.startRootIsolate minidartjs:6533
(anonymous function)
Any help would be greatly appreciated, as I'm not sure where to turn at this point.
You get this error because you try to create a js.Proxy (sfdc) with the result of sforce.connection.query(...) . When you use new js.Proxy(f), f must be a js.Proxy of a js function. Here you get an object and that's why you get the error.
Here's the code that should work.
import 'dart:html';
import 'package:js/js.dart' as js;
import 'dart:json';
void main() {
js.scoped(() {
var sforce = js.context.sforce;
var callbackSuccess = new js.Callback.once(success);
var callbackFailed = new js.Callback.once(failure);
sforce.connection.query("Select Id, Name, Industry From Account order by Industry",
js.map({"onSuccess" : callbackSuccess, "onFailure" : callbackFailed}));
});
}
void success(queryResult, source) {
print("queryResult is: " + queryResult);
}
void failure(error, source) {
print("error is: " + error);
}

Resources