Configuring the Client for a Router
One of the first tasks of any Ice client is initializing a communicator. If you already have experience using another Ice language mapping, much of the following code will look very familiar:
The code above shows that we are setting the value of the property
Ice.Default.Router to a stringified proxy. The target object of this proxy has the identity Glacier2/router and the accompanying endpoint uses the transport type wss, meaning we intend to communicate with the router over a secure WebSocket connection at port 5064.
On the server end, the Glacier2 router employs our C++ WebSocket transport to accept connections on this port. In this case the chat client establishes a connection to the chat server router indirectly via a reverse proxy hosted at zeroc.com, but it's also possible to connect to an Ice server directly.
Creating a Session
A push client needs to establish a session with the Glacier2 router. In the code below, the client performs a checked cast on the router proxy, causing the Ice run time in the client to establish a connection and verify that the target object exists. Upon completion of the checked cast, the client receives the router proxy and calls
createSession, passing the credentials entered by the user:
The value returned by
createSession is a session proxy, which the code downcasts locally to the proxy type
ChatSessionPrx and passes to
run to continue the initialization process and execute the "main loop" of the application.
run function needs to make three asynchronous invocations. Two are remote calls to query the router for the session timeout and identity category, and the third is a local call to create an object adapter. In the latter case, calling
createObjectAdapterWithRouter has asynchronous semantics because the implementation may perform remote invocations. The client uses the
Promise.all function to execute these tasks:
all convenience function accepts any number of promises, and returns a new promise that completes only when all actions have completed successfully. The client can use
all here because there is no dependency among these actions, so they are essentially invoked simultaneously. When all actions have completed, the callback function receives their results.
Keeping a Session Alive
chat promise indicates the overall status of the client. If the close callback is invoked and the chat promise hasn't yet completed, it indicates that the connection with the server has been lost. The callback resolves the
chat promise by invoking
reject and passing it an exception with the cause of the failure.
In order to receive push notifications about chat activity, the client must register a callback. To do this, it must first create a servant and add it to the object adapter. The call to
adapter.add returns a proxy for the Ice object, which the client downcasts to the type
ChatRoomCallbackPrx prior to calling
setCallback on the session:
At this point, the client is ready to receive notifications. The servant, implemented here as the type
ChatCallbackI, defines methods corresponding to the operations on a Slice interface. Notice also the identity assigned to this servant; the identity category is the one we obtained earlier from the router. A Glacier2 client must use its assigned category in the identities of all callback objects for push notifications to be routed successfully.
Sending a Message
A new chat message is sent each time the user hits the Enter key in the
input text field. The client defines the following event handler:
The code extracts the message and passes it to the chat server by calling
session.send. The return value is a timestamp, which the client converts into a date and includes in the log message that it appends to the chat history.