Is there any possibility to send an ActiveMQ message from a browser using amq ajax, including a topic and a specific selector?
I have an app in 2 parts:
PART 1 --> Web client is listening on a topic:
var myHandler = function(message) {console.log(message);}
amq.addListener('amqlistener', 'topic://mytopic', myHandler);
PART 2 --> Web app sends different orders to this topic:
amq.sendMessage('topic://mytopic', myData);
Very simple and all works OK.
Now, I need to filter some messages, so I have put a selector in the PART 1 like this:
amq.addListener('amqlistener', 'topic://mytopic', myHandler, {selector:"dev='xxxxx'"} );
and here is (in PART 2) where I don't get the way to send a message including this specific selector.
Any help is well welcome :)
You don't send with selectors, you send with headers/properties that the selector can use to filter out messages.
amq has a function that looks like this:
var sendJmsMessage = function(destination, message, type, headers)
It accepts headers. I would supply your header 'dev' with value 'xxxxx' there.
Related
I'm building WeChat Mini-Program that on one of it's pages has web-view control. For example:
page.wxml
<web-view src="https://..." bindmessage="onWebViewMessage"></web-view>
page.js
const app = getApp();
Page({
onWebViewMessage:function(e) {
console.log(e);
},
onLoad:function() {
}
});
In web-view an HTML page is loaded (index.html), that includes jweixin-1.3.2.js lib from WeChat, for connecting with WeChat API as well as connect to parent Mini-program. Page is empty, no DOM elements, just javascript that will execute when document is loaded.
It has it's javascript something like this:
index.js
document.addEventListener('DOMContentLoaded',function(){
wx.miniProgram.postMessage({data:'test'});
});
I am able to post messages from this document to mini-program without issues. Also can send some mini-program navigation commands such as wx.miniProgram.navigateTo({url:'path/to/page'}); so all seems fine. I can also get callback in Mini-program when web-view has completed loading.
Question:
How can I post message from Mini-program to web-view? For example, to pass a string or an Object to the web-view.
I have been googling for hours and can't seem to find anyone doing it, but I can't believe it's just one-way communication possible.
Any help or idea is appreciated!
I have found an effective way to pass data from mini-program to web-view content, and it seems at this moment in time, this is the only possible way to do it.
Mini-program
1. Base64 module
You will need to be able to convert normal String into Base64 string. Mini-program API has a method for converting byte array into base64 string, but that won't be usable for this purpose. So, create your own module that does that:
File: lib/b64.js
var string2base64 = function(str) {
.... here put your js code for making b64 string ....
return result;
};
module.exports = {
string2base64
};
2. Page with Web-View
In the page that has web-view control, prepare DOM element in wxml file like this:
File: pages/xxx/index.wxml
<web-view src="{{webURL}}" bindload="onWebLoad" binderror="onWebError"></web-view>
Notice that src parameter is now bound to page's webURL property. Whenever page sets value to this property, will automatically be applied to the DOM elemenet.
In file pages/xxx/index.js you will need to add base64 module:
const b64 = require('../../lib/b64.js')
note that require path may vary depending how you have setup your project
and in page's data object, add webURL and webBaseURL properties, like this:
Page({
data: {
webURL:'',
webBaseURL:'https://your/web/app/url',
messageQueue:[],
messageQueueSize:0,
.... other page properties go here ....
},
..... rest of your page code goes here .....
})
Notice that webURL is set to be empty. This means that when page loads, an empty string will be set to DOM object by default.
webBaseURL will explain just in a bit.
messageQueue is an Array that will store pending messages to be sent to web-view.
messageQueueSize is just Array length. Used for better performance, to avoid reading Array.length.
3. Start Message Queue
In onShow callback of the page, set webURL and start interval that will read messageQueue Array every 250ms. You can change the way this is done if you dislike using intervals, this was just simplest way to do theory test.
onShow: function(){
// This will start loading of the content in web-view
this.setData({webURL: this.data.webBaseURL } );
// Sends message from message queue to web-view
let _this = this;
setInterval(function(e) {
if( _this.data.messageQueueSize < 1 ) return;
_this.data.messageQueueSize --;
let msg = _this.data.messageQueue.splice(0,1);
_this.setData({webURL: _this.data.webBaseURL+"#"+msg});
},250);
}
You can see that message is appended to web-view source (url) as a hash.
webBaseURL is used to generate final URL with hash, that is then send to web-view.
4. Add a Message to the Queue
To create a message in message queue, just define following method in your page:
addMessageToQueue: function(obj) {
obj.unique = Math.round(Math.random()*100000);
let msg = b64.string2base64(JSON.stringify(obj));
this.data.messageQueue.push(msg);
this.data.messageQueueSize++;
}
Whenever you call this method, just pass an Object with whatever properties you need it to have, and it will be converted into JSON string, then to base64 string, and finally appended to the message queue.
unique property is added to make generated base64 result always different even if the rest of object properties are the same - I just needed this for the purpose of my project. You can ignore it / remove it if you do not need it.
Since there's interval running and checking on the message queue, all messages added like this will be sent to web-view in the same order they were added to the queue.
Now there's only one thing left - to add hash change listening in the HTML page we have loaded into the web-view:
HTML Web-app
1. Listen to hash change
window.addEventListener("hashchange",function(e){
let messageBase64 = window.location.hash.substr(1);
let json = window.atob( messageBase64 );
let data = JSON.parse(json);
console.log("Received data from mini-program:",data);
});
Tested on Xiaomi Mi8 Pro. I am yet to test on other devices sold in China.
Cheers!
I've got a web service under development that uses Django and Django Channels to send data across websockets to a remote application. The arrangement is asynchronous and I pass information between the 2 by sending JSON formatted commands across websockets and then receive replies back on the same websocket.
The problem I'm having is figuring out how to get the replies back to a Javascript call from a Django template that invokes a Python function to initiate the JSON websocket question. Since the command question & data reply happen in different Django areas and the originating Javascript/Python functions call does not have a blocking statement, the Q&A are basically disconnected and I can't figure out how to get the results back to the browser.
Right now, my idea is to use Django global variables or store the results in the Django models. I can get either to work, but I beleive the Django global variables would not scale beyond multiple workers from runserver or if the system was eventually spread across multiple servers.
But since the reply data is for different purposes (for example, list of users waiting in a remote lobby, current debugging levels in remote system, etc), the database option seems unworkable because the reply data is varying structure. That, plus the replies are temporal and don't need to be permanently stored in the database.
Here's some code showing the flow. I'm open to different implementation recommendations or a direct answer to the question of how to share information between the 2 Django functions.
In the template, for testing, I just have a button defined like this:
<button id="request_lobby">Request Lobby</button>
With a Javascript function. This function is incomplete as I've yet to do anything about the response (because I can't figure out how to connect it):
$("#request_lobby").click(function(){
$.ajax({
type: "POST",
url: "{% url 'test_panel_function' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}', button:"request_lobby" },
success: function(response){
}
});
});
This is the Django/Python function in views.py . The return channel for the remote application is pre-stored in the database as srv.server_channel when the websocket is initially connected (not shown):
#login_required
def test_panel_function(request):
button = request.POST.get('button', '')
if button == "request_lobby" :
srv = Server.objects.get(server_key="1234567890")
json_res = []
json_res.append({"COMMAND": "REQUESTLOBBY"})
message = ({
"text": json.dumps(json_res)
})
Channel(srv.server_channel).send(message)
return HttpResponse(button)
Later, the remote application sends the reply back on the websocket and it's received by a Django Channels demultiplexer in routing.py :
class RemoteDemultiplexer(WebsocketDemultiplexer):
mapping = {
"gLOBBY" : "gLOBBY.receive",
}
http_user = True
slight_ordering = True
channel_routing = [
route_class(RemoteDemultiplexer, path=r"^/server/(?P<server_key>[a-zA-Z0-9]+)$"),
route("gLOBBY.receive" , command_LOBBY),
]
And the consumer.py :
#channel_session
def command_LOBBY(message):
skey = message.channel_session["server_key"]
for x in range(int(message.content['LOBBY'])):
logger.info("USERNAME: " + message.content[str(x)]["USERNAME"])
logger.info("LOBBY_ID: " + message.content[str(x)]["LOBBY_ID"])
logger.info("OWNER_ID: " + message.content[str(x)]["IPADDRESS"])
logger.info("DATETIME: " + message.content[str(x)]["DATETIME"])
So I need to figure out how to get the reply data in command_LOBBY to the Javascript/Python function call in test_panel_function
Current ideas, both of which seem bad and why I think I need to ask this question for SO:
1) Use Django global variables:
Define in globals.py:
global_async_result = {}
And include in all relevant Django modules:
from test.globals import global_async_result
In order to make this work, when I originate the initial command in test_panel_function to send to the remote application (the REQUESTLOBBY), I'll include a randomized key in the JSON message which would be round-tripped back to command_LOBBY and then global_async_result dictionary would be indexed with the randomized key.
In test_panel_function , I would wait in a loop checking a flag for the results to be ready in global_async_result and then retrieve them from the randomized key and delete the entry in global_async_result.
Then the reply can be given back to the Javascript in the Django template.
That all makes sense to me, but uses global variables (bad), and seems that it wouldn't scale as the web service is spread across servers.
2) Store replies in Django mySQL model.py table
I could create a table in models.py to hold the replies temporarily. Since Django doesn't allow for dynamic or temporary table creations on the fly, this would have to be a pre-defined table.
Also, because the websocket replies would be different formats for different questions, I could not know in advance all the fields ever needed and even if so, most fields would not be used for differing replies.
My workable idea here is to create the reply tables using a field for the randomized key (which is still routed back round-trip through the websocket) and another large field to just store the JSON reply entirely.
Then in test_panel_function which is blocking in a loop waiting for the results, pull the JSON from the table, delete the row, and decode. Then the reply can be given back to the Javascript in the Django template.
3) Use Django signals
Django has a signals capability, but the response function doesn't seem to be able to be embedded (like inside test_panel_function) and there seems to be no wait() function available for an arbitrary function to just wait for the signal. If this were available, it would be very helpful
I have a Node.js REST API service and I have a resouce - Link for example.
To get all links I use GET /links
To submit new link I use POST /links
To get one link by linkid I use GET /links:id
Each link have an array of Tags and I need a REST style URI to get the links by tag value. What will be REST style URI in this case ?
For getting the links of a certain tag you can define the following route:
/tags/:tagID/links
And for getting tags of a certain link:
/links/:linkID/tags
I think it should be:
GET /links/:id/tags
that should return all the tags related to the link with id ":id"
If you like to work with your tags as a separated thing you could do it like this:
GET /tags ==> retrieve all tags.
GET /tags/:id ==> retrieve tag with id..
GET /tags/links/:id
Also resftull is not strict, and some times, the resource, or action that you need to execute does not fit in that schema, and you can create a custom method:
GET /tags/get-for-link-id/:id => retrieve tags related to a link
That example is pointless, but consider that you are having a complicated route with so much params eg:
GET /tags?q=return&state=active&sort=date if this request is repeated so much times, for your api customer it would be pleasant to have a custom alias like GET /tags/activeByDate
It depends. TYou can do something like /blah:{tagId}/ (which is perfectly valid URI as well). Or you can do /links/?tagID={id} and so on. I don't prefer the already mentioned hierarchical URI /tags/{id}/links, I think a flat URI is much better. If the relationship has attributes as well, then you can use /tag-link-relationships/{relationshipId} or /tag-link-relationships/tag:{tagId}/ or /tag-link-relationships/?tag={tagId} etc...
From client perspective the URI structure does not matter, because the client follows the hyperlinks the service responds with (aka. uniform interface / HATEOAS constraint).
off: Almost every day we got this question, at least try to search next time.
Here is a sample code
GmailApp.sendEmail("email#example.com", "mail subject", "mail body");
after the call I can see a sent message in my gmail account and that has a ID like this 147f7e77a4efed11 I want to retrieve this ID for the sent mail via the above code
sendEmail method returns an instance of GmailApp which is useful for chaining actions but no way to get the ID of the sent email.
what I am doing now is to perform a search and take the first message. But I am sure that is not a reliable way.
example
var message = GmailApp.search("to:email#example.com", 0, 1)[0].getMessages()[0];
now I can get the ID of the message and perform the desired actions.
Is it possible to retrieve the message or the ID of the message without an unreliable search?
After building your service, you can use the messages.list and then filter them like you would when searching in GMail, you can also use labels to get only sent mails etc.
messages = gmail_service.users().messages().list(userId='me', q="subject:mail subject deliveredto:email#example.com", maxResults=1).execute()
if messages['messages']:
for message in messages['messages']:
print 'message ID: %s' % (message['id'])
If you pass through the email you're searching for and other "unique" references as arguments in a Python function it makes it a lot more versatile too.
Edit: After talking with you I think that creating your own personal ID/reference for each email sent would be the most prudent method of retrieval. I recommend using faker, they have a javascript version and I use faker for all of my data needs. There's plenty of documentation for it and then you can filter your list according to how you set your ID.
you can use the new gmail api directly. you will need a manual oauth flow to get the token, then use urlFetch to make the call. https://developers.google.com/gmail/api/v1/reference/users/messages/send
it returns a message resource with its id. might also be possible to do this with advanced services but i havent tried. i have done it with urlfetch and worked ok.
Can you set the Message-Id header on the email? (Not sure if the apps scripts allows that or overwrites it or not.) If so, I'd generate a unique Id that way and you can look it up using a search "rfc822msgid:".
create a draft first, then send it
function sendEmail(opts) {
let draft = GmailApp.createDraft(recipient=opts.recipient, subject=opts.title, {
htmlBody: opts.msg,
});
draft.send()
let ret = {
id: draft.getId(),
messageId: draft.getMessageId(),
}
console.log('sendEmail results: ', ret )
return ret
}
2022 Update
GmailDraft.send() returns a GmailMessage you can use that to label the sent message.
Example:
const draft = GmailApp.createDraft('Foo <foo#bar.com>','Lorem Ipsum','Dolor Sit Amet');
const label = GmailApp.getUserLabelByName('Test');
const msg = draft.send();
const thrd = msg.getThread();
label.addToThread(thrd);
google-apps-script solution working for sent messages with methods: GmailApp, MailApp
enable Gmail service
use the code:
var messages = Gmail.Users.Messages.list(
"me", {q: "subject:Test Me", maxResults: 1}
).messages;
console.log(messages[0].id)
On every page of my sites, I am using AJAX to poll the server and retrieve a list of messages. The server maintains a list of messages and the SessionId (I'm in an ASP.NET environment, but I feel like this question is applicable to any server side technology) that the message is intended for. If a message is found for the particular SessionId, it is returned to the client side script. I use a JavaScript library to create a notification (using noty, a Jquery Notification Plugin). Once it returns a particular message, the server discards that message.
This works well if the user only has a single tab/window open for a particular site. However, let's say they have two open and they do something that causes a warning message to be generated. I have no control over which tab the notification goes to, so the user may not end up seeing the warning message.
Is there a way of uniquely identifying a browser tab? Then I could pass this as one of the parameters in my AJAX call.
Firstly, polling doesn't seem good mechanism. It might hit your server down when you have large number of active users. Ideally you should return a message in the response to the request that was result of invalid action.
Still below solution might work for you. It is inspired by the reply of #SergioGarcia.
Keep a hidden input just before the end of your form tag, which stores a unique ID for identifying a tab uniquely. You will store the messages on server session against unique tabID,
<input type="hidden" id="hiddenInputTabId" value="<%=getValue()%>" />
and then define getValue.
function string getValue() {
var v = getValueFormBodyOrAccessValueDirectlyByMakingInput_a_ServerSideControl();
if (string.IsNullOrWhiteSpace(v)) {
return Guid.NewId();
} else {
return v;
}
}
Because it is a hidden input you should get it's value in the POSTed form body, and for ajax requests below snippet should take care of sending that value in header which you can access on server side.
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("tabId", $('#hiddenInputTabId').val());
},
});
Same header can be check while returning the response to your polling requests and only respond message available against the provided tabId should be responded.
You can add a query string parameter called tabId and control it's binding to tab using javascript.
There is a functional prototype below:
$(function () {
// from: https://developer.mozilla.org/en-US/docs/Web/API/Window.location
function getQueryStringParameter (sVar) {
return decodeURI(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURI(sVar).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
}
// from: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
function newGuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
window.tabId = getQueryStringParameter('tabId');
// tabId not defined, reload the page setting it
if (!window.tabId) {
window.tabId = newGuid();
}
// on click set the tabId of each link to current page
$(document).on('click', 'a', function (e) {
var $this = $(this);
var newLocation = $(this).attr("href");
// In page links
if (newLocation.match(/^#.+$/)) {
return;
}
// Outbound links
if (newLocation.match(new RegExp("^https?")) && !newLocation.match(new RegExp("^https?://" + window.location.host))) {
return;
}
// Insert tab id
if (newLocation.match(/(\?|&)tabId=[0-9a-f-]+/)) {
newLocation.replace(/(\?|&)tabId=[0-9a-f-]+/, (newLocation.indexOf('?') == -1 ? "?" : "&") + "tabId=" + window.tabId);
} else {
newLocation += (newLocation.indexOf('?') == -1 ? "?" : "&") + "tabId=" + window.tabId;
}
window.location.href = newLocation;
e.preventDefault();
});
});
If you enter a page in your application without setting the tabId parameter on query string, it will be set to a new UUID (Guid).
When the page has a tabId parameter on query string, it defines the window.tabId variable inside your page and you can use that in your application.
When the user click on any link in your page, a javascript event will be triggered and the link url will be redirected to match the current tabId. An right click to open in new tab or a middle click will not trigger that event and the user will be sent to a new tab without the query string parameters, so the new page will create a new tabId in that page.
You can see it working here: http://codepen.io/anon/pen/sCcvK
You can do it by generating a unique tab id with javascript by loading your client.
I strongly recommend you to use something for intertab communication, like intercom.js, which can broadcast the messages from a single tab with a single connection to every other tabs. Intertab works with socket.io, which has long polling fallback, so it may be good in your current system as well. I agree that polling is a poor choice, and you should use websockets instead.
If you use ZMQ on the server, then in the browser you can use NullMQ either (for websockets ofc). I think it does not have intertab support, so you should make your own intertab solution to make it work. It is not so hard to write such a system, you need only a common storage, for example localStorage, but it can be even cookie... If you don't have a storage event, you have to ping that storage for changes with setInterval. You have to store there the messages, and which tab broadcasts them (probably in a semaphore) and when was the last time it pinged the storage. After that you can keep each tab in sync with the others, or by using a unique tab id, you can send customized messages to any of the tabs. If the broadcast tab has a storage timeout (it did not ping the storage for a long while), then it is probably closed, so you should assign the broadcast service to another tab.
So what I ended up doing was changing how my notification framework functioned in order to prevent the need for identifying unique tabs. It's just too hard to layer information on the stateless web.
Instead of using Ajax to pump messages out to the client instantly, I build them up on each page into a List<Message> property. On PreRender I render them to the client with ClientScript.RegisterStartupScript(). But if I need to send the user to another page, I started using Server.Transfer() instead of Response.Redirect() instead so that it will preserve the message queue. The new page checks the old page to see if it exists and if is the correct Type. If it is the correct type, I cast it and retrieve the message queue from the old page and add them to the new page's queue. And since Server.Transfer() doesn't update the URL on the client, I also added a JavaScript function to manually push the state to the URL in supported browsers.
I know I took this in a little different direction than I did on the question, but I think I had been approaching it wrong in the beginning.