All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sss.openstar.rpc.UserSession.scala Maven / Gradle / Ivy

package sss.openstar.rpc


import akka.NotUsed
import akka.actor.{ActorContext, ActorRef}
import akka.stream.scaladsl.Source
import com.typesafe.scalalogging.Logger
import sss.ancillary.{Guid, LogFactory}
import sss.db.Db
import sss.openstar.account.NodeIdentity
import sss.openstar.chains.Chains.GlobalChainIdMask
import sss.openstar.contacts.ContactService
import sss.openstar.contacts.ContactService.LoggedInUser
import sss.openstar.controller.Send
import sss.openstar.html5push.Subscriptions
import sss.openstar.html5push.Subscriptions.Subscription
import sss.openstar.identityledger.{IdentityServiceQuery, MessageStoreProviders}
import sss.openstar.message.MessageDownloadActor.PublishUnProcessedMessages
import sss.openstar.message.MessageInBox.SavedMessage
import sss.openstar.message.MessagePaywall.MessagePaywallGenerator
import sss.openstar.message.payloads.MessageEcryption.{AttachmentDetails, MessageAttachments}
import sss.openstar.message.{MessageDownloadPersistCache, MessageInBox, OutgoingMessageProcessorUtil, UtxoQuery, UtxoWatch}
import sss.openstar.network.MessageEventBus
import sss.openstar.nodebuilder.MessageHandlingActors
import sss.openstar.rpc.RpcBridgeEventSource.RpcBridgeEventSourceShutdown
import sss.openstar.tools.SendTxSupport.SendTx
import sss.openstar.ui.rpc.Event
import sss.openstar.util.TryOps.LogTry
import sss.openstar.wallet.UnlockedWallet
import sss.openstar.wallet.UtxoTracker.TrackWallet
import sss.openstar.{Currency, UniqueNodeIdentifier}

import java.util.concurrent.atomic.AtomicReference

/**
  * Created by alan on 12/20/16.
  */



class MessageAttachmentsHolder(attachmentProviderName: UniqueNodeIdentifier) {
  private val ref = new AtomicReference[Map[Guid,MessageAttachments]](Map.empty)

  def clear(): Unit = {
    ref.set(Map.empty)
  }

  def apply(guid: Guid):MessageAttachments  = {
    ref.updateAndGet(currentMap => {
      currentMap + (guid -> currentMap.getOrElse(guid, MessageAttachments(attachmentProviderName)))
    })(guid)
  }

  def apply(guid: Guid, attachments: MessageAttachments): Unit = {
    ref.updateAndGet(currentMap => {
      currentMap + (guid -> attachments)
    })
  }

  def addDetails(guid: Guid, details: AttachmentDetails): Unit = {
    ref.updateAndGet(currentMap => {
      val attachments = currentMap.getOrElse(guid, MessageAttachments(attachmentProviderName))
      currentMap + (guid -> attachments.copy(
        attachmentDetails =
          attachments.attachmentDetails.filter(_.name != details.name) :+ details))
    })
  }

  def getAttachments(guid: Guid): Option[MessageAttachments] = {
    ref.get().get(guid)
  }

}
case class UserSession[BASECURRENCY <: Currency](messageHandlingActors: Option[MessageHandlingActors],
                                          loggedInUser: LoggedInUser,
                                          messageAttachments: MessageAttachmentsHolder,
                                          userAdaWallet: UnlockedWallet[BASECURRENCY]
                       )(
                                           implicit val nodeId: NodeIdentity,
                                           actorContext: ActorContext,
                                           events: MessageEventBus,
                                           //val userStarzWallet: UnlockedWallet[Starz],
                                           db: Db) {


  lazy val messages: MessageInBox = MessageInBox(nodeId.id)

  lazy implicit val guidToSavedMessage: Guid => Option[SavedMessage] = messages.find

  def update(updatedLoggedInUser: LoggedInUser): UserSession[BASECURRENCY] = copy(loggedInUser = updatedLoggedInUser)

  def createEventSource: Source[Event, NotUsed] = RpcBridgeEventSource(nodeId.id, userAdaWallet.w.ledgerId)
}

object UserSessionFactory {
  type LookUpMessageByGuid = Guid => Option[SavedMessage]
}

class UserSessionFactory[BASECURRENCY <: Currency] {

  implicit val log: Logger = LogFactory.getLogger(this.getClass.toString)


  def apply(sessId: String): Option[UserSession[BASECURRENCY]] = {
    val all = allSessions.get()
    all.get(sessId)
  }

  def update(sessId: String, updated: UserSession[BASECURRENCY]): UserSession[BASECURRENCY] = {
    allSessions.updateAndGet(
      _ + (sessId -> updated)
    )(sessId)
  }

  def remove(sessId: String)(implicit events: MessageEventBus): Unit = synchronized {
    allSessions.getAndUpdate(
      _ - sessId
    ).get(sessId).foreach { sess =>
      sess.messageHandlingActors.foreach(_.stop())
      events publish RpcBridgeEventSourceShutdown(sess.nodeId.id)
    }

  }

  def register(sessId: String,
               nodeIdentity: NodeIdentity,
               hostingNodeIdentity: String,
               //starzUserWallet: UnlockedWallet[Starz],
               adaUserWallet: UnlockedWallet[BASECURRENCY],
               subscriptionOpt: Option[Subscription],
               messageInBoxActorGroup: ActorRef)
              (implicit db: Db,
               subscriptions: Subscriptions,
               persistCache: MessageDownloadPersistCache,
               utxoWatch: UtxoWatch,
               utxoQuery: UtxoQuery,
               personalPaywallGenerator: MessagePaywallGenerator[BASECURRENCY],
               outgoingMessageProcessorUtil: OutgoingMessageProcessorUtil,
               events: MessageEventBus,
               identityService: IdentityServiceQuery,
               contactService: ContactService,
               actorContext: ActorContext,
               send: Send,
               sendTx: SendTx,
               chainId: GlobalChainIdMask
              ): Map[String, UserSession[BASECURRENCY]] = synchronized {

    remove(sessId)
    // TODO remove same user already logged in removeUser(nodeIdentity.id)

    implicit val imNodeIdentity = nodeIdentity
    //implicit val imUserWallet = starzUserWallet

    val messageHandlingActorsOpt = if(nodeIdentity.id == hostingNodeIdentity) {
      None
    } else Some(
      MessageHandlingActors.addMessageHandlingActors[BASECURRENCY](adaUserWallet, nodeIdentity, messageInBoxActorGroup)
    )


    //Don't delete subscriptions if they down't exist, only update them if they do
    subscriptionOpt.map ( _ =>
      subscriptions.persist(nodeIdentity.id, subscriptionOpt)
        .andLog("subscriptions.persist")
    )


    val balance = adaUserWallet.w.balance().get

    //events publish TrackWallet[Starz](starzUserWallet.w, balance)
    events publish TrackWallet[BASECURRENCY](adaUserWallet.w, balance)
    events publish PublishUnProcessedMessages(nodeIdentity.id)

    val providers = identityService.messageStores(nodeIdentity.id)
    events publish MessageStoreProviders(nodeIdentity.id, providers)

    val loggedInUser = contactService.findUser(nodeIdentity.id).getOrElse {
      contactService.addContact(nodeIdentity.id)
      contactService.findUser(nodeIdentity.id).get
    }

    val attachmentsHolder = new MessageAttachmentsHolder(hostingNodeIdentity)

    allSessions.updateAndGet(
      _ + (sessId -> UserSession[BASECURRENCY](
        messageHandlingActorsOpt,
        loggedInUser,
        attachmentsHolder,
        adaUserWallet))
    )
  }


  private val allSessions: AtomicReference[Map[String, UserSession[BASECURRENCY]]] = new AtomicReference(Map.empty)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy