public
Created — forked from khronnuz/ChatIn.scala

Multi-room Chat server / client with Lift

  • Download Gist
MultiChat.scala
Scala
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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
package myproject.comet
 
import net.liftweb._
import actor.LiftActor
import common.{Full, Empty, Box}
import http._
import js.JE._
import js.JE.JsArray._
import js.JE.JsRaw._
import js.JsCmds._
import util._
import Helpers._
import util.AnyVar._
import xml.NodeSeq
import com.foursquare.rogue.Rogue._
import net.liftweb.mongodb._
import net.liftweb.mongodb.record._
import net.liftweb.util._
import net.liftweb.common._
import net.liftweb.json.JsonAST.JString
import net.liftweb.json.JsonDSL._
import org.bson.types.ObjectId
import net.liftweb.record.LifecycleCallbacks
import net.liftweb.record._
import scala.xml._
import net.liftweb.record.field._
import net.liftweb.mongodb.record.field._
import net.liftweb.mongodb.record._
 
import com.foursquare.rogue.Rogue._
import net.liftweb.mongodb._
import com.mongodb.{BasicDBObject, BasicDBObjectBuilder, DBObject}
import br.com.netsar.model.{User, Room}
import scala.PartialFunction
 
/*
Chat server. Keep and proxy the messages to the comet actors.
*/
class ChatServer(val room: String) extends LiftActor with ListenerManager with Logger {
//class ChatServer(val room: Room) extends LiftActor with ListenerManager {
private var messages = List(("System Bot", "Welcome!"))
private var users: List[User] = Nil
 
def createUpdate = ChatServerUpdate(messages, users)
 
 
// processar as mensagens que chegam
override def lowPriority = {
case ChatServerMsg(user, msg) =>
info("mensagem recebida de %s" format user)
messages = (user, msg) :: messages
updateListeners(NewMsg((user, msg)))
 
case NewUser(user) =>
info("server novo usuário %s" format user.firstName)
users = user :: users
updateListeners(NewServerUser(user))
case UserLeft(user) => {
info("server - usuario saiu %s" format user.firstName)
info("nova lista de usuários %s" format users.map(_.firstName).toString())
users = users filterNot (u => u._id.is == user._id.is)
updateListeners(ChatServerUsers(users))
}
case _ => info("Mensagem desconhecida")
}
}
 
object ChatManager {
//private var rooms = Map(Room where(_.active eqs true).fetch.map(rToPair) :_*)
private var rooms = Map("default" :: Nil map (rToPair): _*)
 
private def rToPair(r: String) = r -> new ChatServer(r)
 
def default = synchronized {
rooms("default")
}
 
 
def find(room: String) = synchronized {
rooms.get(room) orElse {
val c = new ChatServer(room)
rooms += (room -> c)
//rooms += rToPair room
rooms.get(room)
}
}
}
 
/*
* Cliente do chat. Cada sessão do cliente tem uma instancia dele.
*/
class Chat extends CometActor with CometListener with Logger {
private var messages: List[(String, String)] = Nil
 
override def lifespan = Full(10 seconds)
 
private val user = User.currentUser.get
 
override def localSetup() = {
super.localSetup()
 
info("localSetup(%s)" format user.firstName)
//sendMessage(NewUser(user))
 
}
 
def sendMessage(msg: Any) {
ChatManager.find(name getOrElse "default").get ! msg
}
 
override protected def localShutdown() {
 
// remove from user lists if still there.
//sendMessage(UserLeft(user))
super.localShutdown
 
}
 
def registerWith = ChatManager.find(name getOrElse "default").get
 
override def lowPriority = {
case ChatServerUpdate(m, u) =>
info("Iniciando chat local com %s e %s" format(u.map(_.getDisplayName), m))
messages = m
reRender(false)
case NewMsg(t) =>
messages = t :: messages
partialUpdate(Call("addChatMessage", t._1, t._2))
}
 
 
def createDisplay(v: List[(String, String)]): NodeSeq = {
{
for {item <- v} yield
<li>
<strong>
{item._1}
</strong>{item._2}
</li>
}
}
 
def render = {
 
 
info("chat render para %s " format user.firstName.is)
"#ul-messages *" #> createDisplay(messages) &
"#room-name [value]" #> name.getOrElse("default") &
"#jsBlock *" #> Script(JsRaw("$(function() {initPods();});")
)
}
}
 
/*
* Contact List client. Each client session has one instance of this.
*/
class ContactList extends CometActor with CometListener with Logger {
private var users: List[User] = Nil
 
override def lifespan = Full(10 seconds)
 
private val user = User.currentUser.get
 
override def localSetup() = {
super.localSetup()
 
info("localSetup(%s)" format user.firstName)
sendMessage(NewUser(user))
 
}
 
def sendMessage(msg: Any) {
ChatManager.find(name getOrElse "default").get ! msg
}
 
override protected def localShutdown() {
 
// remove from user lists if still there.
sendMessage(UserLeft(user))
super.localShutdown
 
}
 
def registerWith = ChatManager.find(name getOrElse "default").get
 
override def lowPriority = {
case ChatServerUpdate(m, u) =>
info("iniciando chat local com %s e %s" format(u.map(_.firstName), m))
users = u
reRender(false)
case NewServerUser(u) =>
info("recebeu novo usuario %s" format u.firstName.is)
//if (user.id != u.id) {
users = u :: users
info("adicionou novo usuario %s" format u.firstName.is)
//partialUpdate(Call("addUser", u.firstName.is))
reRender(false)
//}
case ChatServerUsers(u) =>
info("recebeu nova lista de usuários %s" format u.map(_.firstName).toString())
users = u
reRender(false)
}
 
 
def createDisplayUsers(v: List[User]): NodeSeq = {
{
for {item <- v} yield
<li>
<strong>
{item.firstName.is}
 
</strong>
</li>
}
}
 
def render = {
 
val userIds = users.map(c => Str(c.id.toString)).toList
 
info("render para %s com %s" format(user.firstName.is, users.map(_.getDisplayName)))
"#ul-users *" #> createDisplayUsers(users) &
"#room-name [value]" #> name.getOrElse("default") &
"#jsBlock *" #> Script(JsCrVar("connectedUsers", JsArray(userIds)) &
JsRaw("$(function() {updateChatRoomUsers();});")
)
}
}
 
 
case class ChatServerUpdate(msgs: List[(String, String)], usrs: List[User])
 
case class ChatServerUsers(users: List[User])
 
case class ChatServerMsg(user: String, msg: String)
 
case class NewUser(user: User)
 
case class NewServerUser(user: User)
 
case class NewMsg(msg: (String, String))
 
case class UserLeft(user: User)
 
case class ChatInitialUpdate(msgs: List[(String, String)], users: List[User])
chatroom.html
HTML
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
<div class="pods">
<h3><a href="#">Contact List</a></h3>
 
<div id="contactList">
<div class="lift:comet?type=ContactList;metaname=room">
<div id="jsBlock" style="display: none"></div>
<div>
<ul id="ul-users">
<li><strong>Jhonny</strong> MyCompany</li>
</ul>
</div>
</div>
</div>
<h3><a href="#">Chat</a></h3>
 
<div id="chat">
<div class="lift:comet?type=Chat;metaname=room">
<div id="chat-messages">
<ul id="ul-messages">
<li><strong>User</strong>A message</li>
</ul>
</div>
<div id="chat-input-row">
<form class="lift:form.ajax">
<input class="large lift:ChatIn" id="chat_in"/>
<input type="hidden" id="room-name" name="room" value=""/>
<button id="chat-send" type="submit" class="btn small">Send</button>
</form>
</div>
</div>
 
</div>
</div>

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.