I'm using a library called PubNub for posting messages. The PubNub method posts messages asynchronously, and it has a way to see if the message was posted or not.
I'm using Spring MVC and ThymeLeaf, so I would like to send the response back to my front-end after I get the message status (error or success), however, I don't know how to wait until my PubNub method finishes, and then send the result. Here's the code:
#Controller
public class HomeController {
#PostMapping("/triggerDevices")
public String triggerDevices(#ModelAttribute(value = "message") Message message, Model model) {
//
//
// validations and build data
//
//
MyResult result = null;
//Async method
pubNub.publish()
.message(message)
.channel(channel)
.async((result, status) -> {
//This block takes some time
if (status == null || status.isError()) {
//Error case
result = new MyResult (false, status.errorMessage(),message.device);
} else {
//Success case
result = new MyResult (true, null, message.device);
}
});
//Result
model.addAttribute("result", result);
return "home :: info-success";
}
}
I hope someone helps me, thanks so much.
PubNub Java SDK Publish sync
Just use the sync method instead of async
PNPublishResult result = pubnub.publish()
.channel("coolChannel")
.message("test")
.shouldStore(true)
.ttl(10)
.sync();
See full PubNub SDK Java Docs for publish/sync.
That should do it for you.
Cheers!
Using sync is an easy fix! but if u need to keep it async, i would return within the async function result here after you get the result:
//Success case
result = new MyResult (true, null, message.device);
model.addAttribute("result", result);
return "home :: info-success";
Related
I am using software.amazon.awssdk version 2.18.21 to invoke Lambda function from spring boot application. While invoking Lambda function which takes approx 2-3 minutes to finish throws Http status 504: Gateway Time-out Exception.
I have been suggested to use Asynchronous Call to invoke Lambda function and then read the response. How can i convert this existing code to asynchronous call and get response to verify if it was success or error?
//imports from
import software.amazon.awssdk.http.ApacheHttpClient;
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.services.lambda.model.InvokeRequest;
import software.amazon.awssdk.services.lambda.model.InvokeResponse;
//Calling Lambda Function
try{
LambdaClient client = LambdaClient.builder().httpClientBuilder(ApacheHttpClient.builder()
.maxConnections(100)
.socketTimeout(Duration.ofSeconds(60))
.connectionTimeout(Duration.ofSeconds(60))
).build();
InvokeRequest req = InvokeRequest.builder().functionName("abc").build();
InvokeResponse res = client.invoke(req);
String respnonse = res.payload().asUtf8String();
System.out.println(response);
}catch(Exception e){
e.printStackTrace();
}
Edited: Tried below but unable to implement CompletableFuture. Can you suggest how to implement it for Lambda function and get response
try{
SdkAsyncHttpClient client = NettyNioAsyncHttpClient.builder().readTimeout(Duration.ofSeconds(60)).connectionTimeout(Duration.ofSeconds(60)).build();
LambdaAsyncClient lambdaClient = LambdaAsyncClient .builder().httpClient(client).build();
InvokeRequest req = InvokeRequest.builder().functionName("abc").invocationType("EVENT").build();
CompletableFuture<InvokeResponse> request = lambdaClient.invoke(req);
//InvokeResponse res = client.invoke(req);
//String respnonse = res.payload().asUtf8String();
//System.out.println(response);
}catch(Exception e){
e.printStackTrace();
}
To perform Lambda operations using Asynchronous calls with the Java V2 API, use this:
LambdaAsyncClient
The call the invoke method:
https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/lambda/LambdaAsyncClient.html#invoke(software.amazon.awssdk.services.lambda.model.InvokeRequest)
The patten to use Async methods are similar no matter what the service use. For example, most calls involve using CompletableFuture. Then you code the logic you want within the whenComplete code block.
To learn about the patterns, read this part of the Java V2 DEV Guide:
Asynchronous programming
For example, this code example is from that topic.
public class DynamoDBAsyncListTables {
public static void main(String[] args) throws InterruptedException {
// Create the DynamoDbAsyncClient object
Region region = Region.US_EAST_1;
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder()
.region(region)
.build();
listTables(client);
}
public static void listTables(DynamoDbAsyncClient client) {
CompletableFuture<ListTablesResponse> response = client.listTables(ListTablesRequest.builder()
.build());
// Map the response to another CompletableFuture containing just the table names
CompletableFuture<List<String>> tableNames = response.thenApply(ListTablesResponse::tableNames);
// When future is complete (either successfully or in error) handle the response
tableNames.whenComplete((tables, err) -> {
try {
if (tables != null) {
tables.forEach(System.out::println);
} else {
// Handle error
err.printStackTrace();
}
} finally {
// Lets the application shut down. Only close the client when you are completely done with it.
client.close();
}
});
tableNames.join();
}
}
I am building a JAVA HTTP Adapter, I am authenticating the user in UserAuthenticationSecurityCheck class using the following method
#Override
protected AuthenticatedUser createUser() {
return new AuthenticatedUser(userId, logonId, this.getName(), attributes);
}
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
return false;
}
After this control goes to android app then they call the REST API called /updateClientRegistrtion which will update the ClientRegistrationData
#GET
public Response updateClientRegistartion(#Context HttpServletRequest request) {
AuthenticatedUser authUser = securityContext.getAuthenticatedUser();
Map<String, Object> attributes = authUser.getAttributes();
ClientData clientData = securityContext.getClientRegistrationData();
clientData.getProtectedAttributes().put(some parameter);
if (clientData.getClientId() != null) {
securityContext.storeClientRegistrationData(clientData);
}
But this code is giving me error like
Exception Message :
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
Is there any solution to this problem? Can someone please help me with this.
Tutorial followed : http://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/authentication-and-security/user-authentication/security-check/
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
results when concurrent requests try to store attributes into the same row or the data in the row being modified by another request before it was updated.
This could be from the request being fired more than once ( in close proximity).Another possibility is that while one request was working on the data in memory, another had already modified and updated it.
The code should still work without the line:
securityContext.storeClientRegistrationData(clientData);
Try that out.
Alternatively, put a try-catch around the
storeClientRegistrationData(clientData)
and retry in the catch block.
I am a newbie (6 months going or so) and creating an app on Android (Java) that utilizes FireBase Auth with Google Sign In. (with only a few days of NodeJS exposure now) In other words my end user signs in with the Google Account. That part (I think) works pretty well so far. I use the Firestore Database heavily for a lot of things in the app.
So now I've gotten to the point where I want to use (Callable) Cloud Functions with HTTP Triggers. (never having done any of this before) I'm trying to get a proof of concept working at this time. The actual function works and I can trigger it from my app.
It appears that I cannot figure out how to make the function "private" though; as in "adding proper Members" to the Cloud function who have the right to invoke the function.
I have tried a few different things by trial error, but first let me show what I have.
This is the Cloud Function and I'm passing in an arbitrary String as a test, works nicely: (as long as "allUsers" have the role/right to invoke the function; in other words when the function is public.
exports.createTest = functions.https.onCall((data, context) => {
const text = data.text;
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const email = context.auth.token.email || null;
console.log('UID: ', uid);
console.log('Name: ', name);
console.log('Email: ', email);
console.log('Message: ', text);
});
The above function gets triggered in my Android/Java code like this: (I think this code came from Google Doc/Sample/Example
private FirebaseFunctions mFunctions;
...
private void testing() {
mFunctions = FirebaseFunctions.getInstance();
Log.e(LOG_TAG, "Testing executed!");
String testMessage = "Hello Hello Testing 123 Mic Check";
createTest(testMessage)
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
Log.e(LOG_TAG, "FFE: " + ffe.getMessage() );
Log.e(LOG_TAG, "Code: " + code);
Log.e(LOG_TAG, "Details:" + details);
}
// ...
}
// ...
}
});
}
private Task<String> createTest(String text) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("text", text);
data.put("push", true);
return mFunctions
.getHttpsCallable("createTest") //this is the function name
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
String result = (String) task.getResult().getData();
if (result != null) {
Log.e(LOG_TAG, "Result: " + result);
}
return result;
}
});
}
Only when I have "allUsers" added with the role/right to "invoke Cloud Function" then I get this working. My understanding of HTTP Requests and such is pretty limited, which is not making things easier.
I tried using the "allAuthenticatedUsers" options, which I figured would do the trick, because I actually authenticate my Users in the app through Firebase/Google Sign In. This Cloud Function shall only be available to either a) authenticated users or b) users of a specific domain. (I have a domain, let's say #testorganization.com) Or if I can identify my particular app (api key?) then that would work, too.
The moment I add a member "allAuthenticatedUsers" with role to invoke the function (and remove "allUsers) nothing happens. I also tried adding the entire domain, but that wouldn't work. (duh) Also tried adding my service account (trial and error at this point) and didn't seem to work.
In my Node JS code I am actually receiving the UID of the authenticated user, so it appears that some kind of user authentication information is already being exchanged.
With that knowledge, I can (successfully tried this) get the UID and cross check that against my database and verify a user that way, but seems unnecessary and I should be able to make the permissions work. (lock the function down entirely) Plus this took a really long time just finish this cross check. Or is this pretty standard procedure to do?
Like this-->
const usersRef = admin.firestore().collection('users').doc(uid)
usersRef.get()
.then((docSnapshot) => {
if (docSnapshot.exists) {
usersRef.onSnapshot((doc) => {
console.log('User Type logged in: ', doc.data().userCategory)
console.log('User Title: ', doc.data().userTitle)
});
} else {
console.log('User does not exist')
}
});
Edit:
So while not having figured out how to shut down the function entirely, I did discover that instead of cross checking my users, I can simple check for auth like this:
if (context.auth){
//user is auth'd
} else {
//no auth
}
That's a little bit better, I guess. (but still doesn't technically prevent access to the function?!)
Thank you so much for any help. Much appreciated.
Edit2:
Here is a screensshot of the area in the cloud console (for cloud function roles/privileges) that I am referring to:
https://imgur.com/cBsjaaL
With a Callable Cloud Function, if you want to ensure that only authenticated users can trigger it's business logic, you actually don't need to configure any extra "cloud function roles/privileges" as shown at the bottom of your question.
By default, with a Callable Cloud Function you will get, when available, "Firebase Authentication and FCM tokens automatically included in requests" and it will "automatically deserializes the request body and validates auth tokens", as explained in the doc.
So you just have to follow the doc and use the context parameter. As you have mentioned in your question, you can check the user is authenticated by doing:
if (context.auth) {
//...
}
If you want to verify the user email, you would do:
exports.addMessage = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return admin.auth().getUser(uid)
.then(userRecord => {
const userEmail = userRecord.email;
//....
})
.catch(function(error) {
console.log('Error fetching user data:', error);
// Send back an error to the front end
// See https://firebase.google.com/docs/functions/callable#handle_errors
});
});
You will find more examples on how to "work with" users with the Admin SDK here in the doc.
I have 3rd party code that I connect to via DataInputStream. The 3rd party code continually spits out information as it generates it. When something of interest comes across I want to pass it along to GraphQL Subscription(s)
I'm not sure how to wire the 3rd party code to the server-side GraphQL subscription code given this scenario. Any suggestions would be appreciated.
Some conceptual code is below:
public void liveStream(DataInputStream in) {
// Sit and constantly watch input stream and report when messages come in
while(true) {
SomeMessage message = readFromInputStream(in);
System.out.println("Received Message Type:" + message.getType());
// Convert SomeMessage into the appropriate class based on its type
if (message.getType() == "foo") {
Foo foo = convertMessageToFoo(message);
} else if (message.getType() == "bar") {
Bar bar = convertMessageToBar(message);
} else if (howeverManyMoreOfThese) {
// Keep converting to different objects
}
}
}
// The client code will eventually trigger this method when
// the GraphQL Subscription query is sent over
VertxDataFetcher<Publisher<SomeClassTBD>> myTestDataFetcher() {
return new VertxDataFetcher<> (env, future) -> {
try {
future.complete(myTest());
} catch(Exception e) {
future.fail(e);
}
});
}
OK, I wrapped my liveStream code in an ObservableOnSubscribe using an executorService and I'm getting back all the data. I guess I can now either pass it straight through to the front end or create separate publishers to deal with specific object types and have graphql subscriptions point to their respective publishers.
ExecutorService executor = Executors.newSingleThreadExecutor;
ObservableOnSubscribe<SomeClassTBD> handler = emitter ->
executor.submit(() -> {
try {
//liveStream code here
emitter.onComplete();
}
catch(Exception e) {
emitter.onError(e);
}
finally {
// Cleanup here
}
});
Observable<SomeClassTBD> = Observable.create(handler);
I have a Java Web application with Tomcat 8 (not android), Java 8 and Firebase Admin version 5.2.0.
The below code works fine however I need to be sure that task is complete and return a value.
#POST
#Path("/verifyToken")
#Produces(MediaType.APPLICATION_JSON)
public Response verifyToken(#Context HttpHeaders headers,#Context HttpServletRequest request) {
try {
String auth = headers.getRequestHeader("authorization").get(0);
if (!auth.isEmpty()) {
System.out.println("logged auth token: " + auth);
}
// validate token
Task<FirebaseToken> task = FirebaseAuth.getInstance().verifyIdToken(auth)
.addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decoded) {
String uid = decoded.getUid();
//do some stuff
}
});
/*
The return statement below shouldn't run unless "task" is
complete.
task has method isComplete()
*/
return Response.status(200).entity(user).build();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Login Exception " + e.getMessage());
return Response.status(500).build();
}
}
Task object (task) has a method "isComplete()". However, it may need to be called more than once. If in first time the task is not complete, the code should know how to wait and call it again later and this way on until certain number of times.
I'm stuck in how to build the logic to properly wait and try again until task is complete or event quit the condition.
How to do it?
I highly recommend you check out Doug Stevenson's excellent series of blog posts on the Task API. This specific problem is covered in https://firebase.googleblog.com/2016/10/become-a-firebase-taskmaster-part-4.html
The solution seems to be Tasks.await(task)....
i'm using Tasks.await() to wait firebase task finish.
example in kotlin to get token:
var task = FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener {}
Tasks.await(task)
var token = task.result!!.token