We are trying to run the sample app for push notifications with some modification to get it to send out a broadcast notification, but it is not getting sent.
We have modified the PushBackendEmulator code as well. The emulator invokes the submitBroadCastNotification procedure successfully and the following result is returned:
Server response :: /-secure-{"result":"Notification sent to all
users","isSuccessful":true}/
However, it appears the WL.Server.sendMessage method is not sending the message and returns. I am not able to see the server side logs either after a thorough search on the liberty server except for the messages.log on the liberty server which shows the following when WL.Server.sendMessage is called.
ht.integration.js.JavaScriptIntegrationLibraryImplementation E
FWLSE0227E: Failed to send notification. Reason: FPWSE0009E: Internal
server error. No devices found [project worklight]
Here is the adapter code:
function submitBroadcastNotification( notificationText) {
var notification = {};
notification.message = {};
notification.message.alert = notificationText;
//notification.target = {};
//notification.target.tagNames = ['test'];
WL.Logger.debug("broadcast: " + notification.message.alert );
var delayTimeOut = **WL.Server.sendMessage**("PushNotificationsApp", notification);
WL.Logger.debug("Return value from WL.Server.sendMessage :"+ delayTimeOut);
return {
result : "Notification sent to all users"
};
}
Here is the PushBackendEmulator code:
public static void main(String [] args){
String serverUrl =
"http://208.124.245.78:9080/worklight";
String notificationText = "Hellofrombroadcastingnotifications";
String userId = "admin";
notificationText = notificationText.replace(" ", "%20");
Logger.debug("sending broadcast notification: " + notificationText);
URL url = new URL(serverUrl
+ "/invoke?
adapter=PushAdapter&procedure=submitBroadcastNotification¶meters=['" + userId + "','" + notificationText + "']");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(10000);
connection.setDoOutput(true);
Logger.debug("Connected to server");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = "";
String inputLine;
while ((inputLine = in.readLine()) != null)
response+= inputLine;
Logger.debug("response is:"+ response);
in.close();
Logger.debug("Server response :: " + response);
connection.disconnect();
Looking at your application from the PMR, it seems to me like you have mixed both event source-based notifications and broadcast notifications.
If you want to use Broadcast notifications, this means you cannot try imposing sending the notification to any specific userId, etc as it is not needed nor based on userIds.
By default, all devices are auto-subscribed to a tag called "push.ALL".
You can read more about broadcast notifications API methods in the IBM Worklight Knowledge Center.
This is a modified version of your application, tested in iOS and Android: https://www.dropbox.com/s/l2yk2pbvykrzfoh/broadcastNotificationsTest.zip?dl=0
Basically, I stripped away from it anything not related to broadcast notifications:
I removed the push securitytest from application-descriptor.xml
I removed any function from the adapter XML and JS files and main.js file that is related to event source-based notifications.
The end result is that after the app is loaded, you are right inside the application (no login).
I then right-clicked the adapter folder in Studio > invoke procedure, and selected the submitBroadcastNotification option to send the notification ("aaa").
In the device, a notification was received. Tapping it (if the app is closed) launches the application, which then triggers the WL.Client.Push.onMessage API in common\js\main.js to display alerts containing the payload and props of the received notification.
This was tested in both iOS and Android.
As the application was loading, I could see in LogCat and Xcode console the token registration.
To test this in iOS, you will need to update application-descriptor.xml with your own pushSender password and add your own apns-certificatae-sandbox.p12 file.
To test in Android, make sure you are have generated a browser key in the GCM console and are using it in application-descriptor.xml
For both, make sure that all requires ports and addresses and accessible in your network
Related
I have an mqtt broker in an android APP. I can connect to it from my nodeMCU (microPython) and publish and check messages.
I created an android app using Xamarin. Forms and I create a MQTT client like this :
IMqttClient client;
string topic = "test/msg";
var configuration = new MqttConfiguration();
this.client = await MqttClient.CreateAsync("192.168.110.51", configuration);
this.client.Disconnected += (o, e) => Debug($"disconnection (at client level)! {e.Message} and {e.Reason} ");
var state = await client.ConnectAsync(new MqttClientCredentials(clientId: "tester"));
await client.SubscribeAsync(topic, MqttQualityOfService.AtLeastOnce);
client
.MessageStream
.Subscribe(msg => Debug($"Message received in topic"));
I created a button that does this :
var msg = new MqttApplicationMessage(topic, Encoding.UTF8.GetBytes("HELO"));
await client.PublishAsync(msg, MqttQualityOfService.AtLeastOnce);
I then test the whole environment and it happens that when I publish from Xamarin I can read the HELO at the MCU, but not from the Xamarin (that's subscribed to the channel) and If I publish from the nodeMCU I can read from other nodeMCU but NOT from the Xamarin.
I tried subscribing to "#" to listen to anything, anyhow nothing appeared.
Any suggestion ??
UPDATE 1:
I tested with MQTT.fx and I can read all messages outputted from both nodeMCU (python) and Phone (Xamarin) and I can also publish messages and nodeMCU (Python) will receive them whilst Xamarin will not notice :(
I am trying to connect to Google's MQTT server but I am getting errors
I created all the certificates and registered my device (Adafruit huzzah32)
and the documentation says you connect to mqtt.googleapis.com:8883
So I do
WiFiClientSecure wifi;
MQTTClient client;
client.begin("mqtt.googleapis.com", 8883, wifi);
When I try to connect I use the device path
const char* jwt = "{json web token}";
const char* device = "projects/{project-id}/locations/{cloud-region}/registries/{registry-id}/devices/{device-id}";
Serial.print("Connecting to mqtt");
while (!client.connect(device,"unused",jwt)) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.println("Connected to mqtt");
but it never connects
I verified the google certificate by calling
openssl s_client -showcerts -connect mqtt.googleapis.com:8883
and I put in my RSA Private key and certificate key that was made
wifi.setCACert(googleCertificate2);
wifi.setCertificate(myCertificate);
wifi.setPrivateKey(privateCert);
What am I doing wrong?
Here is the connection documentation
https://cloud.google.com/iot/docs/how-tos/mqtt-bridge
Update
I made a quick java example to see if I can connect going off the example they have for connecting and I get a MqttException saying Bad user name or password (4)
Here is the code for that
private void doStuff(){
String clientId = String.format("ssl://%s:%s", "mqtt.googleapis.com", 8883);
String mqttClientId = String.format("projects/%s/locations/%s/registries/%s/devices/%s","{project_id}", "us-central1", "{register}", "{device}");
MqttConnectOptions connectOptions = new MqttConnectOptions();
connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
Properties sslProps = new Properties();
sslProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
connectOptions.setSSLProperties(sslProps);
connectOptions.setUserName("unused");
try{
String jwt = createJwtRsa("{project-id}");
connectOptions.setPassword(jwt.toCharArray());
MqttClient client = new MqttClient(clientId, mqttClientId, new MemoryPersistence());
while(!client.isConnected()){
try{
client.connect(connectOptions);
}catch (MqttException e) {
e.printStackTrace();
}
}
Log.d("","");
}catch (Exception e){
e.printStackTrace();
}
}
private String createJwtRsa(String projectId) throws Exception {
DateTime now = new DateTime();
JwtBuilder jwtBuilder =
Jwts.builder().setIssuedAt(now.toDate()).setExpiration(now.plusDays(1000000).toDate()).setAudience(projectId);
byte[] keyBytes = readBytes(getAssets().open("rsa_private_pkcs8"));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey k = kf.generatePrivate(spec);
return jwtBuilder.signWith(SignatureAlgorithm.RS256, k).compact();
}
As you can see here I have the IoT service acount added to IAM
Does that mean my keys that I generated with openssl are incorrect?
My problem ended up being that I was trying to set a really large expiration date on my Json Web Token (on purpose so I didnt have to keep generating new ones since I have not found a way to do that in arduino) and it looks like that google's mqtt server does not accept anything over a day so the keys will have to be updated daily.
Also inorder to connect to the MQTT server I had to change the buffer size of the MqttClient on the arduino to have a buffer size of 1024 bytes.
MQTTClient client(1024);
anything less I would get an error saying buffer isnt big enough.
here the IAM roles are being explained ...the paragraph here sounds alike what you describe:
On the IAM page in Google Cloud Platform Console, verify that the role Cloud IoT Core Service Agent appears in the Members list for the relevant project service account. (Look for the project service account that ends in #gcp-sa-cloudiot.iam.gserviceaccount.com.)
If the Cloud IoT Core Service Agent role does not appear in the Members list, use gcloud to add the cloudiot.serviceAgent role to the relevant project service account. This role includes permission to publish to Pub/Sub topics.
if not yet having installed it, the Cloud SDK is required for all those gcloud CLI commands, which can be used to list & edit the configurations (of which all can be done through the console, as well)... it's maybe easier, because all of the examples there use it, too.
update ...
concerning JWT refresh tokens, see this article or have some Q & A or the specification: JSON Web Token (JWT), JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants.
here's another relevant article: https://medium.com/google-cloud/refreshing-json-web-tokens-jwts-for-google-cloud-iot-core-897318df3836
Here is the piece of code :
//Publishing the topic
snsClient.Publish(new PublishRequest
{
Subject = Constants.SNSTopicMessage,
Message = snsMessageObj.ToString(),
TopicArn = Settings.TopicArn
});
I am getting the below error :
The underlying connection was closed: A connection that was expected
to be kept alive was closed by the server.
And here is the screenshot of detailed error:
But not able to get an idea how to solve this. Any hint or link will helpful.
We had the exact same issue happen to us. We got this error about 40 times a day, which was less than 0.1% of the successful push notifications we sent out.
Our solution? Update the AWSSDK NuGet package from 1.5.30.1 to 2.3.52.0 (the latest v2 release for ease-of-upgrade). As soon as we updated, the errors stopped happening. I looked through lots of release notes and couldn't find anything specifically mentioning this issue. We have no idea why the update worked, but it did.
I hope this helps you and anyone else fix this issue.
This problem may occur when one or more of the following conditions are true:
• A network outage occurs.
• A proxy server blocks the HTTP request.
• A Domain Name System (DNS) problem occurs.
• A network authentication problem occurs.
[https://nilangshah.wordpress.com/2007/03/01/the-underlying-connection-was-closed-unable-to-connect-to-the-remote-server/]1
make sure your payloads size should not exceed more than 256 kb
make sure you had configured timeout property of the PutObjectRequest
Take a look sample aws sns request code (from https://stackoverflow.com/a/13016803/2318852)
// Create topic
string topicArn = client.CreateTopic(new CreateTopicRequest
{
Name = topicName
}).CreateTopicResult.TopicArn;
// Set display name to a friendly value
client.SetTopicAttributes(new SetTopicAttributesRequest
{
TopicArn = topicArn,
AttributeName = "DisplayName",
AttributeValue = "StackOverflow Sample Notifications"
});
// Subscribe an endpoint - in this case, an email address
client.Subscribe(new SubscribeRequest
{
TopicArn = topicArn,
Protocol = "email",
Endpoint = "sample#example.com"
});
// When using email, recipient must confirm subscription
Console.WriteLine("Please check your email and press enter when you are subscribed...");
Console.ReadLine();
// Publish message
client.Publish(new PublishRequest
{
Subject = "Test",
Message = "Testing testing 1 2 3",
TopicArn = topicArn
});
// Verify email receieved
Console.WriteLine("Please check your email and press enter when you receive the message...");
Console.ReadLine();
// Delete topic
client.DeleteTopic(new DeleteTopicRequest
{
TopicArn = topicArn
});
I'm trying to send email from an ASP.NET using my SendGrid account. It works on my dev machine, but not in production, even though the credentials are the same. Likewise, in production I can connect to the SMTP server via telnet (using base64 encoded credentials), but the ASP site can't connect--I get error "Unauthenticated senders not allowed."
I've tried a mix of port numbers (25, 587, 465 -- my site is SSL). Using port 465 times out. 25 and 587 return respond immediately--but with the login error. This is really baffling because, like I say, it's the same credentials on dev machine and production.
I looked very briefly at Microsoft Network Monitor 3.4, but could not make heads or tails of it. I was hoping it would tell me the blow-by-blow commands being sent since I suspect the web site is doing something a little different from how telnet connects, but I don't know what.
Note I also asked my web host if outgoing traffic on these ports were blocked on production firewall, but they aren't.
Here's the actual code--like I say works fine on localhost, but SMTP connection fails in production
[AllowAnonymous]
[HttpPost]
public ActionResult ResetPasswordSend(string email)
{
List<string> userList = new List<string>();
try
{
string[] invalidChars = new string[] { ";", "," };
foreach (var invalidChar in invalidChars) if (email.Contains(invalidChar)) throw new Exception("Email contains invalid character.");
int count = 0;
// since emails are not unique, I must launch resets for all of them
var users = _db.HsProfile.Query("[Email]=#0", SqlDb.Params(email));
foreach (var profile in users)
{
count++;
userList.Add(profile.UserName);
var token = WebSecurity.GeneratePasswordResetToken(profile.UserName, 15);
WebMail.Send(profile.Email, "HumaneSolution.com Password Reset for user " + profile.UserName,
"You received this email because you or someone with your email address requested a password reset on HumaneSolution.com. " +
"If you didn't do this, then you don't need to take any action, and nothing will happen.\n\n" +
"To proceed with the password reset, click the link below within 15 minutes:\n\n" +
Url.BaseUrl("Account/EnterNewPassword/" + token) + "\n\n" +
"Sent to: " + email + " at " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\n" +
"User name: " + profile.UserName);
}
if (count == 0) throw new Exception("Email " + email + " is not registered at HumaneSolution.com.");
}
catch (Exception exc)
{
ViewBag.Error = exc.Message;
}
return View(userList);
}
Based on suggestion from SendGrid, I re-wrote the email code so it does not use WebMail.Send but rather the SmtpClient and MailMessage objects explicitly. SendGrid says there might be some kind of timing problem in how ASP.NET loads credentials from the config file automatically. Here's exactly what they said:
Are you by chance storing your SendGrid credentials in a configuration file, separate from the code that connects to our SMTP server? The reason I ask is because I have seen rails and C# configurations like this receive the unauthenticated error due to the credentials not being passed at the correct time. Usually this is solved by moving the credentials directly in with the code instead of a separate configuration file. Give that a try and see if you notice a difference.<<
I didn't follow their advice completely -- i.e. I'm still using config file, but I'm loading the config values in subclasses of SmtpClient and MailMessage so I avoid hardcoding creds in my app. Anyway, it worked, all is well again.
I am trying to send SMS from twilio account. Here is my code.
try
{
string ACCOUNT_SID = ConfigurationManager.AppSettings["XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"];
string AUTH_TOKEN = ConfigurationManager.AppSettings["XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"];
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
client.SendSmsMessage("+1XXXXXXXXXX", "+1XXXXXXXXXXX", "Hi");
Label1.Text = "Sent Successfully";
}
catch (Exception ex)
{
Label1.Text = "Error:"+ex.Message;
}
Running on my server, I am receiving message "Sent Successfully" but not receiving message on my phone.
I have changed the original numbers with "XXXXX".Also I have added packages for Twilio.
Please let me know if can.
Twilio evangelist here.
You might be getting an error back from the Twilio REST API when you make the call to SendSmsMessage. You can check if this is happening by grabbing the value returned from the method and seeing if the RestException property is null or not:
var result = client.SendSmsMessage("+1xxxxxxxxxx", "+1xxxxxxxxxx", "Hi");
if (result.RestException!=null)
{
//An error occured
Console.Writeline(result.RestException.Message);
}
Another option would be to use a tool like Fiddler to watch the actual HTTP request/response as it happens and see if any errors are happening.
Hope that helps.