chat starts working
This commit is contained in:
parent
a34df7ceb4
commit
05e020a068
|
@ -6,7 +6,7 @@ import reactivemongo.bson.BSONDocument
|
||||||
import lila.db.Types.Coll
|
import lila.db.Types.Coll
|
||||||
import lila.user.{ User, UserRepo }
|
import lila.user.{ User, UserRepo }
|
||||||
|
|
||||||
private[chat] final class ChatApi(
|
final class ChatApi(
|
||||||
coll: Coll,
|
coll: Coll,
|
||||||
flood: lila.security.Flood,
|
flood: lila.security.Flood,
|
||||||
maxLinesPerChat: Int,
|
maxLinesPerChat: Int,
|
||||||
|
@ -61,9 +61,9 @@ private[chat] final class ChatApi(
|
||||||
private def pushLine(chatId: ChatId, line: Line) = coll.update(
|
private def pushLine(chatId: ChatId, line: Line) = coll.update(
|
||||||
BSONDocument("_id" -> chatId),
|
BSONDocument("_id" -> chatId),
|
||||||
BSONDocument("$push" -> BSONDocument(
|
BSONDocument("$push" -> BSONDocument(
|
||||||
"messages" -> BSONDocument(
|
Chat.BSONFields.lines -> BSONDocument(
|
||||||
"$each" -> line,
|
"$each" -> List(line),
|
||||||
"$slice" -> maxLinesPerChat)
|
"$slice" -> -maxLinesPerChat)
|
||||||
)),
|
)),
|
||||||
upsert = true)
|
upsert = true)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package lila.chat
|
||||||
import akka.actor._
|
import akka.actor._
|
||||||
import chess.Color
|
import chess.Color
|
||||||
|
|
||||||
import lila.hub.actorApi.chat._
|
import actorApi._
|
||||||
|
|
||||||
private[chat] final class FrontActor(api: ChatApi) extends Actor {
|
private[chat] final class FrontActor(api: ChatApi) extends Actor {
|
||||||
|
|
||||||
|
@ -13,18 +13,19 @@ private[chat] final class FrontActor(api: ChatApi) extends Actor {
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
|
|
||||||
case UserTalk(chatId, userId, text) ⇒ api.userChat.write(chatId, userId, text) foreach publish(chatId)
|
case UserTalk(chatId, userId, text, replyTo) ⇒
|
||||||
|
api.userChat.write(chatId, userId, text) foreach publish(chatId, replyTo)
|
||||||
|
|
||||||
case PlayerTalk(chatId, color, text) ⇒ api.playerChat.write(chatId, Color(color), text) foreach publish(chatId)
|
case PlayerTalk(chatId, color, text, replyTo) ⇒
|
||||||
|
api.playerChat.write(chatId, Color(color), text) foreach publish(chatId, replyTo)
|
||||||
|
|
||||||
case SystemTalk(chatId, text) ⇒ api.userChat.system(chatId, text) foreach publish(chatId)
|
case SystemTalk(chatId, text, replyTo) ⇒
|
||||||
|
api.userChat.system(chatId, text) foreach publish(chatId, replyTo)
|
||||||
case msg: NotifyLine ⇒ bus.publish(msg, 'chatOut)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def publish(chatId: String)(lineOption: Option[Line]) {
|
def publish(chatId: String, replyTo: ActorRef)(lineOption: Option[Line]) {
|
||||||
lineOption foreach { line ⇒
|
lineOption foreach { line ⇒
|
||||||
self ! NotifyLine(chatId, Line toJson line)
|
replyTo ! ChatLine(chatId, line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ object Line {
|
||||||
def write(x: Line) = BSONString(lineToStr(x))
|
def write(x: Line) = BSONString(lineToStr(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val UserLineRegex = """^([\w-]{2,})[\s!](.+)$""".r
|
private val UserLineRegex = """^([\w-]{2,})(\s|\!)(.+)$""".r
|
||||||
def strToUserLine(str: String): Option[UserLine] = str match {
|
def strToUserLine(str: String): Option[UserLine] = str match {
|
||||||
case UserLineRegex(username, " ", text) ⇒ UserLine(username, text, false).some
|
case UserLineRegex(username, " ", text) ⇒ UserLine(username, text, false).some
|
||||||
case UserLineRegex(username, "!", text) ⇒ UserLine(username, text, true).some
|
case UserLineRegex(username, "!", text) ⇒ UserLine(username, text, true).some
|
||||||
|
|
9
modules/chat/src/main/actorApi.scala
Normal file
9
modules/chat/src/main/actorApi.scala
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package lila.chat
|
||||||
|
package actorApi
|
||||||
|
|
||||||
|
import akka.actor.ActorRef
|
||||||
|
|
||||||
|
case class UserTalk(chatId: String, userId: String, text: String, replyTo: ActorRef)
|
||||||
|
case class PlayerTalk(chatId: String, white: Boolean, text: String, replyTo: ActorRef)
|
||||||
|
case class SystemTalk(chatId: String, text: String, replyTo: ActorRef)
|
||||||
|
case class ChatLine(chatId: String, line: Line)
|
|
@ -1,8 +1,8 @@
|
||||||
package lila.game
|
package lila.game
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringEscapeUtils.escapeXml
|
|
||||||
import play.api.libs.json._
|
import play.api.libs.json._
|
||||||
|
|
||||||
|
import lila.chat.{ Line, UserLine, PlayerLine }
|
||||||
import chess.Pos.{ piotr, allPiotrs }
|
import chess.Pos.{ piotr, allPiotrs }
|
||||||
import chess.{ PromotableRole, Pos, Color, Situation, Move ⇒ ChessMove, Clock ⇒ ChessClock }
|
import chess.{ PromotableRole, Pos, Color, Situation, Move ⇒ ChessMove, Clock ⇒ ChessClock }
|
||||||
|
|
||||||
|
@ -107,20 +107,20 @@ object Event {
|
||||||
def data = JsString(pos.key)
|
def data = JsString(pos.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Message(author: String, text: String, t: Boolean) extends Event {
|
case class PlayerMessage(line: PlayerLine) extends Event {
|
||||||
def typ = "message"
|
def typ = "message"
|
||||||
def data = Json.obj("u" -> author, "t" -> escapeXml(text))
|
def data = Line toJson line
|
||||||
override def owner = true
|
override def owner = true
|
||||||
override def troll = t
|
override def troll = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// it *IS* a username, and not a user ID
|
// it *IS* a username, and not a user ID
|
||||||
// immediately used for rendering
|
// immediately used for rendering
|
||||||
case class WatcherMessage(username: Option[String], text: String, t: Boolean) extends Event {
|
case class UserMessage(line: UserLine, w: Boolean) extends Event {
|
||||||
def typ = "message"
|
def typ = "message"
|
||||||
def data = Json.obj("u" -> username, "t" -> escapeXml(text))
|
def data = Line toJson line
|
||||||
override def watcher = true
|
override def troll = line.troll
|
||||||
override def troll = t
|
override def watcher = w
|
||||||
}
|
}
|
||||||
|
|
||||||
object End extends Empty {
|
object End extends Empty {
|
||||||
|
|
|
@ -35,13 +35,6 @@ case class WithUserIds(f: Iterable[String] ⇒ Unit)
|
||||||
|
|
||||||
case object GetUids
|
case object GetUids
|
||||||
|
|
||||||
package chat {
|
|
||||||
case class UserTalk(chatId: String, userId: String, text: String)
|
|
||||||
case class PlayerTalk(chatId: String, white: Boolean, text: String)
|
|
||||||
case class SystemTalk(chatId: String, text: String)
|
|
||||||
case class NotifyLine(chatId: String, json: JsObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
package report {
|
package report {
|
||||||
case class Cheater(userId: String, text: String)
|
case class Cheater(userId: String, text: String)
|
||||||
case class Check(userId: String)
|
case class Check(userId: String)
|
||||||
|
|
|
@ -59,7 +59,7 @@ final class Env(
|
||||||
}), name = ActorMapName)
|
}), name = ActorMapName)
|
||||||
|
|
||||||
private val socketHub = system.actorOf(
|
private val socketHub = system.actorOf(
|
||||||
Props(new lila.socket.SocketHubActor.Default[Socket] {
|
Props(new lila.socket.SocketHubActor[Socket] {
|
||||||
def mkActor(id: String) = new Socket(
|
def mkActor(id: String) = new Socket(
|
||||||
gameId = id,
|
gameId = id,
|
||||||
history = history(),
|
history = history(),
|
||||||
|
@ -68,6 +68,10 @@ final class Env(
|
||||||
socketTimeout = SocketTimeout,
|
socketTimeout = SocketTimeout,
|
||||||
disconnectTimeout = PlayerDisconnectTimeout,
|
disconnectTimeout = PlayerDisconnectTimeout,
|
||||||
ragequitTimeout = PlayerRagequitTimeout)
|
ragequitTimeout = PlayerRagequitTimeout)
|
||||||
|
def receive: Receive = ({
|
||||||
|
case msg@lila.chat.actorApi.ChatLine(id, line) ⇒
|
||||||
|
self ! lila.hub.actorApi.map.Tell(id take 8, msg).pp
|
||||||
|
}: Receive) orElse socketHubReceive
|
||||||
}),
|
}),
|
||||||
name = SocketName)
|
name = SocketName)
|
||||||
|
|
||||||
|
@ -113,6 +117,7 @@ final class Env(
|
||||||
|
|
||||||
lazy val messenger = new Messenger(
|
lazy val messenger = new Messenger(
|
||||||
bus = system.lilaBus,
|
bus = system.lilaBus,
|
||||||
|
socketHub = socketHub,
|
||||||
i18nKeys = i18nKeys)
|
i18nKeys = i18nKeys)
|
||||||
|
|
||||||
lazy val fenUrlWatch = new FenUrlWatch(
|
lazy val fenUrlWatch = new FenUrlWatch(
|
||||||
|
|
|
@ -2,17 +2,18 @@ package lila.round
|
||||||
|
|
||||||
import lila.common.Bus
|
import lila.common.Bus
|
||||||
import lila.game.Game
|
import lila.game.Game
|
||||||
import lila.hub.actorApi.chat._
|
import lila.chat.actorApi._
|
||||||
import lila.i18n.I18nKey.{ Select ⇒ SelectI18nKey }
|
import lila.i18n.I18nKey.{ Select ⇒ SelectI18nKey }
|
||||||
import lila.i18n.I18nKeys
|
import lila.i18n.I18nKeys
|
||||||
|
|
||||||
final class Messenger(
|
final class Messenger(
|
||||||
bus: Bus,
|
bus: Bus,
|
||||||
|
socketHub: akka.actor.ActorRef,
|
||||||
i18nKeys: I18nKeys) {
|
i18nKeys: I18nKeys) {
|
||||||
|
|
||||||
def apply(game: Game, message: SelectI18nKey, args: Any*) {
|
def apply(game: Game, message: SelectI18nKey, args: Any*) {
|
||||||
val translated = message(i18nKeys).en(args: _*)
|
val translated = message(i18nKeys).en(args: _*)
|
||||||
bus.publish(SystemTalk(game.id + "/w", translated), 'chatIn)
|
bus.publish(SystemTalk(game.id + "/w", translated, socketHub), 'chatIn)
|
||||||
if (game.nonAi) bus.publish(SystemTalk(game.id, translated), 'chatIn)
|
if (game.nonAi) bus.publish(SystemTalk(game.id, translated, socketHub), 'chatIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ private[round] final class Socket(
|
||||||
disconnectTimeout: Duration,
|
disconnectTimeout: Duration,
|
||||||
ragequitTimeout: Duration) extends SocketActor[Member](uidTimeout) {
|
ragequitTimeout: Duration) extends SocketActor[Member](uidTimeout) {
|
||||||
|
|
||||||
|
context.system.lilaBus.subscribe(self, 'chatOut)
|
||||||
|
|
||||||
private val timeBomb = new TimeBomb(socketTimeout)
|
private val timeBomb = new TimeBomb(socketTimeout)
|
||||||
|
|
||||||
private final class Player(color: Color) {
|
private final class Player(color: Color) {
|
||||||
|
@ -87,8 +89,13 @@ private[round] final class Socket(
|
||||||
sender ! Connected(enumerator, member)
|
sender ! Connected(enumerator, member)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Nil ⇒
|
case Nil ⇒
|
||||||
case events: Events ⇒ notify(events)
|
case events: Events ⇒ notify(events)
|
||||||
|
|
||||||
|
case lila.chat.actorApi.ChatLine(chatId, line) ⇒ notify(List(line match {
|
||||||
|
case l: lila.chat.UserLine ⇒ Event.UserMessage(l, chatId endsWith "/w")
|
||||||
|
case l: lila.chat.PlayerLine ⇒ Event.PlayerMessage(l)
|
||||||
|
}))
|
||||||
|
|
||||||
case AnalysisAvailable ⇒ notifyAll("analysisAvailable", true)
|
case AnalysisAvailable ⇒ notifyAll("analysisAvailable", true)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import chess.Color
|
||||||
import play.api.libs.json.{ JsObject, Json }
|
import play.api.libs.json.{ JsObject, Json }
|
||||||
|
|
||||||
import actorApi._, round._
|
import actorApi._, round._
|
||||||
|
import lila.chat.actorApi._
|
||||||
import lila.common.PimpedJson._
|
import lila.common.PimpedJson._
|
||||||
import lila.game.{ Game, Pov, PovRef, PlayerRef, GameRepo }
|
import lila.game.{ Game, Pov, PovRef, PlayerRef, GameRepo }
|
||||||
import lila.hub.actorApi.map._
|
import lila.hub.actorApi.map._
|
||||||
|
@ -37,6 +38,11 @@ private[round] final class SocketHandler(
|
||||||
case ("liveGames", o) ⇒ o str "d" foreach { ids ⇒
|
case ("liveGames", o) ⇒ o str "d" foreach { ids ⇒
|
||||||
socket ! LiveGames(uid, ids.split(' ').toList)
|
socket ! LiveGames(uid, ids.split(' ').toList)
|
||||||
}
|
}
|
||||||
|
case ("talk", o) ⇒ o str "d" foreach { text ⇒
|
||||||
|
member.userId foreach { userId =>
|
||||||
|
bus.publish(UserTalk(gameId + "/w", userId, text, socket), 'chatIn)
|
||||||
|
}
|
||||||
|
}
|
||||||
}) { playerId ⇒
|
}) { playerId ⇒
|
||||||
{
|
{
|
||||||
case ("p", o) ⇒ o int "v" foreach { v ⇒ socket ! PingVersion(uid, v) }
|
case ("p", o) ⇒ o int "v" foreach { v ⇒ socket ! PingVersion(uid, v) }
|
||||||
|
@ -70,8 +76,8 @@ private[round] final class SocketHandler(
|
||||||
}
|
}
|
||||||
case ("talk", o) ⇒ o str "d" foreach { text ⇒
|
case ("talk", o) ⇒ o str "d" foreach { text ⇒
|
||||||
bus.publish(member.userId match {
|
bus.publish(member.userId match {
|
||||||
case Some(userId) ⇒ lila.hub.actorApi.chat.UserTalk(uid, userId, text)
|
case Some(userId) ⇒ UserTalk(gameId, userId, text, socket)
|
||||||
case None ⇒ lila.hub.actorApi.chat.PlayerTalk(uid, member.color.white, text)
|
case None ⇒ PlayerTalk(gameId, member.color.white, text, socket)
|
||||||
}, 'chatIn)
|
}, 'chatIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ object ApplicationBuild extends Build {
|
||||||
play.api, play.test, RM, PRM, hasher)
|
play.api, play.test, RM, PRM, hasher)
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val game = project("game", Seq(common, memo, db, hub, user, chess)).settings(
|
lazy val game = project("game", Seq(common, memo, db, hub, user, chess, chat)).settings(
|
||||||
libraryDependencies ++= provided(
|
libraryDependencies ++= provided(
|
||||||
play.api, RM, PRM)
|
play.api, RM, PRM)
|
||||||
)
|
)
|
||||||
|
@ -106,7 +106,7 @@ object ApplicationBuild extends Build {
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val round = project("round", Seq(
|
lazy val round = project("round", Seq(
|
||||||
common, db, memo, hub, socket, chess, game, user, i18n, ai, pref)).settings(
|
common, db, memo, hub, socket, chess, game, user, i18n, ai, pref, chat)).settings(
|
||||||
libraryDependencies ++= provided(play.api, RM, PRM)
|
libraryDependencies ++= provided(play.api, RM, PRM)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -348,6 +348,11 @@ var storage = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
message: function(msg) {
|
||||||
|
$('div.lichess_chat').each(function() {
|
||||||
|
$(this).chat("append", msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
nbm: function(e) {
|
nbm: function(e) {
|
||||||
$('#nb_messages').text(e || "0").toggleClass("unread", e > 0);
|
$('#nb_messages').text(e || "0").toggleClass("unread", e > 0);
|
||||||
},
|
},
|
||||||
|
@ -1584,11 +1589,12 @@ var storage = {
|
||||||
if (!$toggle[0].checked) {
|
if (!$toggle[0].checked) {
|
||||||
self.element.addClass('hidden');
|
self.element.addClass('hidden');
|
||||||
}
|
}
|
||||||
|
if (self.options.messages.length > 0) self._appendMany(self.options.messages);
|
||||||
},
|
},
|
||||||
append: function(msg) {
|
append: function(msg) {
|
||||||
this._appendHtml(this._render(msg));
|
this._appendHtml(this._render(msg));
|
||||||
},
|
},
|
||||||
appendMany: function(objs) {
|
_appendMany: function(objs) {
|
||||||
var self = this,
|
var self = this,
|
||||||
html = "";
|
html = "";
|
||||||
$.each(objs, function() {
|
$.each(objs, function() {
|
||||||
|
@ -1605,7 +1611,7 @@ var storage = {
|
||||||
} else {
|
} else {
|
||||||
user = '<span class="user">' + $.userLinkLimit(msg.u, 14) + '</span>';
|
user = '<span class="user">' + $.userLinkLimit(msg.u, 14) + '</span>';
|
||||||
}
|
}
|
||||||
return '<li class="' + (u == 'system' ? ' trans_me' : '') + (msg.r ? ' troll' : '') + '">' + urlToLink(msg.t) + '</li>';
|
return '<li class="' + (msg.u == 'system' ? ' trans_me' : '') + (msg.r ? ' troll' : '') + '">' + user + urlToLink(msg.t) + '</li>';
|
||||||
},
|
},
|
||||||
_appendHtml: function(html) {
|
_appendHtml: function(html) {
|
||||||
this.$msgs.append(html);
|
this.$msgs.append(html);
|
||||||
|
|
|
@ -2,7 +2,6 @@ div.lichess_board_wrap {
|
||||||
float: left;
|
float: left;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
span.board_mark {
|
span.board_mark {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
Loading…
Reference in a new issue