Added encryption/decryption login
This commit is contained in:
parent
0681105778
commit
844cca761a
17
build.sbt
17
build.sbt
@ -23,6 +23,14 @@ val osName = System.getProperty("os.name") match {
|
|||||||
|
|
||||||
fork := true
|
fork := true
|
||||||
|
|
||||||
|
inThisBuild(
|
||||||
|
List(
|
||||||
|
scalaVersion := scalaVersion.value, // 2.11.12, or 2.13.2
|
||||||
|
semanticdbEnabled := true, // enable SemanticDB
|
||||||
|
semanticdbVersion := scalafixSemanticdb.revision // use Scalafix compatible version
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"base",
|
"base",
|
||||||
"controls",
|
"controls",
|
||||||
@ -40,6 +48,7 @@ libraryDependencies += "com.sfxcode.sapphire" %% "sapphire-extension" % "1.0.6"
|
|||||||
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
|
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
|
||||||
|
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
|
"org.typelevel" %% "cats-core" % "2.1.1",
|
||||||
"org.scalafx" %% "scalafx" % "12.0.2-R18",
|
"org.scalafx" %% "scalafx" % "12.0.2-R18",
|
||||||
"org.scalafx" %% "scalafx-extras" % "0.3.4",
|
"org.scalafx" %% "scalafx-extras" % "0.3.4",
|
||||||
"com.softwaremill.sttp.client" %% "json4s" % "2.1.1",
|
"com.softwaremill.sttp.client" %% "json4s" % "2.1.1",
|
||||||
@ -57,7 +66,11 @@ libraryDependencies ++= Seq(
|
|||||||
)
|
)
|
||||||
libraryDependencies += "org.asynchttpclient" % "async-http-client" % "2.12.1"
|
libraryDependencies += "org.asynchttpclient" % "async-http-client" % "2.12.1"
|
||||||
libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.3"
|
libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.3"
|
||||||
scalacOptions ++= Seq("-Ymacro-annotations", "-deprecation")
|
scalacOptions ++= Seq(
|
||||||
|
"-Ymacro-annotations",
|
||||||
|
"-deprecation",
|
||||||
|
"-Ywarn-unused:imports"
|
||||||
|
)
|
||||||
|
|
||||||
libraryDependencies += "org.scalafx" %% "scalafxml-core-sfx8" % "0.5"
|
libraryDependencies += "org.scalafx" %% "scalafxml-core-sfx8" % "0.5"
|
||||||
// https://mvnrepository.com/artifact/com.jfoenix/jfoenix
|
// https://mvnrepository.com/artifact/com.jfoenix/jfoenix
|
||||||
@ -90,6 +103,6 @@ javaFxTitle := "chatto-sapphire"
|
|||||||
|
|
||||||
javaFxCategory := "Aplication"
|
javaFxCategory := "Aplication"
|
||||||
|
|
||||||
javaFxNativeBundles := "image"
|
javaFxNativeBundles := "deb"
|
||||||
|
|
||||||
javaFxVerbose := true
|
javaFxVerbose := true
|
||||||
|
@ -4,3 +4,4 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
|
|||||||
|
|
||||||
addSbtPlugin("com.quadstingray" % "sbt-javafx" % "1.5.2")
|
addSbtPlugin("com.quadstingray" % "sbt-javafx" % "1.5.2")
|
||||||
|
|
||||||
|
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.17")
|
@ -1,5 +1,5 @@
|
|||||||
sapphire.core.fxml.basePath="/fxml/"
|
sapphire.core.fxml.basePath="/fxml/"
|
||||||
application.name = "Application"
|
application.name = "Chatto"
|
||||||
project.name = "chatto-sapphire"
|
project.name = "chatto-sapphire"
|
||||||
project.version = "0.1.0-SNAPSHOT"
|
project.version = "0.1.0-SNAPSHOT"
|
||||||
stage.default {
|
stage.default {
|
||||||
|
@ -87,7 +87,15 @@
|
|||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-message-box {
|
.chat-message-sender-box {
|
||||||
|
-fx-text-fill: white;
|
||||||
|
-fx-background-color: LIGHTGREEN;
|
||||||
|
/* -fx-background-color: #82ccdd; */
|
||||||
|
-fx-background-radius: 30px;
|
||||||
|
-fx-padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-message-receiver-box {
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
/* -fx-background-color: LIGHTGREEN; */
|
/* -fx-background-color: LIGHTGREEN; */
|
||||||
-fx-background-color: #82ccdd;
|
-fx-background-color: #82ccdd;
|
||||||
|
@ -3,30 +3,17 @@ package wow.doge.chatto
|
|||||||
import javax.enterprise.context.ApplicationScoped
|
import javax.enterprise.context.ApplicationScoped
|
||||||
import javax.enterprise.inject.Produces
|
import javax.enterprise.inject.Produces
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
import com.typesafe.config.ConfigFactory
|
|
||||||
import com.sfxcode.sapphire.core.controller.DefaultWindowController
|
import com.sfxcode.sapphire.core.controller.DefaultWindowController
|
||||||
// import org.asynchttpclient.Dsl._
|
// import org.asynchttpclient.Dsl._
|
||||||
import wow.doge.chatto.controller.MainViewController
|
import wow.doge.chatto.controller.MainViewController
|
||||||
import sttp.client.asynchttpclient.future.AsyncHttpClientFutureBackend
|
import sttp.client.asynchttpclient.future.AsyncHttpClientFutureBackend
|
||||||
import sttp.client._
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.async.Async.{async, await}
|
import scala.async.Async.{async, await}
|
||||||
import sttp.client.json4s._
|
|
||||||
import org.json4s._
|
|
||||||
// import org.json4s.native.JsonMethods._
|
// import org.json4s.native.JsonMethods._
|
||||||
import org.json4s.jackson.JsonMethods._
|
|
||||||
|
|
||||||
import org.json4s.JsonDSL._
|
|
||||||
import scala.util.Success
|
|
||||||
import scala.util.Failure
|
|
||||||
import com.softwaremill.quicklens._
|
|
||||||
import org.scalafx.extras._
|
import org.scalafx.extras._
|
||||||
import wow.doge.chatto.service.UserService
|
|
||||||
import javax.inject._
|
import javax.inject._
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import com.sfxcode.sapphire.core.controller.SceneControllerDidChangeEvent
|
|
||||||
import javax.enterprise.event.Observes
|
|
||||||
import com.sfxcode.sapphire.core.controller.SceneControllerWillChangeEvent
|
|
||||||
@Named
|
@Named
|
||||||
@ApplicationScoped
|
@ApplicationScoped
|
||||||
class ApplicationController extends DefaultWindowController {
|
class ApplicationController extends DefaultWindowController {
|
||||||
@ -55,6 +42,9 @@ class ApplicationController extends DefaultWindowController {
|
|||||||
@Produces
|
@Produces
|
||||||
def httpBackend = backend
|
def httpBackend = backend
|
||||||
|
|
||||||
|
// @Produces
|
||||||
|
// def encryptionService: EncryptionService = EncryptionServiceImpl()
|
||||||
|
|
||||||
def replacePrimarySceneContent(): Unit = {
|
def replacePrimarySceneContent(): Unit = {
|
||||||
// Styling
|
// Styling
|
||||||
reloadStyles()
|
reloadStyles()
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package wow.doge.chatto.control
|
package wow.doge.chatto.control
|
||||||
|
|
||||||
import javafx.scene.layout.HBox
|
import javafx.scene.layout.HBox
|
||||||
import javafx.scene.control.Label
|
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import wow.doge.chatto.controller.ChatData
|
import wow.doge.chatto.model.Message
|
||||||
import com.sfxcode.sapphire.core.value.FXBean
|
|
||||||
import wow.doge.chatto.controller.Message
|
|
||||||
import com.sandec.mdfx.MDFXNode
|
import com.sandec.mdfx.MDFXNode
|
||||||
import javafx.geometry.Pos
|
import javafx.geometry.Pos
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
|
@ -5,7 +5,6 @@ import javafx.fxml.FXML
|
|||||||
import javafx.scene.control.RadioButton
|
import javafx.scene.control.RadioButton
|
||||||
import javafx.scene.control.Label
|
import javafx.scene.control.Label
|
||||||
import javafx.fxml.FXMLLoader
|
import javafx.fxml.FXMLLoader
|
||||||
import scalafx.Includes._
|
|
||||||
|
|
||||||
class UserBox() extends VBox() {
|
class UserBox() extends VBox() {
|
||||||
@FXML private var _userRadioButton: RadioButton = _
|
@FXML private var _userRadioButton: RadioButton = _
|
||||||
|
@ -4,7 +4,6 @@ import javafx.scene.layout.HBox
|
|||||||
import javafx.scene.control.Label
|
import javafx.scene.control.Label
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import wow.doge.chatto.controller.ChatData
|
import wow.doge.chatto.controller.ChatData
|
||||||
import com.sfxcode.sapphire.core.value.FXBean
|
|
||||||
|
|
||||||
class UserBox2(val username: String, val chatData: ChatData) extends HBox() {
|
class UserBox2(val username: String, val chatData: ChatData) extends HBox() {
|
||||||
val usernameLabel = new Label(username) {
|
val usernameLabel = new Label(username) {
|
||||||
|
@ -3,53 +3,30 @@ package wow.doge.chatto.controller
|
|||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import javafx.scene.control.Label
|
import javafx.scene.control.Label
|
||||||
import javafx.scene.control.Button
|
import javafx.scene.control.Button
|
||||||
import javafx.scene.layout.FlowPane
|
|
||||||
import javafx.scene.control.TextArea
|
import javafx.scene.control.TextArea
|
||||||
import javafx.scene.control.ListView
|
|
||||||
import javafx.scene.layout.HBox
|
import javafx.scene.layout.HBox
|
||||||
import javafx.scene.layout.VBox
|
import javafx.scene.layout.VBox
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import wow.doge.chatto.control.UserBox
|
|
||||||
import javafx.application.Platform
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import org.scalafx.extras._
|
import org.scalafx.extras._
|
||||||
import wow.doge.chatto.messagebuble.BubbledMDFXNode
|
|
||||||
import wow.doge.chatto.service.UserService
|
import wow.doge.chatto.service.UserService
|
||||||
import scala.concurrent.ExecutionContext
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
import com.sfxcode.sapphire.core.value.FXBean
|
import com.sfxcode.sapphire.core.value.FXBean
|
||||||
import wow.doge.chatto.AppDataHandler
|
import wow.doge.chatto.AppDataHandler
|
||||||
import com.jfoenix.controls.JFXListView
|
import com.jfoenix.controls.JFXListView
|
||||||
import scala.async.Async.{async, await}
|
import scala.async.Async.{async, await}
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import scalafx.collections.ObservableBuffer
|
import scalafx.collections.ObservableBuffer
|
||||||
import javafx.beans.property.SimpleListProperty
|
|
||||||
import wow.doge.chatto.control.UserBox2
|
|
||||||
import javafx.beans.value.ChangeListener
|
|
||||||
import com.sfxcode.sapphire.core.value.KeyBindings
|
import com.sfxcode.sapphire.core.value.KeyBindings
|
||||||
import com.sfxcode.sapphire.core.value.FXBeanAdapter
|
import com.sfxcode.sapphire.core.value.FXBeanAdapter
|
||||||
import scalafx.collections.ObservableMap
|
|
||||||
import com.sfxcode.sapphire.core.value.BeanConversions
|
|
||||||
import javafx.util.converter.DateStringConverter
|
|
||||||
import javafx.beans.binding.Bindings
|
|
||||||
import wow.doge.chatto.service.ActiveUser
|
import wow.doge.chatto.service.ActiveUser
|
||||||
import scala.collection.mutable
|
|
||||||
import scala.collection.concurrent.TrieMap
|
import scala.collection.concurrent.TrieMap
|
||||||
import wow.doge.chatto.messagebuble.BubbleSpec
|
|
||||||
import javafx.scene.layout.Background
|
|
||||||
import javafx.scene.layout.BackgroundFill
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import scalafx.beans.property.ReadOnlyBufferProperty
|
|
||||||
import scalafx.beans.property.ReadOnlyBufferWrapper
|
|
||||||
import javafx.beans.property.ReadOnlyListProperty
|
import javafx.beans.property.ReadOnlyListProperty
|
||||||
import scalafx.beans.property.BufferProperty
|
import scalafx.beans.property.BufferProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
import com.sandec.mdfx.MDFXNode
|
|
||||||
import javafx.scene.layout.BorderPane
|
import javafx.scene.layout.BorderPane
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
import net.synedra.validatorfx.Validator
|
import net.synedra.validatorfx.Validator
|
||||||
import wow.doge.chatto.control.JFXSmoothScroll
|
|
||||||
import javafx.scene.control.ContextMenu
|
import javafx.scene.control.ContextMenu
|
||||||
import javafx.scene.control.MenuItem
|
import javafx.scene.control.MenuItem
|
||||||
import javafx.scene.input.Clipboard
|
import javafx.scene.input.Clipboard
|
||||||
@ -57,16 +34,21 @@ import javafx.scene.input.ClipboardContent
|
|||||||
import scalafx.scene.input.KeyCodeCombination
|
import scalafx.scene.input.KeyCodeCombination
|
||||||
import scalafx.scene.input.KeyCode
|
import scalafx.scene.input.KeyCode
|
||||||
import scalafx.scene.input.KeyCombination
|
import scalafx.scene.input.KeyCombination
|
||||||
import javafx.scene.input.DataFormat
|
|
||||||
import wow.doge.chatto.control.MessageBox
|
import wow.doge.chatto.control.MessageBox
|
||||||
import javafx.scene.control.SelectionMode
|
import javafx.scene.control.SelectionMode
|
||||||
import scalafx.beans.property.BooleanProperty
|
|
||||||
import javafx.scene.control.ListCell
|
import javafx.scene.control.ListCell
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import com.github.marlonlom.utilities.timeago.TimeAgo
|
import com.github.marlonlom.utilities.timeago.TimeAgo
|
||||||
|
import wow.doge.chatto.service.EncryptionService
|
||||||
|
import wow.doge.chatto.model.MessageCipher
|
||||||
|
import wow.doge.chatto.model.MessageType
|
||||||
|
import scala.util.Try
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import wow.doge.chatto.model.Message
|
||||||
|
|
||||||
class ChatController @Inject() (
|
class ChatController @Inject() (
|
||||||
userService: UserService,
|
userService: UserService,
|
||||||
|
encryptionService: EncryptionService,
|
||||||
appDataHandler: AppDataHandler
|
appDataHandler: AppDataHandler
|
||||||
) extends AbstractViewController
|
) extends AbstractViewController
|
||||||
with LazyLogging {
|
with LazyLogging {
|
||||||
@ -86,19 +68,19 @@ class ChatController @Inject() (
|
|||||||
@FXML private var isOnlineLabel: Label = _
|
@FXML private var isOnlineLabel: Label = _
|
||||||
@FXML private var selectedUserBox: HBox = _
|
@FXML private var selectedUserBox: HBox = _
|
||||||
|
|
||||||
private val usersBuffer = ObservableBuffer.empty[ActiveUser]
|
private lazy val usersBuffer = ObservableBuffer.empty[ActiveUser]
|
||||||
private val usersListProperty = BufferProperty(usersBuffer)
|
private lazy val usersListProperty = BufferProperty(usersBuffer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Readonly property wrapping an unmodifiable list.
|
* Readonly property wrapping an unmodifiable list.
|
||||||
* Synchronized with the internal users list property.
|
* Synchronized with the internal users list property.
|
||||||
* Attemping to modify the internal list will throw an exception
|
* Attemping to modify the internal list will throw an exception
|
||||||
*/
|
*/
|
||||||
val usersListROProp: ReadOnlyListProperty[ActiveUser] = BufferProperty(
|
lazy val usersListROProp: ReadOnlyListProperty[ActiveUser] = BufferProperty(
|
||||||
FXCollections.unmodifiableObservableList(usersListProperty())
|
FXCollections.unmodifiableObservableList(usersListProperty())
|
||||||
)
|
)
|
||||||
|
|
||||||
private val chatDataStore = TrieMap.empty[String, ChatDataProperty]
|
private lazy val chatDataStore = TrieMap.empty[String, ChatDataProperty]
|
||||||
|
|
||||||
private lazy val chatDataAdapter = FXBeanAdapter[ChatData](this)
|
private lazy val chatDataAdapter = FXBeanAdapter[ChatData](this)
|
||||||
|
|
||||||
@ -108,7 +90,9 @@ class ChatController @Inject() (
|
|||||||
chatMainPane.hgrow = Priority.ALWAYS
|
chatMainPane.hgrow = Priority.ALWAYS
|
||||||
|
|
||||||
chatListView.selectionModel().selectionMode = SelectionMode.MULTIPLE
|
chatListView.selectionModel().selectionMode = SelectionMode.MULTIPLE
|
||||||
chatListView.setCellFactory(_ => new ChatListCell())
|
chatListView.setCellFactory(_ =>
|
||||||
|
new ChatListCell(appDataHandler.appData.credentials.username)
|
||||||
|
)
|
||||||
|
|
||||||
chatDataAdapter.set(FXBean(ChatData.empty))
|
chatDataAdapter.set(FXBean(ChatData.empty))
|
||||||
|
|
||||||
@ -149,6 +133,8 @@ class ChatController @Inject() (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usersListView.items <== usersListProperty
|
||||||
|
|
||||||
usersListView
|
usersListView
|
||||||
.selectionModel()
|
.selectionModel()
|
||||||
.selectedItemProperty()
|
.selectedItemProperty()
|
||||||
@ -164,10 +150,45 @@ class ChatController @Inject() (
|
|||||||
}
|
}
|
||||||
chatDataAdapter.set(chatDataBean)
|
chatDataAdapter.set(chatDataBean)
|
||||||
maybeCDP.foreach(cdp => {
|
maybeCDP.foreach(cdp => {
|
||||||
|
cdp.messages().clear()
|
||||||
lastActiveLabel.text <== cdp.lastActive
|
lastActiveLabel.text <== cdp.lastActive
|
||||||
isOnlineLabel.text <== cdp.isActive.asString()
|
isOnlineLabel.text <== cdp.isActive.asString()
|
||||||
chatListView.items <== cdp.messages
|
// chatListView.items <== cdp.messages
|
||||||
|
// logger.debug(s"1 ${cdp.messages}")
|
||||||
})
|
})
|
||||||
|
async {
|
||||||
|
val maybeMessages = await {
|
||||||
|
offFXAndWait {
|
||||||
|
userService
|
||||||
|
.getMessages(appDataHandler.appData.credentials, nv.userName)
|
||||||
|
.map(_.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug(maybeMessages.toString)
|
||||||
|
onFX {
|
||||||
|
// maybeMessages.foreach(
|
||||||
|
// _.map(m =>
|
||||||
|
// maybeCDP.foreach(cdp => {
|
||||||
|
// cdp.messages() ++= m
|
||||||
|
// // logger.debug(
|
||||||
|
// // s"2 ${chatDataStore.get(nv.userName).map(_.messages())}"
|
||||||
|
// // )
|
||||||
|
// chatListView.items <== cdp.messages
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
for {
|
||||||
|
tryMessages <- maybeMessages
|
||||||
|
messages <- tryMessages.toEither
|
||||||
|
cdp <- maybeCDP.toRight("CDP is null")
|
||||||
|
_ <- Right {
|
||||||
|
cdp.messages ++= messages
|
||||||
|
chatListView.items <== cdp.messages
|
||||||
|
}
|
||||||
|
} yield ()
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -185,12 +206,6 @@ class ChatController @Inject() (
|
|||||||
chatListMenu.items += copyMessageMenuItem
|
chatListMenu.items += copyMessageMenuItem
|
||||||
chatListView.contextMenu = chatListMenu
|
chatListView.contextMenu = chatListMenu
|
||||||
|
|
||||||
usersListView.items <== usersListProperty
|
|
||||||
|
|
||||||
val validator = new Validator()
|
|
||||||
|
|
||||||
submitButton.disable <== validator.containsErrorsProperty()
|
|
||||||
|
|
||||||
submitButton.onAction = (e) => {
|
submitButton.onAction = (e) => {
|
||||||
if (!chatInput.text().equals("") &&
|
if (!chatInput.text().equals("") &&
|
||||||
!chatInput.text().equals(" ") &&
|
!chatInput.text().equals(" ") &&
|
||||||
@ -203,11 +218,19 @@ class ChatController @Inject() (
|
|||||||
// cdp.username(),
|
// cdp.username(),
|
||||||
// chatInput.text()
|
// chatInput.text()
|
||||||
// )
|
// )
|
||||||
cdp.messages += Message.empty.copy(message = chatInput.text())
|
cdp.messages += Message(
|
||||||
|
fromUser = appDataHandler.appData.credentials.username,
|
||||||
|
toUser = chatDataAdapter.get.bean.userName,
|
||||||
|
chatInput.text(),
|
||||||
|
Instant.now()
|
||||||
|
)
|
||||||
|
// Message.empty.copy(message = chatInput.text()) +=: cdp.messages()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val validator = new Validator()
|
||||||
|
|
||||||
validator
|
validator
|
||||||
.createCheck()
|
.createCheck()
|
||||||
.withMethod(c => {
|
.withMethod(c => {
|
||||||
@ -245,17 +268,28 @@ class ChatController @Inject() (
|
|||||||
maybeActiveUsers.foreach(users => usersBuffer ++= users)
|
maybeActiveUsers.foreach(users => usersBuffer ++= users)
|
||||||
}
|
}
|
||||||
|
|
||||||
chatDataStore
|
// chatDataStore
|
||||||
.map { case (key, value) => value }
|
// .map { case (key, value) => value }
|
||||||
.foreach(cdp => {
|
// .foreach(cdp => {
|
||||||
cdp.messages ++= Seq(
|
// cdp.messages ++= Seq(
|
||||||
Message.empty.copy(message = "hi"),
|
// Message.empty.copy(message = "hi"),
|
||||||
Message.empty.copy(message = "hello"),
|
// Message.empty.copy(message = "hello"),
|
||||||
Message.empty.copy(message = "bye")
|
// Message.empty.copy(message = "bye")
|
||||||
)
|
// )
|
||||||
|
// })
|
||||||
|
|
||||||
|
// simulate update
|
||||||
|
val maybeCDP = for {
|
||||||
|
usersMap <- maybeActiveUsers.map(_.groupBy(_.userName))
|
||||||
|
user <- usersMap.get("user1").toRight("")
|
||||||
|
cdp <- chatDataStore.get("user1").toRight("")
|
||||||
|
} yield (cdp)
|
||||||
|
maybeCDP.foreach(cdp => {
|
||||||
|
cdp.isActive() = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def func() = {
|
def func() = {
|
||||||
val x = offFXAndWait {
|
val x = offFXAndWait {
|
||||||
2 + 3
|
2 + 3
|
||||||
@ -272,6 +306,9 @@ class ChatController @Inject() (
|
|||||||
chatDataAdapter.set(FXBean(ChatData.empty))
|
chatDataAdapter.set(FXBean(ChatData.empty))
|
||||||
usersListView.items().clear()
|
usersListView.items().clear()
|
||||||
chatListView.items().clear()
|
chatListView.items().clear()
|
||||||
|
// chatDataStore.foreach {
|
||||||
|
// case (_, cdp) => cdp.messages.clear()
|
||||||
|
// }
|
||||||
chatDataStore.clear()
|
chatDataStore.clear()
|
||||||
usersBuffer.clear()
|
usersBuffer.clear()
|
||||||
chatInput.clear()
|
chatInput.clear()
|
||||||
@ -291,55 +328,42 @@ final case class ChatData(
|
|||||||
.getOrElse("User has not logged in yet")
|
.getOrElse("User has not logged in yet")
|
||||||
lazy val onlineString = activeUser.online.toString()
|
lazy val onlineString = activeUser.online.toString()
|
||||||
}
|
}
|
||||||
object ChatData {
|
final object ChatData {
|
||||||
def empty = {
|
def empty = {
|
||||||
ChatData("empty", ActiveUser.empty, ObservableBuffer.empty[Message])
|
ChatData("empty", ActiveUser.empty, ObservableBuffer.empty[Message])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class ChatDataProperty(chatData: ChatData) {
|
final class ChatDataProperty(chatData: ChatData) {
|
||||||
val bean = FXBean(chatData)
|
val bean = FXBean(chatData)
|
||||||
val username = bean.getStringProperty("userName")
|
val username = bean.getStringProperty("userName")
|
||||||
val isActive = bean.getBooleanProperty("activeUser.online")
|
val isActive = bean.getBooleanProperty("activeUser.online")
|
||||||
val lastActive = bean.getStringProperty("lastActiveString")
|
val lastActive = bean.getStringProperty("lastActiveString")
|
||||||
val messages = BufferProperty(chatData.messages)
|
val messages = BufferProperty(chatData.messages)
|
||||||
}
|
|
||||||
|
|
||||||
final case class Message(
|
def updateItem(chatData: ChatData) = {
|
||||||
fromUser: String,
|
username() = chatData.userName
|
||||||
toUser: String,
|
isActive() = chatData.activeUser.online
|
||||||
message: String,
|
lastActive() = chatData.lastActiveString
|
||||||
messageTime: Instant
|
messages() ++= chatData.messages
|
||||||
)
|
|
||||||
object Message {
|
|
||||||
lazy val markdownStyleSheet =
|
|
||||||
getClass().getResource("/styles/markdown.css").toExternalForm()
|
|
||||||
|
|
||||||
def empty = Message("", "", "", Instant.MIN)
|
|
||||||
|
|
||||||
def createMdMessageBox(
|
|
||||||
message: Message
|
|
||||||
) = {
|
|
||||||
val mdfxNode = new MDFXNode(message.message);
|
|
||||||
mdfxNode
|
|
||||||
.getStylesheets()
|
|
||||||
.add(markdownStyleSheet)
|
|
||||||
mdfxNode.setMaxWidth(500)
|
|
||||||
mdfxNode.vgrow = Priority.ALWAYS
|
|
||||||
mdfxNode.setAlignment(Pos.CENTER)
|
|
||||||
mdfxNode.styleClass = Seq("chat-message-box")
|
|
||||||
|
|
||||||
val box = new HBox()
|
|
||||||
box.setAlignment(Pos.CENTER_RIGHT)
|
|
||||||
// box.maxWidth(500)
|
|
||||||
box.hgrow = Priority.ALWAYS
|
|
||||||
box.vgrow = Priority.ALWAYS
|
|
||||||
box.children ++= Seq(mdfxNode)
|
|
||||||
box.fillHeight = true
|
|
||||||
box
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ChatListCell extends ListCell[Message] {
|
final case class EncryptedMessage(
|
||||||
|
fromUser: String,
|
||||||
|
toUser: String,
|
||||||
|
messageCipher: MessageCipher,
|
||||||
|
messageTime: ZonedDateTime
|
||||||
|
) {
|
||||||
|
def toMessage(
|
||||||
|
passphrase: String,
|
||||||
|
decryptionFn: (String, MessageCipher) => Try[String]
|
||||||
|
): Try[Message] =
|
||||||
|
decryptionFn(passphrase, this.messageCipher)
|
||||||
|
.map(ms => Message(this.fromUser, this.toUser, ms, messageTime.toInstant))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ChatListCell(principal: String) extends ListCell[Message] {
|
||||||
private val messageBox = new MessageBox()
|
private val messageBox = new MessageBox()
|
||||||
override def updateItem(item: Message, empty: Boolean): Unit = {
|
override def updateItem(item: Message, empty: Boolean): Unit = {
|
||||||
super.updateItem(item, empty)
|
super.updateItem(item, empty)
|
||||||
@ -349,7 +373,11 @@ final class ChatListCell extends ListCell[Message] {
|
|||||||
} else {
|
} else {
|
||||||
// messageBox.setItem(item)
|
// messageBox.setItem(item)
|
||||||
// setGraphic(messageBox)
|
// setGraphic(messageBox)
|
||||||
setGraphic(Message.createMdMessageBox(item))
|
if (principal.equals(item.fromUser)) {
|
||||||
|
setGraphic(Message.createMdMessageBox(item, MessageType.Sender))
|
||||||
|
} else {
|
||||||
|
setGraphic(Message.createMdMessageBox(item, MessageType.Receiver))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
package wow.doge.chatto.controller
|
package wow.doge.chatto.controller
|
||||||
|
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
import com.sfxcode.sapphire.core.controller.ViewController
|
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import com.jfoenix.controls.JFXButton
|
import com.jfoenix.controls.JFXButton
|
||||||
import com.jfoenix.controls.JFXTextField
|
import com.jfoenix.controls.JFXTextField
|
||||||
import com.jfoenix.controls.JFXPasswordField
|
import com.jfoenix.controls.JFXPasswordField
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import scalafx.event.ActionEvent
|
|
||||||
import com.sfxcode.sapphire.core.value.KeyBindings
|
|
||||||
import scalafx.scene.layout.VBox
|
|
||||||
import com.sfxcode.sapphire.core.value.FXBean
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import com.sfxcode.sapphire.core.value.FXBeanAdapter
|
|
||||||
import wow.doge.chatto.service.UserService
|
import wow.doge.chatto.service.UserService
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.util.Success
|
import scala.util.Success
|
||||||
@ -20,18 +14,13 @@ import scala.util.Failure
|
|||||||
import javafx.scene.control.Label
|
import javafx.scene.control.Label
|
||||||
import javafx.scene.input.KeyCode
|
import javafx.scene.input.KeyCode
|
||||||
import scala.async.Async.{async, await}
|
import scala.async.Async.{async, await}
|
||||||
import wow.doge.chatto.AppData
|
|
||||||
import wow.doge.chatto.UserCredentials
|
import wow.doge.chatto.UserCredentials
|
||||||
import sttp.client._
|
import sttp.client._
|
||||||
import scala.concurrent.Future
|
|
||||||
import sttp.client.asynchttpclient.WebSocketHandler
|
|
||||||
import wow.doge.chatto.types.AppTypes.HttpBackend
|
import wow.doge.chatto.types.AppTypes.HttpBackend
|
||||||
import wow.doge.chatto.types.AppTypes
|
import wow.doge.chatto.types.AppTypes
|
||||||
import org.scalafx.extras._
|
import org.scalafx.extras._
|
||||||
import wow.doge.chatto.AppDataHandler
|
import wow.doge.chatto.AppDataHandler
|
||||||
import com.sfxcode.sapphire.core.value.BeanConversions
|
import com.sfxcode.sapphire.core.value.BeanConversions
|
||||||
import javafx.scene.layout.StackPane
|
|
||||||
import com.jfoenix.controls.JFXSpinner
|
|
||||||
|
|
||||||
class LoginController @Inject() (
|
class LoginController @Inject() (
|
||||||
userService: UserService,
|
userService: UserService,
|
||||||
|
@ -2,18 +2,13 @@ package wow.doge.chatto.controller
|
|||||||
|
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import javafx.scene.control.MenuBar
|
import javafx.scene.control.MenuBar
|
||||||
import javafx.scene.layout.Pane
|
|
||||||
import javax.enterprise.event.Observes
|
|
||||||
|
|
||||||
import com.sfxcode.sapphire.core.controller.ViewController
|
import com.sfxcode.sapphire.core.controller.ViewController
|
||||||
import com.sfxcode.sapphire.core.scene.{ContentDidChangeEvent, ContentManager}
|
import com.sfxcode.sapphire.core.scene.ContentManager
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
import wow.doge.chatto.messagebuble.BubbledMDFXNode
|
|
||||||
import scalafx.scene.layout.GridPane
|
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import javafx.scene.layout.HBox
|
import javafx.scene.layout.HBox
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
import wow.doge.chatto.control.UserBox
|
|
||||||
|
|
||||||
class MainViewController extends ViewController with LazyLogging {
|
class MainViewController extends ViewController with LazyLogging {
|
||||||
|
|
||||||
|
58
src/main/scala/wow/doge/chatto/model/Message.scala
Normal file
58
src/main/scala/wow/doge/chatto/model/Message.scala
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package wow.doge.chatto.model
|
||||||
|
|
||||||
|
import java.time.Instant
|
||||||
|
import com.sandec.mdfx.MDFXNode
|
||||||
|
import javafx.scene.layout.HBox
|
||||||
|
import scalafx.Includes._
|
||||||
|
import javafx.scene.layout.Priority
|
||||||
|
import javafx.geometry.Pos
|
||||||
|
import wow.doge.chatto.model.MessageType.Sender
|
||||||
|
import wow.doge.chatto.model.MessageType.Receiver
|
||||||
|
|
||||||
|
final case class Message(
|
||||||
|
fromUser: String,
|
||||||
|
toUser: String,
|
||||||
|
message: String,
|
||||||
|
messageTime: Instant
|
||||||
|
)
|
||||||
|
object Message {
|
||||||
|
lazy val markdownStyleSheet =
|
||||||
|
getClass().getResource("/styles/markdown.css").toExternalForm()
|
||||||
|
|
||||||
|
def empty = Message("", "", "", Instant.MIN)
|
||||||
|
|
||||||
|
def createMdMessageBox(
|
||||||
|
message: Message,
|
||||||
|
messageType: MessageType
|
||||||
|
) = {
|
||||||
|
val mdfxNode = new MDFXNode(message.message);
|
||||||
|
mdfxNode
|
||||||
|
.getStylesheets()
|
||||||
|
.add(markdownStyleSheet)
|
||||||
|
mdfxNode.setMaxWidth(500)
|
||||||
|
mdfxNode.vgrow = Priority.ALWAYS
|
||||||
|
mdfxNode.setAlignment(Pos.CENTER)
|
||||||
|
mdfxNode.styleClass = messageType match {
|
||||||
|
case Sender => Seq("chat-message-sender-box")
|
||||||
|
case Receiver => Seq("chat-message-receiver-box")
|
||||||
|
}
|
||||||
|
|
||||||
|
val box = new HBox()
|
||||||
|
messageType match {
|
||||||
|
case Receiver => box.setAlignment(Pos.CENTER_LEFT)
|
||||||
|
case Sender => box.setAlignment(Pos.CENTER_RIGHT)
|
||||||
|
}
|
||||||
|
// box.maxWidth(500)
|
||||||
|
box.hgrow = Priority.ALWAYS
|
||||||
|
box.vgrow = Priority.ALWAYS
|
||||||
|
box.children ++= Seq(mdfxNode)
|
||||||
|
box.fillHeight = true
|
||||||
|
box
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait MessageType
|
||||||
|
object MessageType {
|
||||||
|
case object Sender extends MessageType
|
||||||
|
case object Receiver extends MessageType
|
||||||
|
}
|
30
src/main/scala/wow/doge/chatto/model/MessageCipher.scala
Normal file
30
src/main/scala/wow/doge/chatto/model/MessageCipher.scala
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package wow.doge.chatto.model
|
||||||
|
|
||||||
|
import org.json4s.FieldSerializer
|
||||||
|
import org.json4s.FieldSerializer._
|
||||||
|
|
||||||
|
case class MessageCipher(
|
||||||
|
iv: String,
|
||||||
|
v: Int,
|
||||||
|
iterations: Int,
|
||||||
|
keySize: Int,
|
||||||
|
tagSize: Int,
|
||||||
|
mode: String,
|
||||||
|
adata: String,
|
||||||
|
cipher: String,
|
||||||
|
salt: String,
|
||||||
|
cipherText: String
|
||||||
|
)
|
||||||
|
|
||||||
|
object MessageCipher {
|
||||||
|
val rename = FieldSerializer[MessageCipher](
|
||||||
|
renameTo("iterations", "iter") orElse
|
||||||
|
renameTo("keySize", "ks") orElse
|
||||||
|
renameTo("tagSize", "ts") orElse
|
||||||
|
renameTo("cipherText", "ct"),
|
||||||
|
renameFrom("iter", "iterations") orElse
|
||||||
|
renameFrom("ks", "keySize") orElse
|
||||||
|
renameFrom("ts", "tagSize") orElse
|
||||||
|
renameFrom("ct", "cipherText")
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package wow.doge.chatto.service
|
||||||
|
|
||||||
|
import wow.doge.chatto.model.MessageCipher
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
trait EncryptionService {
|
||||||
|
|
||||||
|
def encrypt(password: String, plainText: String): String Either MessageCipher
|
||||||
|
def decrypt(password: String, cipher: MessageCipher): Try[String]
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
package wow.doge.chatto.service
|
||||||
|
|
||||||
|
import wow.doge.chatto.model.MessageCipher;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
class EncryptionServiceImpl extends EncryptionService {
|
||||||
|
|
||||||
|
override def encrypt(
|
||||||
|
password: String,
|
||||||
|
plainText: String
|
||||||
|
): String Either MessageCipher = {
|
||||||
|
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||||
|
val secureRandom = new SecureRandom()
|
||||||
|
val saltLength = 12
|
||||||
|
val keyLength = 128
|
||||||
|
val iterationCount = 10000
|
||||||
|
val tagSize = 128
|
||||||
|
|
||||||
|
val encode = (bytes: Array[Byte]) =>
|
||||||
|
Base64.getEncoder().encodeToString(bytes)
|
||||||
|
|
||||||
|
val salt = Array(saltLength.toByte)
|
||||||
|
secureRandom.nextBytes(salt)
|
||||||
|
val nonce = Array(12.toByte)
|
||||||
|
secureRandom.nextBytes(nonce)
|
||||||
|
|
||||||
|
// val spec =
|
||||||
|
// new PBEKeySpec(password.toCharArray(), salt, iterationCount, keyLength)
|
||||||
|
|
||||||
|
// val tmp = factory.generateSecret(spec)
|
||||||
|
// val secretKey = new SecretKeySpec(tmp.getEncoded(), "AES")
|
||||||
|
// val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
||||||
|
// cipher.init(
|
||||||
|
// Cipher.ENCRYPT_MODE,
|
||||||
|
// secretKey,
|
||||||
|
// new GCMParameterSpec(128, nonce)
|
||||||
|
// )
|
||||||
|
|
||||||
|
// val cipherTextByte = cipher.doFinal(plainText.getBytes)
|
||||||
|
|
||||||
|
val messageCipher = for {
|
||||||
|
factory <- {
|
||||||
|
Try(SecretKeyFactory.getInstance("PBKDFWithHmacSHA56")).toOption
|
||||||
|
.toRight("Failed to get skf instance")
|
||||||
|
}
|
||||||
|
|
||||||
|
spec <- {
|
||||||
|
Try(
|
||||||
|
new PBEKeySpec(
|
||||||
|
password.toCharArray(),
|
||||||
|
salt,
|
||||||
|
iterationCount,
|
||||||
|
keyLength
|
||||||
|
)
|
||||||
|
).toOption.toRight("Failed to get pbekeyspec")
|
||||||
|
}
|
||||||
|
|
||||||
|
secret <- Try(factory.generateSecret(spec)).toOption
|
||||||
|
.toRight("Failed to get secret")
|
||||||
|
|
||||||
|
secretKey <- Try(new SecretKeySpec(secret.getEncoded(), "AES")).toOption
|
||||||
|
.toRight("Failed to get secret key")
|
||||||
|
|
||||||
|
cipher <- Try(Cipher.getInstance("AES/GCM/NoPadding")).toOption
|
||||||
|
.toRight("Failed to get cipher instance")
|
||||||
|
_ <- Right(
|
||||||
|
cipher.init(
|
||||||
|
Cipher.ENCRYPT_MODE,
|
||||||
|
secretKey,
|
||||||
|
new GCMParameterSpec(128, nonce)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
cipherTextByte <- Try(cipher.doFinal(plainText.getBytes())).toOption
|
||||||
|
.toRight("Failed to generate cipher")
|
||||||
|
|
||||||
|
messageCipher = MessageCipher(
|
||||||
|
v = 1,
|
||||||
|
salt = encode(salt),
|
||||||
|
mode = "gcm",
|
||||||
|
iterations = iterationCount,
|
||||||
|
cipher = "aes",
|
||||||
|
adata = "",
|
||||||
|
cipherText = encode(cipherTextByte),
|
||||||
|
iv = encode(nonce),
|
||||||
|
keySize = keyLength,
|
||||||
|
tagSize = tagSize
|
||||||
|
)
|
||||||
|
} yield (messageCipher)
|
||||||
|
|
||||||
|
messageCipher
|
||||||
|
}
|
||||||
|
|
||||||
|
override def decrypt(
|
||||||
|
password: String,
|
||||||
|
messageCipher: MessageCipher
|
||||||
|
): Try[String] = {
|
||||||
|
val decode = (text: String) => {
|
||||||
|
Base64.getDecoder().decode(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
Try {
|
||||||
|
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||||
|
val spec = new PBEKeySpec(
|
||||||
|
password.toCharArray(),
|
||||||
|
decode(messageCipher.salt),
|
||||||
|
messageCipher.iterations,
|
||||||
|
messageCipher.keySize
|
||||||
|
);
|
||||||
|
val tmp = factory.generateSecret(spec);
|
||||||
|
val secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
|
||||||
|
|
||||||
|
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
||||||
|
cipher.init(
|
||||||
|
Cipher.DECRYPT_MODE,
|
||||||
|
secretKey,
|
||||||
|
new GCMParameterSpec(128, decode(messageCipher.iv))
|
||||||
|
);
|
||||||
|
new String(cipher.doFinal(decode(messageCipher.cipherText)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object EncryptionServiceImpl {
|
||||||
|
def apply() = new EncryptionServiceImpl()
|
||||||
|
}
|
@ -1,93 +1,71 @@
|
|||||||
package wow.doge.chatto.service
|
package wow.doge.chatto.service
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
|
||||||
import scala.async.Async.{async, await}
|
|
||||||
import sttp.client.json4s._
|
import sttp.client.json4s._
|
||||||
import org.json4s._
|
import org.json4s._
|
||||||
import sttp.client._
|
import sttp.client._
|
||||||
import scala.concurrent.Future
|
|
||||||
import sttp.client.asynchttpclient.WebSocketHandler
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import scala.util.Success
|
|
||||||
import scala.util.Failure
|
|
||||||
import wow.doge.chatto.AppData
|
|
||||||
import wow.doge.chatto.types.AppTypes.HttpBackend
|
import wow.doge.chatto.types.AppTypes.HttpBackend
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
import org.scalafx.extras._
|
|
||||||
import wow.doge.chatto.ApplicationController
|
|
||||||
import wow.doge.chatto.UserCredentials
|
import wow.doge.chatto.UserCredentials
|
||||||
import javax.inject._
|
import javax.inject._
|
||||||
import wow.doge.chatto.AppDataHandler
|
import wow.doge.chatto.AppDataHandler
|
||||||
import org.json4s.jackson.JsonMethods._
|
|
||||||
import org.json4s.ext.JavaTimeSerializers
|
import org.json4s.ext.JavaTimeSerializers
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import org.json4s.jackson.Serialization._
|
import wow.doge.chatto.model.MessageCipher
|
||||||
|
import wow.doge.chatto.controller.EncryptedMessage
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
class UserService @Inject() (appDataHandler: AppDataHandler)(
|
class UserService @Inject() (
|
||||||
|
appDataHandler: AppDataHandler,
|
||||||
|
encryptionService: EncryptionService
|
||||||
|
)(
|
||||||
implicit backend: HttpBackend
|
implicit backend: HttpBackend
|
||||||
) extends LazyLogging {
|
) extends LazyLogging {
|
||||||
private implicit lazy val serialization = org.json4s.jackson.Serialization
|
private implicit lazy val serialization = org.json4s.jackson.Serialization
|
||||||
private implicit lazy val formats =
|
private implicit lazy val formats =
|
||||||
DefaultFormats ++ JavaTimeSerializers.all
|
DefaultFormats ++ JavaTimeSerializers.all + MessageCipher.rename
|
||||||
private val domain = "http://localhost:8080"
|
private val domain = "http://localhost:8080"
|
||||||
private lazy val baseUrl = uri"$domain/api/chat"
|
private lazy val baseUrl = uri"$domain/api/chat"
|
||||||
// private lazy val authBasicRequest = (credentials: UserCredentials) =>
|
|
||||||
// basicRequest.auth
|
|
||||||
// .basic(credentials.username, credentials.password)
|
|
||||||
// .header("X-AUTH-TOKEN", credentials.token)
|
|
||||||
private lazy val tokenBasicRequest = (token: String) => {
|
private lazy val tokenBasicRequest = (token: String) => {
|
||||||
basicRequest.header("X-AUTH-TOKEN", token)
|
basicRequest.header("X-AUTH-TOKEN", token)
|
||||||
}
|
}
|
||||||
|
|
||||||
def func1() = async {
|
|
||||||
val willBeResponse = func2()
|
|
||||||
val r = await { willBeResponse }
|
|
||||||
r.body.map(println)
|
|
||||||
}
|
|
||||||
|
|
||||||
def func2() =
|
|
||||||
basicRequest
|
|
||||||
.get(uri"https://httpbin.org/get")
|
|
||||||
.response(asJson[HttpBinResponse])
|
|
||||||
.send()
|
|
||||||
|
|
||||||
private def endpoint(uri: String) = uri"$baseUrl/$uri"
|
private def endpoint(uri: String) = uri"$baseUrl/$uri"
|
||||||
|
|
||||||
def getUsers(credentials: UserCredentials) = async {
|
def getUsers(credentials: UserCredentials) =
|
||||||
// logger.debug(s"${appDataHandler.appData}")
|
|
||||||
// println(
|
|
||||||
// write[ActiveUser](
|
|
||||||
// ActiveUser("hmm what is it", true, Some(ZonedDateTime.now()))
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
await {
|
|
||||||
// authBasicRequest(credentials)
|
|
||||||
tokenBasicRequest(credentials.token)
|
tokenBasicRequest(credentials.token)
|
||||||
.get(uri"http://localhost:8080/api/chat/get/users")
|
.get(uri"http://localhost:8080/api/chat/get/users")
|
||||||
.response(asJson[List[String]])
|
.response(asJson[List[String]])
|
||||||
.send()
|
.send()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getMessages(credentials: UserCredentials) = async {
|
def getEncryptedMessages(credentials: UserCredentials, user: String) =
|
||||||
// logger.debug(s"${appDataHandler.appData}")
|
Request
|
||||||
await {
|
.messagesPaginated(credentials, user)
|
||||||
// authBasicRequest(credentials)
|
.send()
|
||||||
tokenBasicRequest(credentials.token)
|
|
||||||
.get(uri"http://localhost:8080/api/chat/get/users")
|
def getMessages(credentials: UserCredentials, user: String) =
|
||||||
.response(asJson[List[String]])
|
Request
|
||||||
|
.messagesPaginated(credentials, user)
|
||||||
|
.mapResponseRight(
|
||||||
|
_.map(_.toMessage("password", encryptionService.decrypt)).sequence
|
||||||
|
)
|
||||||
.send()
|
.send()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getActiveUsers(credentials: UserCredentials) =
|
def getActiveUsers(credentials: UserCredentials) =
|
||||||
// authBasicRequest(credentials)
|
|
||||||
tokenBasicRequest(credentials.token)
|
tokenBasicRequest(credentials.token)
|
||||||
.get(uri"http://localhost:8080/api/chat/get/active-users")
|
.get(uri"http://localhost:8080/api/chat/get/active-users")
|
||||||
.response(asJson[List[ActiveUser]])
|
.response(asJson[List[ActiveUser]])
|
||||||
.send()
|
.send()
|
||||||
|
|
||||||
|
object Request {
|
||||||
|
lazy val messagesPaginated = (credentials: UserCredentials, user: String) =>
|
||||||
|
tokenBasicRequest(credentials.token)
|
||||||
|
.get(
|
||||||
|
uri"http://localhost:8080/api/chat/get/messages/$user?page=0&size=9"
|
||||||
|
)
|
||||||
|
.response(asJson[List[EncryptedMessage]])
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class HttpBinResponse(
|
final case class HttpBinResponse(
|
||||||
|
Loading…
Reference in New Issue
Block a user