-
Notifications
You must be signed in to change notification settings - Fork 5
Websocket Example
Here is the obligitory chat client example for websockets. Some of the advantages of STREST really show here.
First we create a new strest connection to the server and establish our callbacks for the connected and disconnected events:
strest = new Strest(
'ws://localhost:8000/websocket',
function(event) {
console.log("connected");
},
function(event) {
console.log("disconnected");
}
);Now that we have established a connection we want to register our username. Again the javascript is simple as can be, we only need to specify the uri and (optionally) some params, and register a response callback function.
strest.sendRequest({
uri : '/chat/register',
params : {'username' : $('#username').val()}
},
function(response) {
console.log("Got a response!");
onRegister();
}
);Then our controller looks like:
@Strest(
route = "/chat/register",
requiredParams = {"username"}
)
public class Register extends StrestController {
@Override
public void handleGET(DynMap params) throws StrestException {
String username = params.get(String.class, "username");
Users.instance().register(username, this.getTxnConnection());
this.response.setHeader(StrestUtil.HEADERS.TXN_STATUS, StrestUtil.HEADERS.TXN_STATUS_VALUES.CONTINUE);
}
}Most of the logic of the app happens in the Users singleton:
public class Users implements TxnCompleteCallback {
private static Users instance = new Users();
public static Users instance() {
return instance;
}
//All the users online now
protected ConcurrentHashMap<String, StrestConnectionTxn> onlineNow = new ConcurrentHashMap<String, StrestConnectionTxn>();
public void register(String username, StrestConnectionTxn con) throws StrestException {
if (onlineNow.putIfAbsent(username, con) != null) {
//already a user with that name
throw new StrestHttpException(501, "That username is taken");
}
//store the username in the connection local storage
con.getChannelStorage().put("username", username);
//We register a callback for when the connection is disconnected, so we
//can deregister.
con.onTxnComplete(this);
}
....
}STREST transactions are effective and scalable to use as event notification.
In this example we register for when our friends come online.
on the clientside it looks like this:
//register for connect events.
strest.sendRequest({uri : '/chat/notify/connect'},
function(response) {
alert(response.content + " just came online");
}
);And the corresponding Java
@Strest(
route = "/chat/notify/connect"
)
public class NotifyConnect extends StrestController {
@Override
public void handleGET(DynMap params) throws StrestException {
Users.instance().notifyConnect(this.getTxnConnection());
this.setSendResponse(false);
}
} and in the Users.java
//All the connections wanting connect notices
protected StrestConnectionGroup notifyConnect = new StrestConnectionGroup();
/**
* registers a callback for when users connect.
* connection is sent the list of currently online users as soon as they register for this callback.
*/
public void notifyConnect(StrestConnectionTxn con) {
String self = (String)con.getChannelStorage().get("username");
//Now that I am registered to recieve connect message, then I
//tell everyone else that I am online.
ResponseBuilder response = new ResponseBuilder();
response.txnStatus(StrestUtil.HEADERS.TXN_STATUS_VALUES.CONTINUE);
response.contentUTF8(self);
notifyConnect.sendMessage(response.getResponse());
this.notifyConnect.addConnection(con);
//now we send the user the list of all currently connected users
for (String username : this.onlineNow.keySet()) {
if (username.equals(self)) {
continue; //don't need to notify about self
}
response = new ResponseBuilder();
response.txnStatus(StrestUtil.HEADERS.TXN_STATUS_VALUES.CONTINUE);
response.contentUTF8(username);
con.sendMessage(response);
}
}You'll notice the use of the StrestConnectionGroup, this is a special class that allows us to efficiently send identical messages to groups of connections. It automatically discards connections when they get disconnected.
Strest-server contains a flash based websocket bridge for browsers that don't currently support websockets. The only thing to keep in mind is that flash now requires a 'socket policy' file to be hosted on port 843. Strest-server will automatically serve this file on the correct port (see example_config file), but many OS's lock down all ports below 1024, so you'll need to run as root (or do some fancy port forwarding). Otherwise it works great :). See we-socket-js
The full java sourcecode is available here: https://github.com/trendrr/strest-server/tree/master/src/com/trendrr/strest/examples/chat
The full javascript sourcecode is available here: https://github.com/dustismo/JsStrest/blob/master/chat.html
The excellent web-socket-js flash implementation: https://github.com/gimite/web-socket-js