I have implemented the browser push notification functionality and its working fine. I used this guide as the reference https://developers.google.com/web/fundamentals/getting-started/push-notifications/step-01?hl=en
However as payload is still not supported, I decided to query my server to get the notification data for each user which is also working fine.
There is one issue though. For some cases, after getting data from the server, I want to control whether to show the notification or not. I am not able to figure out how to do this. I tried returning false, throwing errors etc. But is always shows the default notification even if I don't call showNotification method. Let me know how to solve this. Following is the relevant code
self.addEventListener('push', function(event) {
event.waitUntil(
fetch('/getPushNotificationData/').then(function(response){
if (response.status !== 200) {
// I don't want to show any notification in this case
console.log('Looks like there was a problem. Status Code: ' + response.status);
throw new Error();
}
return response.json().then(function(data){
var shouldDisplay = data.shouldDisplay;
if (shouldDisplay=='1'){
var title = data.title;
var message = data.message;
var url = data.url;
return self.registration.showNotification(title, {
body: message,
data: url
});
}
else{
// I don't want to show any notification in this case also
return true;
}
});
})
);
});
Related
Just wondering if we are able to re-write data that we was set via the setWriteString() method while responding to an inbound api call. For example, let's say the scripted rest resource code is as follows:
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var body = request.body.data;
/* do something with request data
..
..
..
then start preparing the response
*/
var writer = response.getStreamWriter();
try
{
response.setContentType('application/json');
response.setStatus(200);
writer.writeString("{\"results\":[");
var inc = new GlideRecord('incident');
inc.query();
while(inc.next()){
var obj = {};
obj.id = inc.getValue('number');
obj.sys_id = inc.getUniqueValue();
writer.writeString(global.JSON.stringify(obj));
if (inc.hasNext()) {
writer.writeString(",");
}
}
writer.writeString("]}");
}
catch (ex)
{
// let's say exception was thrown on the 3rd iteration while gliding the incident table
// oh no...an exception..so we need to write something else to the stream
// is it possible to erase/remove everything that was added to the stream up until the exception occured?
// so that the response will contain details only about the error?
// something like below:
response.setContentType('application/json');
response.setStatus(500);
writer.writeString("{\"error\":\"Something went wrong\"}"); // this isn't working btw...the stream contained both the content generated in "try" block as well as the "catch" block
// this should not contain anything related to whatever was written from the earlier iterations....
}
})(request, response);
For the errors you can use the Scripted REST API Error objects.
Which should reset the output stream.
https://developer.servicenow.com/dev.do#!/learn/courses/paris/app_store_learnv2_rest_paris_rest_integrations/app_store_learnv2_rest_paris_scripted_rest_apis/app_store_learnv2_rest_paris_scripted_rest_api_error_objects
(function run(request, response) {
try {
...
} catch (e) {
var myError = new sn_ws_err.ServiceError();
myError.setStatus(500);
myError.setMessage('Something went wrong');
myError.setDetail('Error while retrieving your data: ' + e);
return myError;
}
})(request,response);
It might also be useful to get the error message from the GlideRecord
gr.getLastErrorMessage();
// something like aborted by businessrule or acl, etc...
For the details of your error message.
The Strophe onMessage handler that I added to the connection doesn't seem to trigger whenever a message gets send. I can't seem to find the problem. I can't find a lot of other info either and the info I do find seems to suggest my code is correct. I can send messages, so I know the connection works, but I cannot receive messages.
I create the connection like this, and then call the login function if a new connection is made:
XMPPChatConnection() {
if (this.#connection === undefined) {
this.#connection = new XMPPHelper.Strophe.Connection(
"wss://xxxxxxxxxxxxxxxxxxxxxxx",
{protocol: "wss"}
);
this.login();
}
return this.#connection;
}
The login function calls the chatListeners function which should setup all the listeners that are required when the user is logged in:
login() {
let jid = this.composeJabberIdentifier();
let token = this.getXMPPToken();
this.#connection.connect(jid, token, (status) => {
if (status === XMPPHelper.Strophe.Status.CONNECTED) {
this.chatListeners();
}
});
}
The messageListener is an imported function and currently only contains a console log:
import messageListener from "../classes/listeners/xmpp/chat/messageListener";
chatListeners() {
this.XMPPChatConnection().addHandler(messageListener, null, 'message', 'chat');
}
messageListener:
export default function messageListener(message) {
console.log(message);
}
What did I do wrong?
So I found the cause of my problems. I was using the Xabber client to send messages back, but it turned out Xabber sent the messages to the wrong resource.
On top of that I should have set my presence after login with a priority of >= 0.
this.XMPPChatConnection().send($pres().c("priority").t("0"));
I followed this tutorial ,to make Push notification on Google Chrome by using GCM. My problem is I'm unable to complete the operation! i have no idea why.
In subscribe function, it breaks out the function whenever it tries to execute
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// ...
};
});
It has no console error and no console warning and it doesn't enter the catch! Here is what I did:
function subscribe() {
var pushButton = document.querySelector('.js-push-button');
pushButton.disabled = true;
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function(subscription) {
// The subscription was successful
isPushEnabled = true;
pushButton.textContent = 'Disable Push Messages';
pushButton.disabled = false;
console.log("sending sub");
sendSubscriptionToServer(subscription);
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function(e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
pushButton.disabled = true;
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
pushButton.disabled = false;
pushButton.textContent = 'Enable Push Messages';
}
});
});
}
The only thing that did work for me is the 'getRegistration' method, used as the following code
navigator.serviceWorker.getRegistration('/Workers/').then( r => subscribe( r ) );
where '/Workers/' is the path where the ServiceWorker.js is
Been searching for solutions for hours and getting close to no luck. I just don't see much documentation on the matter of Parse Config. At least with solutions because I tried everything I could find.
So basically I'm trying to set a default picture when someone saves an object with a status as "denied."
It started with me looking at this: Set default profile picture for parse signup
And here's what I got.
//Accepts/denies picture request
Parse.Cloud.afterSave("Requests", function(request) {
var toUserId = request.object.get("to").id;
var fromUserId = request.object.get("from").id;
var toUser = null;
var fromUser = null;
var status = request.object.get("status");
if (status === "accepted") {
.....
} else if (status === "denied") {
Parse.Config.get().then(function(config) {
request.object.set('photo', config.get("denied"));
}).then(function() {
console.log('Success: Denied photo set.');
}, function(error) {
console.log('error: denied photo not set');
});
} else if (status === "waiting") {
....
}
});
I get a success everytime, but I get nothing as the photo file. I'm stuck and not sure what else to do here. The status changes to denied correctly, but I don't get anything to show up as a file in the photo spot, stays as undefined..
I2015-08-24T01:54:09.837Z]v46 after_save triggered for Requests for user oE3FhNfyWW:
Input: {"object":{"createdAt":"2015-08-24T01:54:03.398Z","from":{"__type":"Pointer","className":"_User","objectId":"odv4R9OWso"},"objectId":"InB8Iods8U","status":"denied","to":{"__type":"Pointer","className":"_User","objectId":"oE3FhNfyWW"},"updatedAt":"2015-08-24T01:54:09.834Z"}}
Result: Success
I2015-08-24T01:54:09.973Z]Success: Denied photo set.
I notice the code doesn't say request.object.save(), which might explain why the object isn't changed when you check later on.
But saving seems strange, since this function runs after saving. That's either wasteful or infinitely-loopy. Since the goal is to modify request.object (the object just saved), then do this on beforeSave().
Remember to call response.success() or .error() at the end of beforeSave().
Something about my use of chrome.hid.send seems to be leaving the bus in a bad state. I consistently can NOT get my second usage of the API call to work. Sometimes, it will also fail on the first usage. WITH THE EXACT SAME CODE, I can come back and try a while later (maybe 10min) and the first send will work.
The device I'm working with does not return a response to all messages sent to it. The test message for example, is just a dummy message that is ignored by the device. I've tested this both on a mac and a PC. My call stack depth is 2 at this point in my application (literally first one is kicked off by a button click and then a setTimeout calls the same method 5s later).
I've testing sending buffers of length 64Bytes as well as 58Bytes. The properties from the HidDeviceInfo object read "maxInputReportSize":64,"maxOutputReportSize":64
Params on first usage:
Params on second usage:
I really can't identify how I'm using the API incorrectly. When messages do succeed, I can see them on the device side.
// Transmits the given data
//
// #param[in] outData, The data to send as an ArrayBuffer
// #param[in] onTxCompleted, The method called on completion of the outgoing transfer. The return
// code is passed as a string.
// #param[in] onRxCompleted, The method called on completion of the incoming transfer. The return
// code is passed as a string along with the response as an ArrayBuffer.
send: function(outData, onTxCompleted, onRxCompleted) {
if (-1 === connection_) {
console.log("Attempted to send data with no device connected.");
return;
}
if (0 == outData.byteLength) {
console.log("Attempted to send nothing.");
return;
}
if (COMMS.receiving) {
console.log("Waiting for a response to a previous message. Aborting.");
return;
}
if (COMMS.transmitting) {
console.log("Waiting for a previous message to finish sending. Aborting.");
return;
}
COMMS.transmitting = true;
var dummyUint8Array = new Uint8Array(outData);
chrome.hid.send(connection_, REPORT_ID, outData, function() {
COMMS.transmitting = false;
if (onTxCompleted) {
onTxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '');
}
if (chrome.runtime.lastError) {
console.log('Error in COMMS.send: ' + chrome.runtime.lastError.message);
return;
}
// Register a response handler if one is expected
if (onRxCompleted) {
COMMS.receiving = true;
chrome.hid.receive(connection_, function(reportId, inData) {
COMMS.receiving = false;
onRxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '', inData);
});
}
});
}
// Example usage
var testMessage = new Uint8Array(58);
var testTransmission = function() {
message[0] = 123;
COMMS.send(message.buffer, null, null);
setTimeout(testTransmission, 5000);
};
testTranmission();
The issue is that Windows requires buffers to be the full report size expected by the device. I have filed a bug against Chromium to track adding a workaround or at least a better error message to pinpoint the problem.
In general you can get more detailed error messages from the chrome.hid API by enabling verbose logging with the --enable-logging --v=1 command line options. Full documentation of Chrome logging is here.