Skip to content
dustismo edited this page Apr 21, 2011 · 4 revisions

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");
	}
);

Register a username

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);
	}
	
        ....

}

Event Callbacks

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.

Flash Websocket Bridge

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

Links

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

Clone this wiki locally