I'm trying to fetch data from this link via Dart. Since I'm making use of dart:io library's HttpClientResponse based instance to listen to the data obtained from the above link, therefore I thought that an instance of StringBuffer would be the best option to capture the received data. It would help me to build the response string in an incremental fashion. But it seems like I'm not making proper use of StringBuffer, because in the end the response string (stored in receivedBuffer) remains empty.
Code:
import 'dart:io';
import 'dart:convert';
void main() async
{
StringBuffer receivedBuffer = new StringBuffer("");
String url = "https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty";
HttpClient client = new HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
print("[info] Fetch successful. Proceeding to transform received data ...");
response.transform(utf8.decoder).listen((contents) => receivedBuffer.write(contents));
print("[info] Done. Contents:\n");
print(receivedBuffer);
}
Output :
[info] Fetch successful. Proceeding to transform received data ...
[info] Done. Contents:
Also, instead of receivedBuffer.write(contents), if I were to write print(contents), then all the
required data is printed as one would expect it to. But while trying to write the contents to recievedBuffer it seems like receivedBuffer wasn't even updated once.
I read this article, and tried to incorporate the answer present over there in my code. To be precise, I made use of Completer instance to take care of my issue, but it didn't help.
What's the issue in the above provided code?
You are not waiting for the stream to complete.
In the listen call, you set up a receiver for stream events, but you don't wait for the events to arrive.
You can either add an onDone parameter to the listen call and do something there, but more likely you will want to just wait for it here, and then I recommend:
await response.transform(utf8.decoder).forEach(receivedBuffer.write);
Using forEach is usually what you want when you are calling listen, but not remembering the returned subscription. Alternatively use an await for:
await for (var content in response.transform(utf8.decoder)) {
receivedBuffer.write(content);
}
(which corresponds to a forEach call in most ways).
Related
Say I have a service worker that populates the cache with the following working code when its activated:
async function install() {
console.debug("SW: Installing ...");
const cache = await caches.open(CACHE_VERSION);
await cache.addAll(CACHE_ASSETS);
console.log("SW: Installed");
}
async function handleInstall(event) {
event.waitUntil(install());
}
self.addEventListener("install", handleInstall);
When performs cache.addAll(), will the browser use its own internal cache, or will it always download the content from the site? This is important, because it one creates a new service worker release, and there are new static assets, the old version maybe be cached by the service worker.
If not then I guess one still has to do named hashed/versioned static assets. Something I was hoping service workers would make none applicable.
cache.addAll()'s behavior is described in the service worker specification, but here's a more concise summary:
For each item in the parameter array, if it's a string and not a Request, construct a new Request using that string as input.
Perform fetch() on each request and get a response.
As long as the response has an ok status, call cache.put() to add the response to the cache, using the request as the key.
To answer your question, the most relevant step is 1., as that determines what kind of Request is passed to fetch(). If you just pass in a string, then there are a lot of defaults that will be used when implicitly constructing the Request. If you want more control over what's fetch()ed, then you should explicitly create a Request yourself and pass that to cache.addAll() instead of passing in strings.
For instance, this is how you'd explicitly set the cache mode on all the requests to 'reload', which always skip the browser's normal HTTP cache and go against the network for a response:
// Define your list of URLs somewhere...
const URLS = ['/one.css', '/two.js', '/three.js', '...'];
// Later...
const requests = URLS.map((url) => new Request(url, {cache: 'reload'}));
await cache.addAll(requests);
I have been working on this problem for a couple of days now, and feel like I'm extremely close to solving the issue. I need to cycle through an object and send a text message to each record in the object before moving on to the next line of code. The code to send works when isolated locally. But I'm having trouble getting it to work in Twilio Functions. All my code appears to work, but the text messages are not sent.
for await (const contact of allItems) {
client.messages
.create({
body: "Hey " + contact.name + "!" + " " + message,
messagingServiceSid: messaging_service,
to: contact.key
});
};
// End Send Message to Each Contact
I've attached the portion of code I believe I'm having issues with.
What I want to do, is for this piece of code to run completely before moving on to the next few lines and invoking a callback.
Any idea how I could do something like this?
Twilio developer evangelist here.
The issue here is that you are not awaiting the actual result of the asynchronous call. Locally, that doesn't matter, but within Twilio Functions once you call the callback function all asynchronous calls that have started are terminated.
To create a loop that makes asynchronous requests and waits for them all to complete you will want to use Promise.all in conjunction with map. In your example, it should look like this:
function SendMessages(allItems, message, client, messagingService) {
const apiRequests = allItems.map((contact) => {
let usersName = contact.name;
return client.messages.create({
body: `Hey ${usersName}! ${message}`,
messagingServiceSid: messagingService,
to: contact.key,
});
})
return Promise.all(apiRequests);
}
In this function we map over the list contacts returning the promise that is created when we try to send a message. The variable apiRequests becomes an array of promises that represent the requests to the API. We can then use this array of promises in Promise.all. Promise.all will only resolve once all the promises it is passed have resolved (or if a promise rejects).
I recommend you read my answer to your previous question as that brings up some further issues that you might have with this.
I am trying integrate the new Twitter API specifically the streaming tweets part in my android app, I am using Retrofit for my http calls.
When I try to make the call to get the streaming tweets it just hangs and does not return anything.
this is my retrofit call
#Streaming
#GET("tweets/search/stream")
suspend fun getFilteredStream(#Header("Authorization") token:String)
I then tried making a call with just OkHttp as shown in the documentation I get a successful response but I dont know how to stream the data.
I can make the call successfully via a curl call and see the data no problem.
How do I stream the data via retrofit or OkHttp
Update:
With OkHttp I was able to get data by doing this
val client: OkHttpClient = OkHttpClient().newBuilder()
.build()
val request: Request = Request.Builder()
.url("https://api.twitter.com/2/tweets/search/stream")
.method("GET", null)
.build()
val response: Response = client.newCall(request).execute()
val source = response.body?.source()
val buffer = Buffer()
while(!source!!.exhausted()){
response.body?.source()?.read(buffer, 8192)
val data = buffer.readString(Charset.defaultCharset())
}
data holds the string data representation of multiple tweet objects but how do I read one tweet at a time, or parse the response like this?
From the docs, I think you'll need to combine the two examples you have.
https://github.com/square/retrofit/blob/108fe23964b986107aed352ba467cd2007d15208/retrofit/src/main/java/retrofit2/http/Streaming.java
Treat the response body on methods returning {#link ResponseBody ResponseBody} as is, i.e. without converting the body to {#code byte[]}.
And example calling code
https://github.com/square/retrofit/blob/108fe23964b986107aed352ba467cd2007d15208/retrofit/src/test/java/retrofit2/CallTest.java#L599
I suspect, dependending on the JSON API you use you may be able to use a Streaming API from the response body. But if not you could split on either just newline or newline followed by { on next line and parse individually. Sorry I can't help here.
See https://en.wikipedia.org/wiki/JSON_streaming#Concatenated_JSON
I can see how to trigger the calculation of a spreadsheet using Microsoft Graph API here...
https://learn.microsoft.com/en-us/graph/api/workbookapplication-calculate?view=graph-rest-1.0&tabs=http
But, when I pull the results from the calculations they don't seem to be updated. However, I pull a second or third time, it is usually updated.
I assume this means that calculation hasn't finished b/c of the size of the file or complexity of the calcs.
However, being asynchronous, I'm not finding any way to check to see when the calculations have finished.
Any idea how to do this?
UPDATE 1:
This is the code I'm (now) using to create the session (per #UJJAVAL123-MSFT)
var persistChanges = false;
var wrkbk = await graphClient.Me.Drive.Items[strItemId].Workbook
.CreateSession(persistChanges)
.Request()
.PostAsync();
This will give me a value for 'id' like this...
cluster=US5&session=15.SN3PEPF000074ED1.A82.1.V24.7737Nwad4oPuVafaO%2fpAkiay14.5.en-US5.en-US26.10037ffe965d2cf2-Unlimited1.A1.N16.16.0.12904.3505114.5.en-US5.en-US1.V1.N0.1.A&usid=1b230e8f-3bd0-cdaa-2da6-47db74154075
I'm not exactly sure how/where to use this, or whether I use the entire thing (it looks like a query string) or if I'm supposed to parse and pull out one of the values...
cluster=US5
session=15.SN3PEPF000074ED1.A82.1.V24.xxxxxxxxxxxxxxxxx%2fpAkiay14.5.en-US5.en-US26.10037ffe965d2cf2-Unlimited1.A1.N16.16.0.12904.3505114.5.en-US5.en-US1.V1.N0.1.A
usid=1b230e8f-3bd0-cdaa-2da6-xxxxxxxxxxxx
and this is the code i'm using to trigger the calculation, but not sure how to connect the two...
var calculationType = "FullRebuild";
await graphClient.Me.Drive.Items[strItemId].Workbook.Application
.Calculate(calculationType)
.Request()
.PostAsync();
Also, I'm seeing that it is possible to create, refresh and close a session, but not entirely sure how to check on a specific async process inside that session.
Here is the code I'm using to check a specific range for a value, not sure where we pass the session-id here either...
var result = await graphClient.Me.Drive.Items[strItemId].Workbook.Worksheets[strSheetName]
.Range(strRangeName)
.Request()
.GetAsync();
UPDATE 2:
I can run an API call (presumably) in the same session successfully by passing the workbook-session-id (which is the ENTIRE string shown above) and I get the expected 204 No Content response. However, it is not clear from the c# Code Snippet in the Microsoft Graph Explorer how to pass the workbook-session-id in the request.
Here is the code it provides...
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
await graphClient.Me.Drive.Items["{item-id}"].Workbook.Application
.Calculate(null)
.Request()
.PostAsync();
So the question remains, how can I do a PostAsync or GetAsync and reference the workbook-session-id?
This code does NOT give me an error...
await graphClient.Me.Drive.Items[strItemId].Workbook.Application
.Calculate(calculationType)
.Request()
.Header("workbook-session-id",wrkbk.Id)
.PostAsync();
So now, the question is WHEN do I get the workbook-session-id? Do I get it when I initially open the workbook and then pass it to every call?
You should create a session and pass the session Id with each request. The presence of a
session Id in the requests ensures that you are using the Excel API in the most efficient
way possible.
Check here for API call to get a session
So after a decent amount of testing, i figured it out.
The answer is that you use the CreateSession method (https://learn.microsoft.com/en-us/graph/api/workbook-createsession?view=graph-rest-1.0&tabs=http) to get the workbook info, and you set the persistChanges setting, then you get back info about the workbook session.
Like this...
using Microsoft.Graph;
// strItemId = the id from the microsoft graph api of the item
// strUserId = the id of the user from the microsoft graph api (note: must have permissions set correctly)
public static async Task<WorkbookSessionInfo> GetWorkbookSessionId(string strItemId, string strUserId)
{
// true = you can see changes in the workbook
// false = don't update the workbook, just do calculations
var persistChanges = true;
try
{
var wrkbk = await graphClient.Users[strUserId].Drive.Items[strItemId].Workbook
.CreateSession(persistChanges)
.Request()
.PostAsync();
var result = wrkbk;
return result;
}
catch (Exception ex)
{
Console.WriteLine($"Error getting items: {ex.Message}");
return null;
}
}
And you are returned a WorkbookSessionInfo object, which includes the SessionId for use in subsequent calls. This way, it keeps all your calls in the same session!
https://learn.microsoft.com/en-us/graph/api/resources/workbooksessioninfo?view=graph-rest-1.0
As part of our project we need to call Twilio to get E164 format of the Phone Number. In order to do that I followed the below steps to achieve. If the phone number is valid then the below step is working but if the phone number is not valid and we are passing the same to Twillo then it is not returning anything back and halt the process.
I know that the below mention number is not valid but that doesn't mean when I am trying to lookup with invalid number it should not return any response. It should return at least an error but actually it is not which is making me more confused. I am trying with IBM websphere server.
Can some one please help me to fix this issue or is there any way where I can set request time out for twilio lookup so that it will allow other process to continue if any failures in twilio lookup. Also, correct me if I did any mistake in my coding for twilio lookup.
Sample URL "https://lookups.twilio.com/v1/PhoneNumbers/phoneNumber"
Steps Followed:
LookupsClient client = new LookupsClient(ACCOUNT_SID, AUTH_TOKEN);
client.setHttpClient(getProxyClient());
// Twilio Lookup with country code
String twilioURL = createURL(phoneNumber, countryCd);
String twilioE164Number = getTwilioNumber(client, twilioURL);
//Twilio Lookup without country code
StringBuilder appender = new StringBuilder();
appender.append(TWILIO_URL);
appender.append(PLUS);
appender.append(phoneNumber);
String twilioE164Number = getTwilioNumber(client, appender.toString());
//Create lookup URL
private String createURL(String phoneNumber, String countryCode){
StringBuilder appender = new StringBuilder();
appender.append(phoneNumber);
appender.append(QUERY_PARAM);
appender.append(countryCode);
return TWILIO_URL+appender.toString();
}
//Get Twilio E164 Number
private String getTwilioNumber(LookupsClient client,String url){
TwilioRestResponse response;
String twilioResult = "";
try {
response = client.get(url);
String str = response.getResponseText();
//Code for parsing the JSON response and set the twilioResult.
} catch (TwilioRestException e) {
logger.error("TwilioRestException while calling twilio "+e);
}catch(Exception ex){
logger.error("Error in twilio Calling "+ex);
}
return twilioResult;
}
//Get proxy client to set.
private HttpClient getProxyClient() {
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT);
//new DefaultHttpClient().getParams().setParameter(arg0, arg1)
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),new UsernamePasswordCredentials(ACCOUNT_SID, AUTH_TOKEN));
CloseableHttpClient httpClient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
return httpClient;
}
v6.3.0 of twilio-java has a LookupsClient has a .getPhoneNumber() method that allows you to pass a phone number instead of requiring that you construct the URL from scratch. The whole point of using LookupsClient instead of a vanilla TwilioClient is that the class does the bulk of the work for you.
Have you tried client.getPhoneNumber(phoneNumber) in this case? This page also demonstrates the structure of the response that you should receive when using that particular endpoint. The E164-formatted phone number should be the phone_number property in the response, although I use twilio-python and I don't know how the Java library exposes response objects for your consumption.
If you aren't getting a response at all, you might want to try making the same request without your proxy configuration to make sure the proxy isn't causing the problem. As for your timeout question, twilio-java's requests are processed synchronously, one way to get around that would be to wrap the request in an asynchronous method call.
Hope some of this helps you diagnose your issue!