Is there a callback for port.postMessage() in WebExtenstions - web-extension

Is there a way to wait till the receiving party processes message sent using port.postMessage(message)? I'd expect something like callback passed as second argument similarly to chrome.scripting.executeScript(injection, callback)

To my knowledge not natively but a wrapper is easy to implement. You need a class that will generate a random UID (Unique ID) for each message and store a map { [uid]: cb }. Attach generated UID to the message. Response will also need to contain same UID.

Related

pyTelegramBotAPI pagination: how to pass a data between pages in a message

I have a Telegram bot for the forwarding of database requests. It returns long messages, so,
I use pagination from python-telegram-bot-pagination, for splitting this message to blocks. But I can't find a way to split the message to blocks effectively.
Now it looks like this:
by user request, the #bot.message_handler runs send_info_to_user function.
send_info_to_user calls the some_long_operation and gets the whole dataset as a result.
send_info_to_user gets a slice from some_long_operation result and sends it as a message for user
in case of using pagination inline buttons, the #bot.callback_query_handler will call send_info_to_user again
it re-calls the some_long_operation and gets the whole dataset again, just for another slice from the result and edit the content of the previous message.
# a time-consumable function
def some_long_operation(user_id):
return [f'some_text{i}\n{user_id}' for i in range(40)]
# send info to user by pages
def send_info_to_user(message, user_id, isCallback=False, page=1):
result = some_long_operation(user_id)
paginator = InlineKeyboardPaginator(
len(answer),
current_page=page,
data_pattern=f'{user_id}#'+'items#{page}' # wrap user_id for callback
)
if isCallback:
bot.edit_message_text(message.chat.id, result[page-1], message.message_id, paginator.markup)
else:
bot.send_message(message.chat.id, result[page-1],paginator.markup)
#bot.message_handler(content_types='text')
def message_reply(message):
send_info_to_user(message, message.from_user.id)
# parse callback from inline buttons
#bot.callback_query_handler(func=lambda call: call.data.split('#')[1]=='items')
def items_page_callback(call):
page = int(call.data.split('#')[2])
user_id = call.data.split('#')[0] # unwrap user_id
get_items(call.message, user_id, True, page)
Obviously, re-call of some_long_operation every time and using a slice of it isn't a good solution. But I can't find a way to pass the data between pages in a message.
The result of some_long_operation is user-specific and changes in time, so, store it anywhere isn't a good idea.
As I think, the some_long_operation should be called once, the result of it should be available as a slices for different pages of the message.

Do you need to save ParseUser before Cloud Function Calls?

I have an app on unity that uses ParseUser to store the user Level and Experience. When the user reaches a new Level a ParseCloud function call is made. However whenever user is retrieved via:
Parse.Cloud.define("LevelUp", function (request, response){
var user = request.user;
});
All the attributes in user have the values that are currently saved on the database, but not the ones that the ParseUser that made the request have in the Parse client.
Do I need to call ParseUser.CurrentUser.SaveAsync(); before every call to the server to get current user values or is there a way to send the dirty ParseUser values to the ParseCloud function and update them from that function.
Thanks!
Short answer yes.
Long answer: Not necessarily, but you need to wrap the unsaved (or dirty) attributes in an object and send it to ParseCloud, due the fact that you can't send ParseObject in a ParseCloud call.
In my case, I ended up changing the approach: retrieve the necessary
information about the level, and do the modifications on the ParseUser on the client.

How do I call a method on my ServiceWorker from within my page?

I have a ServiceWorker registered on my page and want to pass some data to it so it can be stored in an IndexedDB and used later for network requests (it's an access token).
Is the correct thing just to use network requests and catch them on the SW side using fetch, or is there something more clever?
Note for future readers wondering similar things to me:
Setting properties on the SW registration object, e.g. setting self.registration.foo to a function within the service worker and doing the following in the page:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
Results in TypeError: reg.foo is not a function. I presume this is something to do with the lifecycle of a ServiceWorker meaning you can't modify it and expect those modification to be accessible in the future, so any interface with a SW likely has to be postMessage style, so perhaps just using fetch is the best way to go...?
So it turns out that you can't actually call a method within a SW from your app (due to lifecycle issues), so you have to use a postMessage API to pass serialized JSON messages around (so no passing callbacks etc).
You can send a message to the controlling SW with the following app code:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
Combined with the following in the SW code:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
Which results in the following in my SW's console:
postMessage received Object {hello: "world"}
So by passing in a message (JS object) which indicates the function and arguments I want to call my event listener can receive it and call the right function in the SW. To return a result to the app code you will need to also pass a port of a MessageChannel in to the SW and then respond via postMessage, for example in the app you'd create and send over a MessageChannel with the data:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(event.data);
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
and then you can respond via it in your Service Worker within the message handler:
evt.ports[0].postMessage({'hello': 'world'});
To pass data to your service worker, the above mentioned is a good way. But in case, if someone is still having a hard time implementing that, there is an other hack around for that,
1 - append your data to get parameter while you load service-worker (for eg., from sw.js -> sw.js?a=x&b=y&c=z)
2- Now in service worker, fetch those data using self.self.location.search.
Note, this will be beneficial only if the data you pass do not change for a particular client very often, other wise it will keep changing the loading url of service worker for that particular client and every time the client reloads or revisits, new service worker is installed.

Linkedin API oAuth 2.0 REST Query parameters

I'm running into a problem with adding a query to the callback URL. I'm getting an invalid URI scheme error attempting to authorize the following string:
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=75df1ocpxohk88&scope=rw_groups%20w_messages%20r_basicprofile%20r_contactinfo%20r_network&state=7a6c697d357e4921aeb1ba3793d7af5a&redirect_uri=http://marktest.clubexpress.com/basic_modules/club_admin/website/auth_callback.aspx?type=linkedin
I've read some conflicting information in forum posts here. Some say that it's possible to add query strings to callbacks, and others say that it results in error.
If I remove ?type=linkedin, I can authorize just fine and receive the token. It would make my life so much easier if I could use a query string on the callback url, as I need to do some additional processing in the callback.
In short, can I append a query string to the end of the callback url?
For fun, I tried encoding the callback url in the request (obviously this is a no-no according to their documentation):
https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=75df1ocpxohk88&scope=rw_groups%20w_messages%20r_basicprofile%20r_contactinfo%20r_network&state=5cabef71d89149d48df523558bd12121&redirect_uri=http%3a%2f%2fmarktest.clubexpress.com%2fbasic_modules%2fclub_admin%2fwebsite%2fauth_callback.aspx%3ftype%3dlinkedin
This also resulted in an error but was worth a shot.
The documetation here: https://developer.linkedin.com/forum/oauth-20-redirect-url-faq-invalid-redirecturi-error indicates that you CAN use query parameters. And in the first request, it appears that I'm doing it correctly. Post #25 on this page - https://developer.linkedin.com/forum/error-while-getting-access-token indicates that you have to remove the query parameters to make it work
Anyone have experience with successfully passing additional query paramaters in the callback url for the linkedin API using oAuth2.0? If so, what am I doing wrong?
I couldn't wait around for the Linkedin rep's to respond. After much experimentation, I can only surmise that the use of additional query parameters in the callback is not allowed (thanks for making my application more complicated). As it's been suggested in post #25 from the question, I've tucked away the things I need in the "state=" parameter of the request so that it's returned to my callback.
In my situation, I'm processing multiple API's from my callback and requests from multiple users, so I need to know the type and user number. As a solution, I'm attaching a random string to a prefix, so that I can extract the query parameter in my callback and process it. Each state= will therefore be unique as well as giving me a unique key to cache/get object from cache..
so state="Linkedin-5hnx5322d3-543"
so, on my callback page (for you c# folks)
_stateString=Request["state"];
_receivedUserId = _stateString.Split('-')[2];
_receivedCacheKeyPrefix = _stateString.Split('-')[0];
if(_receivedCacheKeyPrefix == "Linkedin") {
getUserDomain(_receivedUserId);
oLinkedIn.AccessTOkenGet(Request["code"],_userDomain);
if (oLinkedin.Token.Length > 0) {
_linkedinToken = oLinkedin.Token;
//now cache token using the entire _statestring and user id (removed for brevity)
}
You not allowed to do that.
Refer to the doc: https://developer.linkedin.com/docs/oauth2
Please note that:
We strongly recommend using HTTPS whenever possible
URLs must be absolute (e.g. "https://example.com/auth/callback", not "/auth/callback")
URL arguments are ignored (i.e. https://example.com/?id=1 is the same as https://example.com/)
URLs cannot include #'s (i.e. "https://example.com/auth/callback#linkedin" is invalid)

(Perl/POE) In POE::Component::IRC, How do you return/get data from a package_state in an external subroutine?

I am trying to get the output data from a package_state in my IRC bot, which uses POE::Component::IRC as a base. But I just cannot seem to do it.
Basically, in a subroutine outside of the POE session, I wish to get the data from an event subroutine fired by POE when it receives the data from the server.
I've tried saving the data in a global array and even external file, but the outer subroutine will read the old data from it before that data gets updated.
More specifically, I am trying to get this bot to check if someone is 'ison' and if they are, return true (or get all data ( #_ ) from irc_303).
Something like this:
sub check_ison {
my $who = "someguy";
$irc->yield(ison => $who);
$data = (somehow retrieve data from irc_303);
return $data; #or true if $data
}
It sounds like you want a synchronous solution to an asynchronous problem. Due to the asynchronous nature of IRC (and POE, for that matter ...), you'll need to issue your ISON query and handle the numeric response as it comes in.
As far as I know, most client NOTIFY implementations issue an ISON periodically (POE::Component::IRC provides timer sugar via POE::Component::Syndicator), update their state, and tell the user if something changes.
You have options...
You could issue ISONs on a timer, save state appropriately in your numeric response handler, and provide a method to query the state. If your application looks more like a client (the user/something needs to be notified when something changes, that is) your numeric response handler could do some basic list comparison and issue appropriate events for users appearing/disappearing.
Otherwise, you could simply have a 'check_ison' that issues the ISON and yields some sort of 'response received' event from the numeric response handler, letting you know fresh data is available.