Creating Room Modules with JavaScript
The following steps describe how to deploy an example JavaScript room module on Union Server. The module is a chat bot that sends "hello" and "goodbye" greetings to all users that join and leave a chat room. (See also Creating Room Modules with Java.)
Step 1: Write the module
Add the code below to a new file named "GreeterBot.js", and save that file in Union Server's /modules/ directory.
importClass(net.user1.union.core.event.RoomEvent); importClass(net.user1.union.api.Client); var moduleContext; var wrapper; // This method must be implemented by every room module script. function init(ctx, wrap) { moduleContext = ctx; wrapper = wrap; // This is a script, so we have to register for // events through the room's wrapper. wrapper.addRoomEventListener(RoomEvent.ADD_CLIENT, "onRoomAddClient"); wrapper.addRoomEventListener(RoomEvent.REMOVE_CLIENT, "onRoomRemoveClient"); } function onRoomAddClient(evt) { var args = ["Welcome Guest" + evt.getClient().getClientID()]; moduleContext.getRoom().sendMessage("CHAT_MESSAGE", args); } function onRoomRemoveClient(evt) { var args = ["Goodbye Guest" + evt.getClient().getClientID() + "."]; moduleContext.getRoom().sendMessage("CHAT_MESSAGE", args); } // This method must be implemented by every room module script. function shutdown() { wrapper.removeRoomEventListener(RoomEvent.ADD_CLIENT, "onRoomAddClient"); wrapper.removeRoomEventListener(RoomEvent.REMOVE_CLIENT, "onRoomRemoveClient"); }
Step 2: Deploy the GreeterBot module
Room modules can be deployed at runtime via client-side code or at server-startup time via union.xml. In this example, we'll deploy the GreeterBot module using client-side code, first in ActionScript, then in JavaScript. In ActionScript, a room's modules are specified via the RoomManager's createRoom() method. For example,
var modules:RoomModules = new RoomModules(); modules.addModule("GreeterBot.js", ModuleType.SCRIPT); chatRoom = reactor.getRoomManager().createRoom("chatRoom", null, null, modules);
The following code uses the preceding technique to deploy the GreeterBot module in a chat application for the room named "chatRoom".
package { import flash.display.Sprite; import flash.events.KeyboardEvent; import flash.text.TextField; import flash.text.TextFieldType; import flash.ui.Keyboard; import net.user1.reactor.IClient; import net.user1.reactor.Reactor; import net.user1.reactor.ReactorEvent; import net.user1.reactor.Room; import net.user1.reactor.RoomModuleType; import net.user1.reactor.RoomModules; public class UnionChatPart1 extends Sprite { // Union objects protected var reactor:Reactor; protected var chatRoom:Room; // User interface objects protected var incomingMessages:TextField; protected var outgoingMessages:TextField; public function UnionChatPart1 () { // Create the user interface buildUI(); // Make the Reactor object reactor = new Reactor(); // Run readyListener() when the connection is ready reactor.addEventListener(ReactorEvent.READY, readyListener); // Connect to the server reactor.connect("tryunion.com", 80); } // Method invoked when the connection is ready protected function readyListener (e:ReactorEvent):void { incomingMessages.appendText("Connected to Union\n"); var modules:RoomModules = new RoomModules(); modules.addModule("GreeterBot.js", RoomModuleType.SCRIPT); chatRoom = reactor.getRoomManager().createRoom("chatRoom", null, null, modules); chatRoom.addMessageListener("CHAT_MESSAGE", chatMessageListener); chatRoom.join(); } // Creates the user interface protected function buildUI ():void { incomingMessages = new TextField; incomingMessages.border = true; incomingMessages.background = true; incomingMessages.width = 399; incomingMessages.height = 200; outgoingMessages = new TextField; outgoingMessages.type = TextFieldType.INPUT; outgoingMessages.border = true; outgoingMessages.background = true; outgoingMessages.width = 399; outgoingMessages.height = 20; outgoingMessages.y = 210; outgoingMessages.addEventListener(KeyboardEvent.KEY_UP, keyUpListener); addChild(incomingMessages); addChild(outgoingMessages); } // Keyboard listener for outgoingMessages protected function keyUpListener (e:KeyboardEvent):void { if (e.keyCode == Keyboard.ENTER) { chatRoom.sendMessage("CHAT_MESSAGE", true, null, outgoingMessages.text); outgoingMessages.text = ""; } } // Method invoked when a chat message is received protected function chatMessageListener (fromClient:IClient, messageText:String):void { if (fromClient != null) { incomingMessages.appendText("Guest" + fromClient.getClientID() + " says: " + messageText + "\n"); } else { incomingMessages.appendText("Union says: " + messageText + "\n"); } } } }
Here's the equivalent client-side chat code in JavaScript/HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Union Chat for JavaScript, with GreeterBot</title> <!--CSS--> <style type="text/css"> #chatPane { border: inset 2px; height: 100px; width: 400px; overflow: auto; padding: 5px; margin-bottom: 5px } </style> <!--Load the Orbiter JavaScript library (non-minified version). Use during development.--> <script type="text/javascript" src="http://cdn.unioncloud.io/Orbiter_latest.js"></script> <!--Load the Orbiter JavaScript library (minified version). Use for production.--> <!--<script type="text/javascript" src="http://cdn.unioncloud.io/Orbiter_latest_min.js"></script>--> <!--Chat code--> <script type="text/javascript"> //============================================================================== // VARIABLES //============================================================================== var orbiter; var chatRoom; //============================================================================== // INITIALIZATION //============================================================================== function init () { // Create the Orbiter instance, used to connect to and communicate with Union, // then enable automatic reconnection (one attempt every 15 seconds) orbiter = new net.user1.orbiter.Orbiter(); orbiter.getConnectionMonitor().setAutoReconnectFrequency(15000); orbiter.getLog().setLevel(net.user1.logger.Logger.DEBUG); // If required JavaScript capabilities are missing, abort if (!orbiter.getSystem().isJavaScriptCompatible()) { displayChatMessage("Your browser is not supported."); return; } // Register for Orbiter's connection events orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.READY, readyListener, this); orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.CLOSE, closeListener, this); displayChatMessage("Connecting to Union..."); // Connect to Union Server orbiter.connect("localhost", 9100); } //============================================================================== // ORBITER EVENT LISTENERS //============================================================================== // Triggered when the connection is ready function readyListener (e) { displayChatMessage("Connected."); displayChatMessage("Joining chat room..."); // Deploy the GreeterBot module when creating the room var modules = new net.user1.orbiter.RoomModules(); modules.addModule("GreeterBot.js", net.user1.orbiter.ModuleType.SCRIPT); chatRoom = orbiter.getRoomManager().createRoom("chatRoom", null, null, modules); chatRoom.addMessageListener("CHAT_MESSAGE", chatMessageListener); chatRoom.join(); } // Triggered when the connection is closed function closeListener (e) { displayChatMessage("Orbiter connection closed."); } //============================================================================== // CHAT ROOM EVENT LISTENERS //============================================================================== // Triggered when the room is joined function joinRoomListener (e) { displayChatMessage("Chat ready!"); displayChatMessage("Number of people now chatting: " + chatRoom.getNumOccupants()); } // Triggered when another client joins the chat room function addOccupantListener (e) { if (chatRoom.getSyncState() != net.user1.orbiter.SynchronizationState.SYNCHRONIZING) { displayChatMessage("User" + e.getClientID() + " joined the chat." + " People chatting: " + chatRoom.getNumOccupants()); orbiter.getClientManager().getClient(e.getClientID()).sendMessage("CHAT_MESSAGE", "Private hi to you!"); } } // Triggered when another client leaves the chat room function removeOccupantListener (e) { displayChatMessage("User" + e.getClientID() + " left the chat." + " People chatting: " + chatRoom.getNumOccupants()); } //============================================================================== // CHAT SENDING AND RECEIVING //============================================================================== // Sends a chat message to everyone in the chat room function sendMessage () { var outgoing = document.getElementById("outgoing"); if (outgoing.value.length > 0) { chatRoom.sendMessage("CHAT_MESSAGE", "true", null, outgoing.value); outgoing.value = ""; // Focus text field again after submission (required for IE8 only) setTimeout(function () {outgoing.focus();}, 10); } } // Triggered when a chat message is received function chatMessageListener (fromClient, message) { // When the server sends a message, the fromClient is null, so treat any // message whose fromClient is null as a message from GreeterBot. if (fromClient === null) { displayChatMessage("Union Server: " + message); } else { displayChatMessage("User" + fromClient.getClientID() + ": " + message); } } // Displays a single chat message function displayChatMessage (message) { // Make the new chat message element var msg = document.createElement("span"); msg.appendChild(document.createTextNode(message)); msg.appendChild(document.createElement("br")); // Append the new message to the chat var chatPane = document.getElementById("chatPane"); chatPane.appendChild(msg); // Trim the chat to 500 messages if (chatPane.childNodes.length > 500) { chatPane.removeChild(chatPane.firstChild); } chatPane.scrollTop = chatPane.scrollHeight; } </script> </head> <body onload="init()"> <!--Contains the incoming chat messages--> <div id="chatPane"></div> <!--The outgoing chat form--> <div> <input type="text" id="outgoing" style="width:340px" onkeydown="if (event.keyCode == 13) sendMessage()"/> <input type="submit" value="Send" style="width:60px" onclick="sendMessage()"/> </div> </body> </html>
Step 3 (Optional): Include additional JavaScript files
To load additional JavaScript files for use in a module, follow these steps:
- Place your additional script files in the "modules" directory.
- Add the following function to your module's main JavaScript file.
- For each file you wish to load, invoke require(), specifying the name of the file to load. For example,
require("example.js");
function require(filename) { new javax.script.ScriptEngineManager() .getEngineByName("JavaScript") .eval(new java.io.FileReader(new java.io.File("modules/" + filename))); }