I'm using App engine Channel API with gwt-gae-channel library (v. 0.4) in GWT and i'm trying to test the recreation of a channel, after expiration (i.e. onError is called with code 401).
The test is:
- use GWT RPC method to create a channel (clientID= and expiration = 1 minute) and get the token needed: createTestChannel(useremail).
- call ChannelFactory.createChannel(token, new ChannelCreatedCallback() { ... }) and channel.open(new MySocketListener(){...})
- when onError(...) is called (channel expires) I try to call createTestChannel(useremail) again (to get a new token for the same clientID) and open a channel, but I always get onError() and onClose() called .
If I refresh the page or open a new tab with the same code, the first channel creation works ok, but after each channel expiration, I cannot recreate them. I also tried another clientID, but it wont work.
This is a known issue:
https://groups.google.com/forum/?fromgroups#!searchin/google-appengine-java/channel/google-appengine-java/kD3H6BWNYuA/NivXiDrqW7QJ
You must create a new channel on the server and get the new token. From the docs :
Tokens expire in two hours. If a client remains connected to a channel for longer than two hours, the socket’s onerror() and onclose() callbacks are called. At this point the client can make an XHR request to the application to request a new token.
http://code.google.com/appengine/docs/java/channel/overview.html#Tokens_and_Security
Related
I am wondering if there is a way to test to see if you are subscribed to a topic on the android side of things.
Basically, I am HOPING that all devices will subscribe to a topic during their installation, when the token is first obtained by the device. However, there is always a chance that the device fails to subscribe. The FCM registration token should be installed on the device for a long time, and thus, the onTokenRefresh() method shouldn't be called again without clearing data, uninstall/reinstall, etc.
My idea was to test to see if the device is subscribed to a topic in my MainActivity, and if not, then try to subscribe again. If it fails to subscribe, then get a new token and try again, etc.
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.e(TAG, "Refreshed token: " + refreshedToken);
// Subscribe to a topic
Log.e(TAG, "Subscribing to topic");
FirebaseMessaging.getInstance().subscribeToTopic("test");
So, I can subscribe and unsubscribe, but how do I check if the device is subscribed to a topic? I did my fair share of googling, and couldn't find anything, unfortunately.
I would greatly appreciate any/all assistance. Thanks!
There is currently no way to check on the client side if they are subscribed to a topic.
The behavior for subscribeToTopic is it would immediately subscribe to the specified topic, if it fails, it would retry on it's own (unless your app was killed). See my answer here.
I think that forcing the onTokenRefresh call just to make sure that subscribeToTopic is too much. You could simply just call it in your initial activity if you want, that way, everytime the app starts, it sends the subscription request.
Actually this can be done by using this api: https://developers.google.com/instance-id/reference/server#get_information_about_app_instances
As IID_TOKEN you need the FCM token and in the header you have to pass Authentication: key=YOUR_SERVER_KEY. You can find the server key as described here: Firebase messaging, where to get Server Key?.
Don't forget to include details=true as query parameter in the url, otherwise the topics won't be included in the response.
I would recommend writing a Cloud Function to encapsulate it, so you don't deploy your server key to the client.
I am writing an OPC UA client using Eclipse Milo and stumbled over the following question: how does the client handle the loss of connections.
For monitoring values I do this using a subscription with the SubscriptionManager:
OpcUaClient client = myCreateClient();
List<MonitoredItemCreateRequest> items = myCreateMonitoredItems();
UaSubscription subscription = client.getSubscriptionManager().createSubscription(1_000.0).get();
List<UaMonitoredItem> result = subscription.createMonitoredItems(TimestampsToReturn.Both, items).get();
for (UaMonitoredItem item : result) {
if (!item.getStatusCode().isBad()) {
item.setValueConsumer(value -> System.out.println("Update: " + value));
}
}
Now when I restart my OPC UA server, which is also implemented using Eclipse Milo, then I do see the client reconnecting, but the subscriptions don't get any more updates. In the log I get the following output:
09:11:15.734 [ua-shared-pool-0] DEBUG o.e.m.o.s.c.s.OpcUaSubscriptionManager - Publish service failure: StatusCode{name=Bad_NoSubscription, value=0x80790000, quality=bad}
java.util.concurrent.CompletionException: UaServiceFaultException: status=Bad_NoSubscription, message=There is no subscription available for this session.
<stack-trace-omitted>
…
So it seems that OpcUaSubscriptionManager is aware of the situation, but does not try to re-register those items. Is that to be done manually?
There is a flowchart that describes the reconnect sequence a client should follow in OPC-UA Part 4, Section 6.5. It involves attempting to re-use the same secure channel, attempting to re-activate the prior session, and even attempting to transfer subscriptions to a new session if that fails. The Milo client SDK does all of this.
Restarting the server is worst-case because it throws away all the state in the process, unlike a normal network interruption. In this case the client SDK will notify via callback that its attempts to restore state after reconnect have failed and that subscriptions must be re-created manually.
Add a SubscriptionListener to UaSubscriptionManager and if you receive the onSubscriptionTransferFailed callback then it's time to re-create the subscription and monitored items.
Actually for my server game I'm not using Netty. I've created a socket multithreaded system for send packet object who is serialized into and deserialized from (Int and Out)StreamBuffer.
I've discovered Netty and I think it's better to use it for my network system.
I've actually created a Client and Server handler (both extends ChannelInboundHandlerAdapter) to serialized and deserialized my packet from the ByteBuf, it's work FINE :) !
Now I want migrate my authentication system.
Actually, I've two Handler, the LoginHandler which can receive and process only the Login Packet (defined by an id when I send a buffer packet), and the ServerHandler which can receive and process all others packets.
Actual algorithme
Client side :
User launch a client a new window ask him to enter his username and password When he click on "Login", the client connect to the server, and after send a LoginPacket.
If a AuthServerPacket is sent by the server with the auth flag to true, he continue and open all others features.
If a AuthServerPacket is sent by the server with the auth flag to false, it display a popup with the reason, and re-open the window login.
Server side :
When a user is connecting to the server it's the LoginHandler which is attached to the client.
In this LoginHandler, only LoginPacket is processed, so, when it receive a LoginPacket it check the informations in a database, if these are correct, the client are added to the ServerHandler and deleted from the LoginHandler, and now he can receive and send all others packets.
ServerHandler send a AuthServerPacket with auth flag to true.
My question is, what is the best way to re-create this system with Netty ?
I don't know if I can add the login handler in the pipeline which it will be not check it if a channel is authentified. I don't know how or if the process is stopped if one of the handler reject the channel.
Someone can help me to understand what is the best way to do what I want with Netty ?
Thanks you in advance for your answers.
Programmatically, beaucoralk.
we talked on IRC #netty today :)
My suggestion is:
In your Pipeline Initializer, always add the LoginHandler
Once Login is successful, then the LoginHandler should:
ctx.pipeline.addAfter(this, "gameHandler", new GameLogicHandler());
ctx.pipeline.remove(this);
So basically your LoginHandler removes itself, after a successful authentication. Important: add the new Handler before removing the old Handler. :)
best regards
I've solved my problem with this :
In my Pipeline Initialize always add the LoginHandler (don't add my ServerHandler)
Once Login is successful, then the LoginHandler do :
ctx.pipeline.addLast(new GameLogicServerHandler());
ctx.pipeline.remove(this);
In fact I have not succeeded to use the addAfter like said Franz Bettag, no method was appropriate.
But thanks you to Bettag who help me to understand many things on #netty IRC.
Premise:
We have groovy scripts that execute every minute. I want one of those scripts to open an HTTP client, and poll a service bus queue / topic for messages. I have my rest client code working an getting messages from the service bus queue. I can do a "Get" every 5 seconds, and wireshark shows that it's reusing the same TCP connection which is better than I expected, but its still not ideal.
Goal:
I would like to make this http client do "long polling", for efficiency and to achieve actual real-time processing. It seems to be more complicated than I anticipated.
Problem:
When I do a "Delete" call to read message from a service bus queue, it immediately returns "HTTP/1.1 204 No Content", and the connection closes. I set a timeout on the client, but I don't think that matters.
Here's the article that shows service bus says it's supports long polling, which I imagine is the hard part. Azure Service Bus Queues
I feel that I don't understand something fundamental about how to implement long polling in code. My understanding is that when there is no data in the queue, it's supposed to delay the response until data exists, or until my client eventually times out waiting (which lets me set my own disconnect/reconnect interval). I don't even care about blocking/nonblocking etc, because the script execution is already spreadout into a threadpool, and will be terminated forcibly and all that.
Any help is greatly appreciated.
The correct and simple answer is that adding the following to the end of an Azure REST API URL (with service bus) is the way to implements long-polling with that service: ?timeout=60 , where 60 tells azure to wait 60 seconds before responding with no-data. So, your application can check for data every 60 seconds, with an internal timeout of 60 seconds on each HTTP request. This will hold the TCP connection open for that timeframe, waiting for an HTTP response.
For understanding long polling, I recommend you can learn the entry Comet of Wiki https://en.wikipedia.org/wiki/Comet_(programming). And there is an answered thread (Long polling in java) explained the mechanism of the HttpURLConnection Class support long polling in Java.
As I know, a simple way in Java Client instead of HttpURLConnection is using the client library of CometD. You can refer to the section Client Library of its offical document https://docs.cometd.org/current/reference/#_java_client to learn how to implement the long polling client in Java. You can download the library at https://download.cometd.org/.
The sample code from the offical document:
// Create (and eventually set up) Jetty's HttpClient:
HttpClient httpClient = new HttpClient();
httpClient.start();
// Prepare the transport
Map<String, Object> options = new HashMap<String, Object>();
ClientTransport transport = new LongPollingTransport(options, httpClient);
// Create the BayeuxClient
ClientSession client = new BayeuxClient("http://localhost:8080/cometd", transport);
// Here set up the BayeuxClient, for example:
// client.getChannel(Channel.META_CONNECT).addListener(new ClientSessionChannel.MessageListener() {
public void onMessage(ClientSessionChannel channel, Message message) {
if (message.isSuccessful()) {
// Here handshake is successful
}
}
});
client.handshake();
Note: There are two REST API of Azure Service Bus for getting messaging entity(s) Get Entity https://msdn.microsoft.com/en-us/library/azure/hh780754.aspx and Entities Discovery https://msdn.microsoft.com/en-us/library/azure/hh780782.aspx. You need to delete the used messaging entity manually thru the Delete Entity REST API. Requesting all of these REST API first require an access_token thru the post request the Request a Token from ACS API for secure access.
I have the following code (from the spring websocket demo app) :
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/queue/greeting', function(greeting) {
displayQueueMessage(greeting);
});
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("/app/wsdemo", {}, JSON.stringify({
'name' : name
}));
}
This is a simple subscribe call for a queue on the server, and another method "sendName()" that sends calls the server.
after sendName is called, the server response to the callback function supplied at the connect method:
function(greeting) {
displayQueueMessage(greeting);
});
My question is - how "long" should the client wait from the subscribe call until he can start calling sendName ? I mean, the potential issue i can see here is the following:
i) the client subscribes first for the queue,
ii) the client calls sendName
iii) the server recieves the 2nd call before he recieves the subscribe call.
iv) the response from the server will not be recieved by the client.
my questions:
1) is that scenario really is an issue?
2) how can i avoid it?
3) iv'e read somewhere that since websocket works with tcp, the order of messages is maintained, so my last question is - what about the fallback capability of stompJS for clients with no websocket support? will the order be maintained as well?
Since you subscribe to the queue during the connect phase, you just have to wait for the connection to be established before sending requests to the server.
I think you fix your problem and now know what is promise, callback and that javascript in asynchronous.
When you subscribe:
stompClient.subscribe('/user/queue/greeting', function(greeting) {
displayQueueMessage(greeting);
});
you pass callback function as second parameter, and when and only when subscribe happens (successful request) you callback will be executed.
You can avoid it if you will call sendName() in callback, or using any other approach to synchronize that two points.