Reactor Chat Tutorial, Part 2

Chat Example 2 adds the following new features to Chat Example 1:

  • Customizable user names
  • User join/leave messages
  • A user list

Here's what the new chat looks like:

Note: this example focuses on the Reactor API, and therefore shows only the bare minimum code required to create a chat user interface.

The Code

Here's the code for the new chat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
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.Attribute;
  import net.user1.reactor.IClient;
  import net.user1.reactor.Reactor;
  import net.user1.reactor.ReactorEvent;
  import net.user1.reactor.Room;
  import net.user1.reactor.RoomEvent;
  import net.user1.reactor.SynchronizationState;

  public class UnionChatPart2 extends Sprite {
    // Union objects
    protected var reactor:Reactor;
    protected var chatRoom:Room;
    // User interface objects
    protected var incomingMessages:TextField;
    protected var outgoingMessages:TextField;
    protected var userlist:TextField;
    protected var nameInput:TextField;

    // Constructor    
    public function UnionChatPart2 () {
      // 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");
      chatRoom = reactor.getRoomManager().createRoom(
                                                   "chatRoom");
      chatRoom.addMessageListener("CHAT_MESSAGE",
                                  chatMessageListener);
      chatRoom.addEventListener(RoomEvent.JOIN,
                                joinRoomListener);
      chatRoom.addEventListener(RoomEvent.ADD_OCCUPANT,
                                addClientListener);
      chatRoom.addEventListener(RoomEvent.REMOVE_OCCUPANT,
                                removeClientListener);
      chatRoom.addEventListener(RoomEvent.UPDATE_CLIENT_ATTRIBUTE,
                                updateClientAttributeListener);
      chatRoom.join();
    }
   
    // Create the user interface
    protected function buildUI ():void {
      incomingMessages = new TextField;
      incomingMessages.border = true;
      incomingMessages.background = true;
      incomingMessages.width = 300;
      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,
                                        outgoingKeyUpListener);
                                       
      userlist = new TextField();
      userlist.border = true;
      userlist.background = true;
      userlist.width = 89;
      userlist.height = 200;
      userlist.x = 310;
                                       
      nameInput = new TextField();
      nameInput.type = TextFieldType.INPUT;
      nameInput.border = true;
      nameInput.background = true;
      nameInput.width = 399;
      nameInput.height = 20;
      nameInput.y = 240;
      nameInput.addEventListener(KeyboardEvent.KEY_UP,
                                 nameKeyUpListener);
     
      addChild(incomingMessages);
      addChild(outgoingMessages);
      addChild(userlist);
      addChild(nameInput);
    }
   
    // Keyboard listener for outgoingMessages
    protected function outgoingKeyUpListener (e:KeyboardEvent):void {
      if (e.keyCode == Keyboard.ENTER) {
        chatRoom.sendMessage("CHAT_MESSAGE",
                             true,
                             null,
                             outgoingMessages.text);
        outgoingMessages.text = "";
      }
    }
   
    // Keyboard listener for nameInput
    protected function nameKeyUpListener (e:KeyboardEvent):void {
      var self:IClient;
      if (e.keyCode == Keyboard.ENTER) {
        self = reactor.self();
        self.setAttribute("username", nameInput.text);
        nameInput.text = "";
      }
    }
   
    // Method invoked when a chat message is received
    protected function chatMessageListener (fromClient:IClient,
                                            messageText:String
                                            ):void {
      incomingMessages.appendText(getUserName(fromClient)
                                  + " says: "
                                  + messageText + "\n");
      incomingMessages.scrollV = incomingMessages.maxScrollV;
    }
   
    // Method invoked when the current client joins the room
    protected function joinRoomListener (e:RoomEvent):void {
      updateUserList();
    }
   
    // Method invoked when a client joins the room
    protected function addClientListener (e:RoomEvent):void {
      if (e.getClient().isSelf()) {
        incomingMessages.appendText("You joined the chat.\n");
      } else {
        if (chatRoom.getSyncState() != SynchronizationState.SYNCHRONIZING) {
          // Show a "guest joined" message only when the room isn't performing
          // its initial occupant-list synchronization.
          incomingMessages.appendText(getUserName(e.getClient())
                                      + " joined the chat.\n");
        }
      }
      incomingMessages.scrollV = incomingMessages.maxScrollV;
      updateUserList();
    }
   
    // Method invoked when a client leave the room
    protected function removeClientListener (e:RoomEvent):void {
      incomingMessages.appendText(getUserName(e.getClient())
                                  + " left the chat.\n");
      incomingMessages.scrollV = incomingMessages.maxScrollV;
      updateUserList();
    }
   
    // Method invoked when any client in the room
    // changes the value of a shared attribute
    protected function updateClientAttributeListener (e:RoomEvent):void {
      var changedAttr:Attribute = e.getChangedAttr();
      if (changedAttr.name == "username") {
        if (changedAttr.oldValue == null) {
          incomingMessages.appendText("Guest" + e.getClientID());
        } else {
          incomingMessages.appendText(changedAttr.oldValue);
        }
        incomingMessages.appendText(" 's name changed to "
                                    + getUserName(e.getClient())
                                    + ".\n");
        incomingMessages.scrollV = incomingMessages.maxScrollV;
        updateUserList();
      }
    }
   
    // Helper method to display the room's
    // clients in the user list
    protected function updateUserList ():void {
      userlist.text = "";
      for each (var client:IClient in chatRoom.getOccupants()) {
        userlist.appendText(getUserName(client) + "\n");
      }
    }
   
    // Helper method to retrieve a client's user name.
    // If no user name is set for the specified client,
    // returns "Guestn" (where 'n' is the client's id).  
    protected function getUserName (client:IClient):String {
      var username:String = client.getAttribute("username");
        if (username == null) {
          return "Guest" + client.getClientID();
        } else {
          return username;
        }
    }
  }
}