Refactored class layout of core package.
This commit is contained in:
parent
7c9c6803dc
commit
882b518a7c
65 changed files with 330 additions and 295 deletions
|
@ -12,7 +12,7 @@ import android.widget.AdapterView.OnItemClickListener
|
||||||
import android.widget._
|
import android.widget._
|
||||||
import com.google.zxing.integration.android.IntentIntegrator
|
import com.google.zxing.integration.android.IntentIntegrator
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.service.CallbackHandler
|
import com.nutomic.ensichat.service.CallbackHandler
|
||||||
import com.nutomic.ensichat.views.UsersAdapter
|
import com.nutomic.ensichat.views.UsersAdapter
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import android.preference.PreferenceManager
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.fragments.{ChatFragment, ContactsFragment}
|
import com.nutomic.ensichat.fragments.{ChatFragment, ContactsFragment}
|
||||||
|
|
||||||
object MainActivity {
|
object MainActivity {
|
||||||
|
|
|
@ -8,9 +8,11 @@ import android.os.Handler
|
||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.body.ConnectionInfo
|
|
||||||
import com.nutomic.ensichat.core.interfaces.{SettingsInterface, TransmissionInterface}
|
import com.nutomic.ensichat.core.interfaces.{SettingsInterface, TransmissionInterface}
|
||||||
import com.nutomic.ensichat.core.{Address, ConnectionHandler, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.messages.body.ConnectionInfo
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.nutomic.ensichat.service.ChatService
|
import com.nutomic.ensichat.service.ChatService
|
||||||
import org.joda.time.{DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,13 @@ import java.io._
|
||||||
import android.bluetooth.{BluetoothDevice, BluetoothSocket}
|
import android.bluetooth.{BluetoothDevice, BluetoothSocket}
|
||||||
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.nutomic.ensichat.core.Message.ReadMessageException
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.body.ConnectionInfo
|
import Message.ReadMessageException
|
||||||
import com.nutomic.ensichat.core.header.MessageHeader
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.{Address, Crypto, Message}
|
import com.nutomic.ensichat.core.messages.body.ConnectionInfo
|
||||||
|
import com.nutomic.ensichat.core.messages.header.MessageHeader
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.util.Crypto
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,8 +12,10 @@ import android.widget.TextView.OnEditorActionListener
|
||||||
import android.widget._
|
import android.widget._
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.activities.EnsichatActivity
|
import com.nutomic.ensichat.activities.EnsichatActivity
|
||||||
import com.nutomic.ensichat.core.body.Text
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
import com.nutomic.ensichat.core.{Address, ConnectionHandler, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.nutomic.ensichat.service.CallbackHandler
|
import com.nutomic.ensichat.service.CallbackHandler
|
||||||
import com.nutomic.ensichat.views.{DatesAdapter, MessagesAdapter}
|
import com.nutomic.ensichat.views.{DatesAdapter, MessagesAdapter}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.content.{Intent, SharedPreferences}
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.{PreferenceFragment, PreferenceManager}
|
import android.preference.{PreferenceFragment, PreferenceManager}
|
||||||
import com.nutomic.ensichat.activities.EnsichatActivity
|
import com.nutomic.ensichat.activities.EnsichatActivity
|
||||||
import com.nutomic.ensichat.core.body.UserInfo
|
import com.nutomic.ensichat.core.messages.body.UserInfo
|
||||||
import com.nutomic.ensichat.core.interfaces.SettingsInterface._
|
import com.nutomic.ensichat.core.interfaces.SettingsInterface._
|
||||||
import com.nutomic.ensichat.fragments.SettingsFragment._
|
import com.nutomic.ensichat.fragments.SettingsFragment._
|
||||||
import com.nutomic.ensichat.service.ChatService
|
import com.nutomic.ensichat.service.ChatService
|
||||||
|
|
|
@ -9,7 +9,7 @@ import com.google.zxing.BarcodeFormat
|
||||||
import com.google.zxing.common.BitMatrix
|
import com.google.zxing.common.BitMatrix
|
||||||
import com.google.zxing.qrcode.QRCodeWriter
|
import com.google.zxing.qrcode.QRCodeWriter
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.util.IdenticonGenerator
|
import com.nutomic.ensichat.util.IdenticonGenerator
|
||||||
|
|
||||||
object UserInfoFragment {
|
object UserInfoFragment {
|
||||||
|
|
|
@ -3,7 +3,8 @@ package com.nutomic.ensichat.service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.support.v4.content.LocalBroadcastManager
|
import android.support.v4.content.LocalBroadcastManager
|
||||||
import com.nutomic.ensichat.core.interfaces.CallbackInterface
|
import com.nutomic.ensichat.core.interfaces.CallbackInterface
|
||||||
import com.nutomic.ensichat.core.{ConnectionHandler, Message}
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.service.CallbackHandler._
|
import com.nutomic.ensichat.service.CallbackHandler._
|
||||||
|
|
||||||
object CallbackHandler {
|
object CallbackHandler {
|
||||||
|
|
|
@ -9,8 +9,8 @@ import android.net.ConnectivityManager
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import com.nutomic.ensichat.bluetooth.BluetoothInterface
|
import com.nutomic.ensichat.bluetooth.BluetoothInterface
|
||||||
import com.nutomic.ensichat.core.interfaces.TransmissionInterface
|
import com.nutomic.ensichat.core.interfaces.TransmissionInterface
|
||||||
import com.nutomic.ensichat.core.util.Database
|
import com.nutomic.ensichat.core.util.{Crypto, Database}
|
||||||
import com.nutomic.ensichat.core.{ConnectionHandler, Crypto}
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.nutomic.ensichat.util.{NetworkChangedReceiver, SettingsWrapper}
|
import com.nutomic.ensichat.util.{NetworkChangedReceiver, SettingsWrapper}
|
||||||
|
|
||||||
object ChatService {
|
object ChatService {
|
||||||
|
|
|
@ -6,9 +6,9 @@ import android.preference.PreferenceManager
|
||||||
import android.support.v4.app.NotificationCompat
|
import android.support.v4.app.NotificationCompat
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.activities.MainActivity
|
import com.nutomic.ensichat.activities.MainActivity
|
||||||
import com.nutomic.ensichat.core.Message
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
import com.nutomic.ensichat.core.body.Text
|
|
||||||
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
||||||
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.service.NotificationHandler._
|
import com.nutomic.ensichat.service.NotificationHandler._
|
||||||
|
|
||||||
object NotificationHandler {
|
object NotificationHandler {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.nutomic.ensichat.util
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap.Config
|
import android.graphics.Bitmap.Config
|
||||||
import android.graphics.{Bitmap, Canvas, Color}
|
import android.graphics.{Bitmap, Canvas, Color}
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates a unique identicon for the given hash.
|
* Calculates a unique identicon for the given hash.
|
||||||
|
|
|
@ -5,7 +5,7 @@ import java.text.DateFormat
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.mobsandgeeks.adapters.{Sectionizer, SimpleSectionAdapter}
|
import com.mobsandgeeks.adapters.{Sectionizer, SimpleSectionAdapter}
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.Message
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
|
||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ import android.view._
|
||||||
import android.widget._
|
import android.widget._
|
||||||
import com.mobsandgeeks.adapters.{InstantAdapter, SimpleSectionAdapter, ViewHandler}
|
import com.mobsandgeeks.adapters.{InstantAdapter, SimpleSectionAdapter, ViewHandler}
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.body.Text
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
import com.nutomic.ensichat.core.{Address, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.views.MessagesAdapter._
|
import com.nutomic.ensichat.views.MessagesAdapter._
|
||||||
|
|
||||||
object MessagesAdapter {
|
object MessagesAdapter {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.view.View.OnClickListener
|
||||||
import android.view.{LayoutInflater, View, ViewGroup}
|
import android.view.{LayoutInflater, View, ViewGroup}
|
||||||
import android.widget.{ArrayAdapter, ImageView, TextView}
|
import android.widget.{ArrayAdapter, ImageView, TextView}
|
||||||
import com.nutomic.ensichat.R
|
import com.nutomic.ensichat.R
|
||||||
import com.nutomic.ensichat.core.User
|
import com.nutomic.ensichat.core.util.User
|
||||||
import com.nutomic.ensichat.fragments.UserInfoFragment
|
import com.nutomic.ensichat.fragments.UserInfoFragment
|
||||||
import com.nutomic.ensichat.util.IdenticonGenerator
|
import com.nutomic.ensichat.util.IdenticonGenerator
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ package com.nutomic.ensichat.core
|
||||||
|
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body._
|
|
||||||
import com.nutomic.ensichat.core.header.{AbstractHeader, ContentHeader, MessageHeader}
|
|
||||||
import com.nutomic.ensichat.core.interfaces._
|
import com.nutomic.ensichat.core.interfaces._
|
||||||
import com.nutomic.ensichat.core.internet.InternetInterface
|
import com.nutomic.ensichat.core.internet.InternetInterface
|
||||||
|
import com.nutomic.ensichat.core.messages.body._
|
||||||
|
import com.nutomic.ensichat.core.messages.header.{AbstractHeader, ContentHeader}
|
||||||
|
import com.nutomic.ensichat.core.routing.{MessageBuffer, Router}
|
||||||
import com.nutomic.ensichat.core.util._
|
import com.nutomic.ensichat.core.util._
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.joda.time.{DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
@ -30,22 +31,22 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
|
|
||||||
private lazy val seqNumGenerator = new SeqNumGenerator(settings)
|
private lazy val seqNumGenerator = new SeqNumGenerator(settings)
|
||||||
|
|
||||||
private val localRoutesInfo = new LocalRoutesInfo(connections)
|
private val localRoutesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
|
|
||||||
private val routeMessageInfo = new RouteMessageInfo()
|
private val routeMessageInfo = new routing.RouteMessageInfo()
|
||||||
|
|
||||||
private lazy val router = new Router(localRoutesInfo,
|
private lazy val router = new Router(localRoutesInfo,
|
||||||
(a, m) => transmissionInterfaces.foreach(_.send(a, m)),
|
(a, m) => transmissionInterfaces.foreach(_.send(a, m)),
|
||||||
noRouteFound)
|
noRouteFound)
|
||||||
|
|
||||||
private lazy val messageBuffer = new MessageBuffer(crypto.localAddress, requestRoute)
|
private lazy val messageBuffer = new routing.MessageBuffer(crypto.localAddress, requestRoute)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds all known users.
|
* Holds all known users.
|
||||||
*
|
*
|
||||||
* This is for user names that were received during runtime, and is not persistent.
|
* This is for user names that were received during runtime, and is not persistent.
|
||||||
*/
|
*/
|
||||||
private var knownUsers = Set[User]()
|
private var knownUsers = Set[util.User]()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates keys and starts Bluetooth interface.
|
* Generates keys and starts Bluetooth interface.
|
||||||
|
@ -80,7 +81,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
/**
|
/**
|
||||||
* Sends a new message to the given target address.
|
* Sends a new message to the given target address.
|
||||||
*/
|
*/
|
||||||
def sendTo(target: Address, body: MessageBody): Unit = {
|
def sendTo(target: routing.Address, body: MessageBody): Unit = {
|
||||||
assert(body.contentType != -1)
|
assert(body.contentType != -1)
|
||||||
FutureHelper {
|
FutureHelper {
|
||||||
val messageId = settings.get("message_id", 0L)
|
val messageId = settings.get("message_id", 0L)
|
||||||
|
@ -88,7 +89,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
body.contentType, Some(messageId), Some(DateTime.now), AbstractHeader.InitialForwardingTokens)
|
body.contentType, Some(messageId), Some(DateTime.now), AbstractHeader.InitialForwardingTokens)
|
||||||
settings.put("message_id", messageId + 1)
|
settings.put("message_id", messageId + 1)
|
||||||
|
|
||||||
val msg = new Message(header, body)
|
val msg = new messages.Message(header, body)
|
||||||
val encrypted = crypto.encryptAndSign(msg)
|
val encrypted = crypto.encryptAndSign(msg)
|
||||||
router.forwardMessage(encrypted)
|
router.forwardMessage(encrypted)
|
||||||
forwardMessageToRelays(encrypted)
|
forwardMessageToRelays(encrypted)
|
||||||
|
@ -96,34 +97,34 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def requestRoute(target: Address): Unit = {
|
private def requestRoute(target: routing.Address): Unit = {
|
||||||
assert(localRoutesInfo.getRoute(target).isEmpty)
|
assert(localRoutesInfo.getRoute(target).isEmpty)
|
||||||
val seqNum = seqNumGenerator.next()
|
val seqNum = seqNumGenerator.next()
|
||||||
val targetSeqNum = localRoutesInfo.getRoute(target).map(_.seqNum).getOrElse(-1)
|
val targetSeqNum = localRoutesInfo.getRoute(target).map(_.seqNum).getOrElse(-1)
|
||||||
val body = new RouteRequest(target, seqNum, targetSeqNum, 0)
|
val body = new RouteRequest(target, seqNum, targetSeqNum, 0)
|
||||||
val header = new MessageHeader(body.protocolType, crypto.localAddress, Address.Broadcast, seqNum, 0)
|
val header = new messages.header.MessageHeader(body.protocolType, crypto.localAddress, routing.Address.Broadcast, seqNum, 0)
|
||||||
|
|
||||||
val signed = crypto.sign(new Message(header, body))
|
val signed = crypto.sign(new messages.Message(header, body))
|
||||||
router.forwardMessage(signed)
|
router.forwardMessage(signed)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def replyRoute(target: Address, replyTo: Address): Unit = {
|
private def replyRoute(target: routing.Address, replyTo: routing.Address): Unit = {
|
||||||
val seqNum = seqNumGenerator.next()
|
val seqNum = seqNumGenerator.next()
|
||||||
val body = new RouteReply(seqNum, 0)
|
val body = new RouteReply(seqNum, 0)
|
||||||
val header = new MessageHeader(body.protocolType, crypto.localAddress, replyTo, seqNum, 0)
|
val header = new messages.header.MessageHeader(body.protocolType, crypto.localAddress, replyTo, seqNum, 0)
|
||||||
|
|
||||||
val signed = crypto.sign(new Message(header, body))
|
val signed = crypto.sign(new messages.Message(header, body))
|
||||||
router.forwardMessage(signed)
|
router.forwardMessage(signed)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def routeError(address: Address, packetSource: Option[Address]): Unit = {
|
private def routeError(address: routing.Address, packetSource: Option[routing.Address]): Unit = {
|
||||||
val destination = packetSource.getOrElse(Address.Broadcast)
|
val destination = packetSource.getOrElse(routing.Address.Broadcast)
|
||||||
val header = new MessageHeader(RouteError.Type, crypto.localAddress, destination,
|
val header = new messages.header.MessageHeader(RouteError.Type, crypto.localAddress, destination,
|
||||||
seqNumGenerator.next(), 0)
|
seqNumGenerator.next(), 0)
|
||||||
val seqNum = localRoutesInfo.getRoute(address).map(_.seqNum).getOrElse(-1)
|
val seqNum = localRoutesInfo.getRoute(address).map(_.seqNum).getOrElse(-1)
|
||||||
val body = new RouteError(address, seqNum)
|
val body = new RouteError(address, seqNum)
|
||||||
|
|
||||||
val signed = crypto.sign(new Message(header, body))
|
val signed = crypto.sign(new messages.Message(header, body))
|
||||||
router.forwardMessage(signed)
|
router.forwardMessage(signed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
/**
|
/**
|
||||||
* Decrypts and verifies incoming messages, forwards valid ones to [[onNewMessage()]].
|
* Decrypts and verifies incoming messages, forwards valid ones to [[onNewMessage()]].
|
||||||
*/
|
*/
|
||||||
def onMessageReceived(msg: Message, previousHop: Address): Unit = {
|
def onMessageReceived(msg: messages.Message, previousHop: routing.Address): Unit = {
|
||||||
if (router.isMessageSeen(msg)) {
|
if (router.isMessageSeen(msg)) {
|
||||||
logger.trace("Ignoring message from " + msg.header.origin + " that we already received")
|
logger.trace("Ignoring message from " + msg.header.origin + " that we already received")
|
||||||
return
|
return
|
||||||
|
@ -164,10 +165,10 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
else {
|
else {
|
||||||
val body = rreq.copy(originMetric = rreq.originMetric + 1)
|
val body = rreq.copy(originMetric = rreq.originMetric + 1)
|
||||||
|
|
||||||
val forwardMsg = crypto.sign(new Message(msg.header, body))
|
val forwardMsg = crypto.sign(new messages.Message(msg.header, body))
|
||||||
localRoutesInfo.getRoute(rreq.requested) match {
|
localRoutesInfo.getRoute(rreq.requested) match {
|
||||||
case Some(route) => router.forwardMessage(forwardMsg, Option(route.nextHop))
|
case Some(route) => router.forwardMessage(forwardMsg, Option(route.nextHop))
|
||||||
case None => router.forwardMessage(forwardMsg, Option(Address.Broadcast))
|
case None => router.forwardMessage(forwardMsg, Option(routing.Address.Broadcast))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -185,7 +186,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
return
|
return
|
||||||
|
|
||||||
val existingRoute = localRoutesInfo.getRoute(msg.header.target)
|
val existingRoute = localRoutesInfo.getRoute(msg.header.target)
|
||||||
val states = Set(LocalRoutesInfo.RouteStates.Active, LocalRoutesInfo.RouteStates.Idle)
|
val states = Set(routing.LocalRoutesInfo.RouteStates.Active, routing.LocalRoutesInfo.RouteStates.Idle)
|
||||||
if (existingRoute.isEmpty || !states.contains(existingRoute.get.state)) {
|
if (existingRoute.isEmpty || !states.contains(existingRoute.get.state)) {
|
||||||
routeError(msg.header.target, Option(msg.header.origin))
|
routeError(msg.header.target, Option(msg.header.origin))
|
||||||
return
|
return
|
||||||
|
@ -193,7 +194,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
|
|
||||||
val body = rrep.copy(originMetric = rrep.originMetric + 1)
|
val body = rrep.copy(originMetric = rrep.originMetric + 1)
|
||||||
|
|
||||||
val forwardMsg = crypto.sign(new Message(msg.header, body))
|
val forwardMsg = crypto.sign(new messages.Message(msg.header, body))
|
||||||
router.forwardMessage(forwardMsg)
|
router.forwardMessage(forwardMsg)
|
||||||
return
|
return
|
||||||
case rerr: RouteError =>
|
case rerr: RouteError =>
|
||||||
|
@ -239,13 +240,13 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
|
|
||||||
if (plainMsg.body.contentType == Text.Type) {
|
if (plainMsg.body.contentType == Text.Type) {
|
||||||
logger.trace(s"Sending confirmation for $plainMsg")
|
logger.trace(s"Sending confirmation for $plainMsg")
|
||||||
sendTo(plainMsg.header.origin, new MessageReceived(plainMsg.header.messageId.get))
|
sendTo(plainMsg.header.origin, new messages.body.MessageReceived(plainMsg.header.messageId.get))
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewMessage(plainMsg)
|
onNewMessage(plainMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def forwardMessageToRelays(message: Message): Unit = {
|
private def forwardMessageToRelays(message: messages.Message): Unit = {
|
||||||
var tokens = message.header.tokens
|
var tokens = message.header.tokens
|
||||||
val relays = database.pickLongestConnectionDevice(connections())
|
val relays = database.pickLongestConnectionDevice(connections())
|
||||||
var index = 0
|
var index = 0
|
||||||
|
@ -268,7 +269,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
.foreach(router.forwardMessage(_))
|
.foreach(router.forwardMessage(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def noRouteFound(message: Message): Unit = {
|
private def noRouteFound(message: messages.Message): Unit = {
|
||||||
messageBuffer.addMessage(message)
|
messageBuffer.addMessage(message)
|
||||||
requestRoute(message.header.target)
|
requestRoute(message.header.target)
|
||||||
}
|
}
|
||||||
|
@ -276,15 +277,15 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
/**
|
/**
|
||||||
* Handles all (locally and remotely sent) new messages.
|
* Handles all (locally and remotely sent) new messages.
|
||||||
*/
|
*/
|
||||||
private def onNewMessage(msg: Message): Unit = msg.body match {
|
private def onNewMessage(msg: messages.Message): Unit = msg.body match {
|
||||||
case ui: UserInfo =>
|
case ui: UserInfo =>
|
||||||
val contact = new User(msg.header.origin, ui.name, ui.status)
|
val contact = new util.User(msg.header.origin, ui.name, ui.status)
|
||||||
knownUsers += contact
|
knownUsers += contact
|
||||||
if (database.getContact(msg.header.origin).nonEmpty)
|
if (database.getContact(msg.header.origin).nonEmpty)
|
||||||
database.updateContact(contact)
|
database.updateContact(contact)
|
||||||
|
|
||||||
callbacks.onConnectionsChanged()
|
callbacks.onConnectionsChanged()
|
||||||
case mr: MessageReceived =>
|
case mr: messages.body.MessageReceived =>
|
||||||
database.setMessageConfirmed(mr.messageId)
|
database.setMessageConfirmed(mr.messageId)
|
||||||
case _ =>
|
case _ =>
|
||||||
val origin = msg.header.origin
|
val origin = msg.header.origin
|
||||||
|
@ -301,10 +302,10 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
* This adds the other node's public key if we don't have it. If we do, it validates the signature
|
* This adds the other node's public key if we don't have it. If we do, it validates the signature
|
||||||
* with the stored key.
|
* with the stored key.
|
||||||
*
|
*
|
||||||
* @param msg The message containing [[ConnectionInfo]] to open the connection.
|
* @param msg The message containing [[messages.body.ConnectionInfo]] to open the connection.
|
||||||
* @return True if the connection is valid
|
* @return True if the connection is valid
|
||||||
*/
|
*/
|
||||||
def onConnectionOpened(msg: Message): Boolean = {
|
def onConnectionOpened(msg: messages.Message): Boolean = {
|
||||||
val maxConnections = settings.get(SettingsInterface.KeyMaxConnections,
|
val maxConnections = settings.get(SettingsInterface.KeyMaxConnections,
|
||||||
SettingsInterface.DefaultMaxConnections.toString).toInt
|
SettingsInterface.DefaultMaxConnections.toString).toInt
|
||||||
if (connections().size == maxConnections) {
|
if (connections().size == maxConnections) {
|
||||||
|
@ -312,9 +313,9 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val info = msg.body.asInstanceOf[ConnectionInfo]
|
val info = msg.body.asInstanceOf[messages.body.ConnectionInfo]
|
||||||
val sender = crypto.calculateAddress(info.key)
|
val sender = crypto.calculateAddress(info.key)
|
||||||
if (sender == Address.Broadcast || sender == Address.Null) {
|
if (sender == routing.Address.Broadcast || sender == routing.Address.Null) {
|
||||||
logger.info("Ignoring ConnectionInfo message with invalid sender " + sender)
|
logger.info("Ignoring ConnectionInfo message with invalid sender " + sender)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -353,24 +354,24 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
|
||||||
* @param address The address of the connected device.
|
* @param address The address of the connected device.
|
||||||
* @param duration The time that we were connected to the device.
|
* @param duration The time that we were connected to the device.
|
||||||
*/
|
*/
|
||||||
def onConnectionClosed(address: Address, duration: Duration): Unit = {
|
def onConnectionClosed(address: routing.Address, duration: Duration): Unit = {
|
||||||
localRoutesInfo.connectionClosed(address)
|
localRoutesInfo.connectionClosed(address)
|
||||||
.foreach(routeError(_, None))
|
.foreach(routeError(_, None))
|
||||||
callbacks.onConnectionsChanged()
|
callbacks.onConnectionsChanged()
|
||||||
database.insertOrUpdateKnownDevice(address, duration)
|
database.insertOrUpdateKnownDevice(address, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
def connections(): Set[Address] = transmissionInterfaces.flatMap(_.getConnections)
|
def connections(): Set[routing.Address] = transmissionInterfaces.flatMap(_.getConnections)
|
||||||
|
|
||||||
private def allKnownUsers() = database.getContacts ++ knownUsers
|
private def allKnownUsers() = database.getContacts ++ knownUsers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [[User]] object containing the user's name (if we know it).
|
* Returns [[util.User]] object containing the user's name (if we know it).
|
||||||
*/
|
*/
|
||||||
def getUser(address: Address) =
|
def getUser(address: routing.Address) =
|
||||||
allKnownUsers()
|
allKnownUsers()
|
||||||
.find(_.address == address)
|
.find(_.address == address)
|
||||||
.getOrElse(new User(address, address.toString(), ""))
|
.getOrElse(new util.User(address, address.toString(), ""))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should be called when the local device's internet connection has changed in any way.
|
* This method should be called when the local device's internet connection has changed in any way.
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
package com.nutomic.ensichat.core
|
|
||||||
|
|
||||||
final case class User(address: Address, name: String, status: String)
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.nutomic.ensichat.core.interfaces
|
package com.nutomic.ensichat.core.interfaces
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Message
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
|
||||||
trait CallbackInterface {
|
trait CallbackInterface {
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nutomic.ensichat.core.interfaces
|
package com.nutomic.ensichat.core.interfaces
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.{Address, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfers data to another node over a certain medium (eg Internet or Bluetooth).
|
* Transfers data to another node over a certain medium (eg Internet or Bluetooth).
|
||||||
|
|
|
@ -3,10 +3,12 @@ package com.nutomic.ensichat.core.internet
|
||||||
import java.io.{IOException, InputStream, OutputStream}
|
import java.io.{IOException, InputStream, OutputStream}
|
||||||
import java.net.{InetAddress, Socket}
|
import java.net.{InetAddress, Socket}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Message.ReadMessageException
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.body.ConnectionInfo
|
import com.nutomic.ensichat.core.messages.Message.ReadMessageException
|
||||||
import com.nutomic.ensichat.core.header.MessageHeader
|
import com.nutomic.ensichat.core.messages.body.ConnectionInfo
|
||||||
import com.nutomic.ensichat.core.{Address, Crypto, Message}
|
import com.nutomic.ensichat.core.messages.header.MessageHeader
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.util.Crypto
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@ package com.nutomic.ensichat.core.internet
|
||||||
|
|
||||||
import java.net.{InetAddress, Socket}
|
import java.net.{InetAddress, Socket}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.ConnectionInfo
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.nutomic.ensichat.core.interfaces.{SettingsInterface, TransmissionInterface}
|
import com.nutomic.ensichat.core.interfaces.{SettingsInterface, TransmissionInterface}
|
||||||
import com.nutomic.ensichat.core.util.FutureHelper
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.{Address, ConnectionHandler, Crypto, Message}
|
import com.nutomic.ensichat.core.messages.body.ConnectionInfo
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.util.{Crypto, FutureHelper}
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.joda.time.{DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ package com.nutomic.ensichat.core.internet
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.{Crypto, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.util.Crypto
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
|
|
||||||
class InternetServerThread(crypto: Crypto, port: Int,
|
class InternetServerThread(crypto: Crypto, port: Int,
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.messages
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.spec.InvalidKeySpecException
|
import java.security.spec.InvalidKeySpecException
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body._
|
import com.nutomic.ensichat.core.messages
|
||||||
import com.nutomic.ensichat.core.header.{AbstractHeader, ContentHeader, MessageHeader}
|
import com.nutomic.ensichat.core.messages.body._
|
||||||
|
import com.nutomic.ensichat.core.messages.header.{AbstractHeader, ContentHeader}
|
||||||
|
|
||||||
object Message {
|
object Message {
|
||||||
|
|
||||||
|
@ -33,9 +34,9 @@ object Message {
|
||||||
@throws(classOf[ReadMessageException])
|
@throws(classOf[ReadMessageException])
|
||||||
def read(stream: InputStream): Message = {
|
def read(stream: InputStream): Message = {
|
||||||
try {
|
try {
|
||||||
val headerBytes = new Array[Byte](MessageHeader.Length)
|
val headerBytes = new Array[Byte](messages.header.MessageHeader.Length)
|
||||||
stream.read(headerBytes, 0, MessageHeader.Length)
|
stream.read(headerBytes, 0, messages.header.MessageHeader.Length)
|
||||||
var (header: AbstractHeader, length) = MessageHeader.read(headerBytes)
|
var (header: AbstractHeader, length) = messages.header.MessageHeader.read(headerBytes)
|
||||||
|
|
||||||
var contentBytes = readStream(stream, length - header.length)
|
var contentBytes = readStream(stream, length - header.length)
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ object Message {
|
||||||
|
|
||||||
val body =
|
val body =
|
||||||
header.protocolType match {
|
header.protocolType match {
|
||||||
case ConnectionInfo.Type => ConnectionInfo.read(remaining)
|
case messages.body.ConnectionInfo.Type => messages.body.ConnectionInfo.read(remaining)
|
||||||
case RouteRequest.Type => RouteRequest.read(remaining)
|
case RouteRequest.Type => RouteRequest.read(remaining)
|
||||||
case RouteReply.Type => RouteReply.read(remaining)
|
case RouteReply.Type => RouteReply.read(remaining)
|
||||||
case RouteError.Type => RouteError.read(remaining)
|
case RouteError.Type => RouteError.read(remaining)
|
|
@ -1,11 +1,10 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.security.spec.X509EncodedKeySpec
|
import java.security.spec.X509EncodedKeySpec
|
||||||
import java.security.{KeyFactory, PublicKey}
|
import java.security.{KeyFactory, PublicKey}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Crypto
|
import com.nutomic.ensichat.core.util.{BufferUtils, Crypto}
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
|
||||||
|
|
||||||
object ConnectionInfo {
|
object ConnectionInfo {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util
|
import java.util
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the data in an encrypted message body.
|
* Represents the data in an encrypted message body.
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the actual message content.
|
* Holds the actual message content.
|
|
@ -1,12 +1,9 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Message
|
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
import scala.Predef.String
|
|
||||||
|
|
||||||
object MessageReceived {
|
object MessageReceived {
|
||||||
|
|
||||||
val Type = 8
|
val Type = 8
|
|
@ -1,8 +1,8 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
private[core] object RouteError {
|
private[core] object RouteError {
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
private[core] object RouteRequest {
|
private[core] object RouteRequest {
|
|
@ -1,8 +1,8 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Message
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
object Text {
|
object Text {
|
|
@ -1,8 +1,8 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Message
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
object UserInfo {
|
object UserInfo {
|
|
@ -1,8 +1,8 @@
|
||||||
package com.nutomic.ensichat.core.header
|
package com.nutomic.ensichat.core.messages.header
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.nutomic.ensichat.core.header
|
package com.nutomic.ensichat.core.messages.header
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.messages.header
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ object ContentHeader {
|
||||||
/**
|
/**
|
||||||
* Constructs [[MessageHeader]] from byte array.
|
* Constructs [[MessageHeader]] from byte array.
|
||||||
*/
|
*/
|
||||||
def read(mh: AbstractHeader, bytes: Array[Byte]): (ContentHeader, Array[Byte]) = {
|
def read(mh: header.AbstractHeader, bytes: Array[Byte]): (ContentHeader, Array[Byte]) = {
|
||||||
val b = ByteBuffer.wrap(bytes)
|
val b = ByteBuffer.wrap(bytes)
|
||||||
|
|
||||||
val contentType = BufferUtils.getUnsignedShort(b)
|
val contentType = BufferUtils.getUnsignedShort(b)
|
||||||
|
@ -37,7 +38,7 @@ object ContentHeader {
|
||||||
/**
|
/**
|
||||||
* Header for user-sent messages.
|
* Header for user-sent messages.
|
||||||
*
|
*
|
||||||
* This is [[AbstractHeader]] with messageId and time fields set.
|
* This is [[header.AbstractHeader]] with messageId and time fields set.
|
||||||
*/
|
*/
|
||||||
final case class ContentHeader(override val origin: Address,
|
final case class ContentHeader(override val origin: Address,
|
||||||
override val target: Address,
|
override val target: Address,
|
||||||
|
@ -47,7 +48,7 @@ final case class ContentHeader(override val origin: Address,
|
||||||
override val time: Some[DateTime],
|
override val time: Some[DateTime],
|
||||||
override val tokens: Int,
|
override val tokens: Int,
|
||||||
override val hopCount: Int = 0)
|
override val hopCount: Int = 0)
|
||||||
extends AbstractHeader {
|
extends header.AbstractHeader {
|
||||||
|
|
||||||
override val protocolType = ContentHeader.ContentMessageType
|
override val protocolType = ContentHeader.ContentMessageType
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ final case class ContentHeader(override val origin: Address,
|
||||||
b.array()
|
b.array()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def length = AbstractHeader.Length + ContentHeader.Length
|
override def length = header.AbstractHeader.Length + ContentHeader.Length
|
||||||
|
|
||||||
override def equals(a: Any): Boolean = a match {
|
override def equals(a: Any): Boolean = a match {
|
||||||
case o: ContentHeader =>
|
case o: ContentHeader =>
|
|
@ -1,14 +1,15 @@
|
||||||
package com.nutomic.ensichat.core.header
|
package com.nutomic.ensichat.core.messages.header
|
||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.messages.Message.ReadMessageException
|
||||||
import com.nutomic.ensichat.core.Message.ReadMessageException
|
import com.nutomic.ensichat.core.messages.{Message, header}
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.BufferUtils
|
import com.nutomic.ensichat.core.util.BufferUtils
|
||||||
|
|
||||||
object MessageHeader {
|
object MessageHeader {
|
||||||
|
|
||||||
val Length = AbstractHeader.Length
|
val Length = header.AbstractHeader.Length
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs header from byte array.
|
* Constructs header from byte array.
|
||||||
|
@ -20,11 +21,11 @@ object MessageHeader {
|
||||||
val b = ByteBuffer.wrap(bytes, 0, MessageHeader.Length)
|
val b = ByteBuffer.wrap(bytes, 0, MessageHeader.Length)
|
||||||
|
|
||||||
val version = BufferUtils.getUnsignedByte(b)
|
val version = BufferUtils.getUnsignedByte(b)
|
||||||
if (version != AbstractHeader.Version)
|
if (version != header.AbstractHeader.Version)
|
||||||
throw new ReadMessageException("Failed to parse message with unsupported version " + version)
|
throw new ReadMessageException("Failed to parse message with unsupported version " + version)
|
||||||
val protocolType = BufferUtils.getUnsignedByte(b)
|
val protocolType = BufferUtils.getUnsignedByte(b)
|
||||||
val tokens = BufferUtils.getUnsignedByte(b)
|
val tokens = BufferUtils.getUnsignedByte(b)
|
||||||
if (tokens > AbstractHeader.MaxForwardingTokens)
|
if (tokens > header.AbstractHeader.MaxForwardingTokens)
|
||||||
throw new ReadMessageException(s"Received message with too many forwarding tokens ($tokens tokens)")
|
throw new ReadMessageException(s"Received message with too many forwarding tokens ($tokens tokens)")
|
||||||
val hopCount = BufferUtils.getUnsignedByte(b)
|
val hopCount = BufferUtils.getUnsignedByte(b)
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ object MessageHeader {
|
||||||
/**
|
/**
|
||||||
* First part of any message, used for routing.
|
* First part of any message, used for routing.
|
||||||
*
|
*
|
||||||
* This is the same as [[AbstractHeader]].
|
* This is the same as [[header.AbstractHeader]].
|
||||||
*/
|
*/
|
||||||
final case class MessageHeader(override val protocolType: Int,
|
final case class MessageHeader(override val protocolType: Int,
|
||||||
override val origin: Address,
|
override val origin: Address,
|
||||||
|
@ -52,7 +53,7 @@ final case class MessageHeader(override val protocolType: Int,
|
||||||
override val seqNum: Int,
|
override val seqNum: Int,
|
||||||
override val tokens: Int,
|
override val tokens: Int,
|
||||||
override val hopCount: Int = 0)
|
override val hopCount: Int = 0)
|
||||||
extends AbstractHeader {
|
extends header.AbstractHeader {
|
||||||
|
|
||||||
def length: Int = MessageHeader.Length
|
def length: Int = MessageHeader.Length
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
object Address {
|
object Address {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Address
|
import com.nutomic.ensichat.core.routing.LocalRoutesInfo._
|
||||||
import com.nutomic.ensichat.core.util.LocalRoutesInfo._
|
|
||||||
import com.typesafe.scalalogging.Logger
|
|
||||||
import org.joda.time.{DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
|
||||||
private[core] object LocalRoutesInfo {
|
private[core] object LocalRoutesInfo {
|
|
@ -1,10 +1,10 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import java.util.{TimerTask, Timer}
|
import java.util.{Timer, TimerTask}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.{Address, Message}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.joda.time.{Seconds, DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains messages that couldn't be forwarded because we don't know a route.
|
* Contains messages that couldn't be forwarded because we don't know a route.
|
|
@ -1,7 +1,7 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.{RouteReply, RouteRequest}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.{Address, Message, Router}
|
import com.nutomic.ensichat.core.messages.body.{RouteReply, RouteRequest}
|
||||||
import org.joda.time.{DateTime, Duration}
|
import org.joda.time.{DateTime, Duration}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,9 +1,9 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import java.util.Comparator
|
import java.util.Comparator
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.header.{ContentHeader, MessageHeader}
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
import com.nutomic.ensichat.core.util.LocalRoutesInfo
|
import com.nutomic.ensichat.core.messages.{Message, header}
|
||||||
|
|
||||||
object Router extends Comparator[Int] {
|
object Router extends Comparator[Int] {
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ private[core] class Router(routesInfo: LocalRoutesInfo, send: (Address, Message)
|
||||||
private def incHopCount(msg: Message): Message = {
|
private def incHopCount(msg: Message): Message = {
|
||||||
val updatedHeader = msg.header match {
|
val updatedHeader = msg.header match {
|
||||||
case ch: ContentHeader => ch.copy(hopCount = ch.hopCount + 1)
|
case ch: ContentHeader => ch.copy(hopCount = ch.hopCount + 1)
|
||||||
case mh: MessageHeader => mh.copy(hopCount = mh.hopCount + 1)
|
case mh: header.MessageHeader => mh.copy(hopCount = mh.hopCount + 1)
|
||||||
}
|
}
|
||||||
new Message(updatedHeader, msg.crypto, msg.body)
|
new Message(updatedHeader, msg.crypto, msg.body)
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
import java.io._
|
import java.io._
|
||||||
import java.security._
|
import java.security._
|
||||||
|
@ -6,10 +6,12 @@ import java.security.spec.{PKCS8EncodedKeySpec, X509EncodedKeySpec}
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import javax.crypto.{Cipher, CipherOutputStream, KeyGenerator, SecretKey}
|
import javax.crypto.{Cipher, CipherOutputStream, KeyGenerator, SecretKey}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.Crypto._
|
import com.nutomic.ensichat.core._
|
||||||
import com.nutomic.ensichat.core.body._
|
|
||||||
import com.nutomic.ensichat.core.header.{MessageHeader, ContentHeader}
|
|
||||||
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
||||||
|
import com.nutomic.ensichat.core.messages.body.{CryptoData, EncryptedBody, Text, UserInfo}
|
||||||
|
import com.nutomic.ensichat.core.messages.header.{ContentHeader, MessageHeader}
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
import com.nutomic.ensichat.core.util.Crypto._
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
|
|
||||||
object Crypto {
|
object Crypto {
|
||||||
|
@ -89,7 +91,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
if (localKeysExist)
|
if (localKeysExist)
|
||||||
return
|
return
|
||||||
|
|
||||||
var address: Address = null
|
var address: routing.Address = null
|
||||||
var keyPair: KeyPair = null
|
var keyPair: KeyPair = null
|
||||||
do {
|
do {
|
||||||
val keyGen = KeyPairGenerator.getInstance(PublicKeyAlgorithm)
|
val keyGen = KeyPairGenerator.getInstance(PublicKeyAlgorithm)
|
||||||
|
@ -99,7 +101,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
address = calculateAddress(keyPair.getPublic)
|
address = calculateAddress(keyPair.getPublic)
|
||||||
|
|
||||||
// Never generate an invalid address.
|
// Never generate an invalid address.
|
||||||
} while(address == Address.Broadcast || address == Address.Null)
|
} while(address == routing.Address.Broadcast || address == routing.Address.Null)
|
||||||
|
|
||||||
settings.put(LocalAddressKey, address.toString)
|
settings.put(LocalAddressKey, address.toString)
|
||||||
|
|
||||||
|
@ -111,7 +113,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
/**
|
/**
|
||||||
* Returns true if we have a public key stored for the given device.
|
* Returns true if we have a public key stored for the given device.
|
||||||
*/
|
*/
|
||||||
private[core] def havePublicKey(address: Address) = new File(keyFolder, address.toString).exists()
|
private[core] def havePublicKey(address: routing.Address) = new File(keyFolder, address.toString).exists()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the public key for the given device.
|
* Returns the public key for the given device.
|
||||||
|
@ -119,7 +121,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
* @throws RuntimeException If the key does not exist.
|
* @throws RuntimeException If the key does not exist.
|
||||||
*/
|
*/
|
||||||
@throws[RuntimeException]
|
@throws[RuntimeException]
|
||||||
def getPublicKey(address: Address): PublicKey = {
|
def getPublicKey(address: routing.Address): PublicKey = {
|
||||||
loadKey(address.toString, classOf[PublicKey])
|
loadKey(address.toString, classOf[PublicKey])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +131,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
* @throws RuntimeException If a key already exists for this address.
|
* @throws RuntimeException If a key already exists for this address.
|
||||||
*/
|
*/
|
||||||
@throws[RuntimeException]
|
@throws[RuntimeException]
|
||||||
def addPublicKey(address: Address, key: PublicKey): Unit = {
|
def addPublicKey(address: routing.Address, key: PublicKey): Unit = {
|
||||||
if (havePublicKey(address))
|
if (havePublicKey(address))
|
||||||
throw new RuntimeException("Already have key for " + address + ", not overwriting")
|
throw new RuntimeException("Already have key for " + address + ", not overwriting")
|
||||||
|
|
||||||
|
@ -139,24 +141,24 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
/**
|
/**
|
||||||
* Prepares message header and body so that they can be signed/verified.
|
* Prepares message header and body so that they can be signed/verified.
|
||||||
*/
|
*/
|
||||||
private def messageForSigning(msg: Message): Array[Byte] = {
|
private def messageForSigning(msg: messages.Message): Array[Byte] = {
|
||||||
val header = msg.header match {
|
val header = msg.header match {
|
||||||
case ch: ContentHeader => ch.copy(tokens = 0, hopCount = 0)
|
case ch: ContentHeader => ch.copy(tokens = 0, hopCount = 0)
|
||||||
case mh: MessageHeader => mh.copy(tokens = 0, hopCount = 0)
|
case mh: MessageHeader => mh.copy(tokens = 0, hopCount = 0)
|
||||||
}
|
}
|
||||||
header.write(msg.body.length) ++ msg.body.write
|
header.write(msg.body.length) ++ msg.body.write
|
||||||
}
|
}
|
||||||
|
|
||||||
def sign(msg: Message): Message = {
|
def sign(msg: messages.Message): messages.Message = {
|
||||||
val sig = Signature.getInstance(SigningAlgorithm)
|
val sig = Signature.getInstance(SigningAlgorithm)
|
||||||
val key = loadKey(PrivateKeyAlias, classOf[PrivateKey])
|
val key = loadKey(PrivateKeyAlias, classOf[PrivateKey])
|
||||||
sig.initSign(key)
|
sig.initSign(key)
|
||||||
sig.update(messageForSigning(msg))
|
sig.update(messageForSigning(msg))
|
||||||
new Message(msg.header, new CryptoData(Option(sig.sign), msg.crypto.key), msg.body)
|
new messages.Message(msg.header, new CryptoData(Option(sig.sign), msg.crypto.key), msg.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@throws[InvalidKeyException]
|
@throws[InvalidKeyException]
|
||||||
private[core] def verify(msg: Message, key: Option[PublicKey] = None): Boolean = {
|
private[core] def verify(msg: messages.Message, key: Option[PublicKey] = None): Boolean = {
|
||||||
val sig = Signature.getInstance(SigningAlgorithm)
|
val sig = Signature.getInstance(SigningAlgorithm)
|
||||||
lazy val defaultKey = loadKey(msg.header.origin.toString, classOf[PublicKey])
|
lazy val defaultKey = loadKey(msg.header.origin.toString, classOf[PublicKey])
|
||||||
sig.initVerify(key.getOrElse(defaultKey))
|
sig.initVerify(key.getOrElse(defaultKey))
|
||||||
|
@ -239,11 +241,11 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private[core] def encryptAndSign(msg: Message, key: Option[PublicKey] = None): Message = {
|
private[core] def encryptAndSign(msg: messages.Message, key: Option[PublicKey] = None): messages.Message = {
|
||||||
sign(encrypt(msg, key))
|
sign(encrypt(msg, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def encrypt(msg: Message, key: Option[PublicKey] = None): Message = {
|
private def encrypt(msg: messages.Message, key: Option[PublicKey] = None): messages.Message = {
|
||||||
// Symmetric encryption of data
|
// Symmetric encryption of data
|
||||||
val secretKey = makeSecretKey()
|
val secretKey = makeSecretKey()
|
||||||
val symmetricCipher = Cipher.getInstance(SymmetricKeyAlgorithm)
|
val symmetricCipher = Cipher.getInstance(SymmetricKeyAlgorithm)
|
||||||
|
@ -255,12 +257,12 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
lazy val defaultKey = loadKey(msg.header.target.toString, classOf[PublicKey])
|
lazy val defaultKey = loadKey(msg.header.target.toString, classOf[PublicKey])
|
||||||
asymmetricCipher.init(Cipher.WRAP_MODE, key.getOrElse(defaultKey))
|
asymmetricCipher.init(Cipher.WRAP_MODE, key.getOrElse(defaultKey))
|
||||||
|
|
||||||
new Message(msg.header,
|
new messages.Message(msg.header,
|
||||||
new CryptoData(None, Option(asymmetricCipher.wrap(secretKey))), encrypted)
|
new CryptoData(None, Option(asymmetricCipher.wrap(secretKey))), encrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
@throws[InvalidKeyException]
|
@throws[InvalidKeyException]
|
||||||
def decrypt(msg: Message): Message = {
|
def decrypt(msg: messages.Message): messages.Message = {
|
||||||
// Asymmetric decryption of secret key
|
// Asymmetric decryption of secret key
|
||||||
val asymmetricCipher = Cipher.getInstance(CipherAlgorithm)
|
val asymmetricCipher = Cipher.getInstance(CipherAlgorithm)
|
||||||
asymmetricCipher.init(Cipher.UNWRAP_MODE, loadKey(PrivateKeyAlias, classOf[PrivateKey]))
|
asymmetricCipher.init(Cipher.UNWRAP_MODE, loadKey(PrivateKeyAlias, classOf[PrivateKey]))
|
||||||
|
@ -273,9 +275,9 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
val body = msg.header.asInstanceOf[ContentHeader].contentType match {
|
val body = msg.header.asInstanceOf[ContentHeader].contentType match {
|
||||||
case Text.Type => Text.read(decrypted)
|
case Text.Type => Text.read(decrypted)
|
||||||
case UserInfo.Type => UserInfo.read(decrypted)
|
case UserInfo.Type => UserInfo.read(decrypted)
|
||||||
case MessageReceived.Type => MessageReceived.read(decrypted)
|
case messages.body.MessageReceived.Type => messages.body.MessageReceived.read(decrypted)
|
||||||
}
|
}
|
||||||
new Message(msg.header, msg.crypto, body)
|
new messages.Message(msg.header, msg.crypto, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -313,10 +315,10 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
|
||||||
/**
|
/**
|
||||||
* Generates the address by hashing the given public key with [[KeyHashAlgorithm]].
|
* Generates the address by hashing the given public key with [[KeyHashAlgorithm]].
|
||||||
*/
|
*/
|
||||||
def calculateAddress(key: PublicKey): Address = {
|
def calculateAddress(key: PublicKey): routing.Address = {
|
||||||
val md = MessageDigest.getInstance(KeyHashAlgorithm)
|
val md = MessageDigest.getInstance(KeyHashAlgorithm)
|
||||||
val hash = md.digest(key.getEncoded)
|
val hash = md.digest(key.getEncoded)
|
||||||
new Address(hash)
|
new routing.Address(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -3,10 +3,11 @@ package com.nutomic.ensichat.core.util
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.sql.DriverManager
|
import java.sql.DriverManager
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.Text
|
|
||||||
import com.nutomic.ensichat.core.header.ContentHeader
|
|
||||||
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
||||||
import com.nutomic.ensichat.core.{Crypto, Address, Message, User}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import org.joda.time
|
import org.joda.time
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.header.ContentHeader
|
|
||||||
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
||||||
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates sequence numbers according to protocol, which are stored persistently.
|
* Generates sequence numbers according to protocol, which are stored persistently.
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
|
|
||||||
|
final case class User(address: Address, name: String, status: String)
|
|
@ -1,11 +0,0 @@
|
||||||
package com.nutomic.ensichat.core
|
|
||||||
|
|
||||||
object UserTest {
|
|
||||||
|
|
||||||
val u1 = new User(AddressTest.a1, "one", "s1")
|
|
||||||
|
|
||||||
val u2 = new User(AddressTest.a2, "two", "s2")
|
|
||||||
|
|
||||||
val u3 = new User(AddressTest.a3, "three", "s3")
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package com.nutomic.ensichat.core.header
|
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.header.MessageHeaderTest._
|
|
||||||
import com.nutomic.ensichat.core.{Address, AddressTest}
|
|
||||||
import junit.framework.TestCase
|
|
||||||
import org.junit.Assert._
|
|
||||||
|
|
||||||
object MessageHeaderTest {
|
|
||||||
|
|
||||||
val h1 = new MessageHeader(ContentHeader.ContentMessageType, AddressTest.a1, AddressTest.a2, 3,
|
|
||||||
0)
|
|
||||||
|
|
||||||
val h2 = new MessageHeader(ContentHeader.ContentMessageType, Address.Null, Address.Broadcast,
|
|
||||||
ContentHeader.SeqNumRange.last, 6, 3)
|
|
||||||
|
|
||||||
val h3 = new MessageHeader(ContentHeader.ContentMessageType, Address.Broadcast, Address.Null, 0, 3)
|
|
||||||
|
|
||||||
val headers = Set(h1, h2, h3)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageHeaderTest extends TestCase {
|
|
||||||
|
|
||||||
def testSerialize(): Unit = {
|
|
||||||
headers.foreach{h =>
|
|
||||||
val bytes = h.write(0)
|
|
||||||
val (header, length) = MessageHeader.read(bytes)
|
|
||||||
assertEquals(h, header)
|
|
||||||
assertEquals(MessageHeader.Length, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,23 +1,27 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.messages
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.MessageTest._
|
import com.nutomic.ensichat.core
|
||||||
import com.nutomic.ensichat.core.body.{ConnectionInfo, ConnectionInfoTest, Text}
|
import com.nutomic.ensichat.core.messages
|
||||||
import com.nutomic.ensichat.core.header.ContentHeaderTest._
|
import com.nutomic.ensichat.core.messages.body.{Text, ConnectionInfo, ConnectionInfoTest}
|
||||||
import com.nutomic.ensichat.core.header.MessageHeader
|
import com.nutomic.ensichat.core.messages.header.ContentHeaderTest._
|
||||||
|
import com.nutomic.ensichat.core.messages.header.MessageHeader
|
||||||
|
import com.nutomic.ensichat.core.routing.AddressTest
|
||||||
|
import com.nutomic.ensichat.core.util.CryptoTest
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
import com.nutomic.ensichat.core.messages.MessageTest._
|
||||||
|
|
||||||
import scala.collection.immutable.TreeSet
|
import scala.collection.immutable.TreeSet
|
||||||
|
|
||||||
object MessageTest {
|
object MessageTest {
|
||||||
|
|
||||||
val m1 = new Message(h1, new Text("first"))
|
val m1 = new core.messages.Message(h1, new Text("first"))
|
||||||
|
|
||||||
val m2 = new Message(h2, new Text("second"))
|
val m2 = new core.messages.Message(h2, new Text("second"))
|
||||||
|
|
||||||
val m3 = new Message(h3, new Text("third"))
|
val m3 = new core.messages.Message(h3, new Text("third"))
|
||||||
|
|
||||||
val messages = Set(m1, m2, m3)
|
val messages = Set(m1, m2, m3)
|
||||||
|
|
||||||
|
@ -28,12 +32,12 @@ class MessageTest extends TestCase {
|
||||||
private lazy val crypto = CryptoTest.getCrypto
|
private lazy val crypto = CryptoTest.getCrypto
|
||||||
|
|
||||||
def testOrder(): Unit = {
|
def testOrder(): Unit = {
|
||||||
var messages = new TreeSet[Message]()(Message.Ordering)
|
var messages = new TreeSet[Message]()(core.messages.Message.Ordering)
|
||||||
messages += m1
|
messages += m1
|
||||||
messages += m2
|
messages += m2
|
||||||
assertEquals(m1, messages.firstKey)
|
assertEquals(m1, messages.firstKey)
|
||||||
|
|
||||||
messages = new TreeSet[Message]()(Message.Ordering)
|
messages = new TreeSet[Message]()(core.messages.Message.Ordering)
|
||||||
messages += m2
|
messages += m2
|
||||||
messages += m3
|
messages += m3
|
||||||
assertEquals(m2, messages.firstKey)
|
assertEquals(m2, messages.firstKey)
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.CryptoTest
|
import com.nutomic.ensichat.core.messages.body
|
||||||
|
import com.nutomic.ensichat.core.util.CryptoTest
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ object ConnectionInfoTest {
|
||||||
val crypto = CryptoTest.getCrypto
|
val crypto = CryptoTest.getCrypto
|
||||||
if (!crypto.localKeysExist)
|
if (!crypto.localKeysExist)
|
||||||
crypto.generateLocalKeys()
|
crypto.generateLocalKeys()
|
||||||
new ConnectionInfo(crypto.getLocalPublicKey)
|
new body.ConnectionInfo(crypto.getLocalPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.AddressTest
|
import com.nutomic.ensichat.core.routing.AddressTest
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.AddressTest
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.AddressTest
|
import com.nutomic.ensichat.core.routing.AddressTest
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.nutomic.ensichat.core.body
|
package com.nutomic.ensichat.core.messages.body
|
||||||
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
|
@ -1,28 +1,30 @@
|
||||||
package com.nutomic.ensichat.core.header
|
package com.nutomic.ensichat.core.messages.header
|
||||||
|
|
||||||
import java.util.{Date, GregorianCalendar}
|
import java.util.GregorianCalendar
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.Text
|
import com.nutomic.ensichat.core.messages
|
||||||
import com.nutomic.ensichat.core.{Address, AddressTest}
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
|
import com.nutomic.ensichat.core.messages.header
|
||||||
|
import com.nutomic.ensichat.core.routing.{Address, AddressTest}
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
||||||
object ContentHeaderTest {
|
object ContentHeaderTest {
|
||||||
|
|
||||||
val h1 = new ContentHeader(AddressTest.a1, AddressTest.a2, 1234,
|
val h1 = new header.ContentHeader(AddressTest.a1, AddressTest.a2, 1234,
|
||||||
Text.Type, Some(123), Some(new DateTime(new GregorianCalendar(1970, 1, 1).getTime)), 3)
|
Text.Type, Some(123), Some(new DateTime(new GregorianCalendar(1970, 1, 1).getTime)), 3)
|
||||||
|
|
||||||
val h2 = new ContentHeader(AddressTest.a1, AddressTest.a3,
|
val h2 = new header.ContentHeader(AddressTest.a1, AddressTest.a3,
|
||||||
30000, Text.Type, Some(8765), Some(new DateTime(new GregorianCalendar(2014, 6, 10))), 2)
|
30000, Text.Type, Some(8765), Some(new DateTime(new GregorianCalendar(2014, 6, 10))), 2)
|
||||||
|
|
||||||
val h3 = new ContentHeader(AddressTest.a4, AddressTest.a2,
|
val h3 = new header.ContentHeader(AddressTest.a4, AddressTest.a2,
|
||||||
250, Text.Type, Some(77), Some(new DateTime(new GregorianCalendar(2020, 11, 11).getTime)), 1)
|
250, Text.Type, Some(77), Some(new DateTime(new GregorianCalendar(2020, 11, 11).getTime)), 1)
|
||||||
|
|
||||||
val h4 = new ContentHeader(Address.Null, Address.Broadcast,
|
val h4 = new header.ContentHeader(Address.Null, Address.Broadcast,
|
||||||
ContentHeader.SeqNumRange.last, 0, Some(0xffff), Some(new DateTime(0L)), 6)
|
header.ContentHeader.SeqNumRange.last, 0, Some(0xffff), Some(new DateTime(0L)), 6)
|
||||||
|
|
||||||
val h5 = new ContentHeader(Address.Broadcast, Address.Null,
|
val h5 = new header.ContentHeader(Address.Broadcast, Address.Null,
|
||||||
0, 0xff, Some(0), Some(new DateTime(0xffffffffL)), 0)
|
0, 0xff, Some(0), Some(new DateTime(0xffffffffL)), 0)
|
||||||
|
|
||||||
val headers = Set(h1, h2, h3, h4, h5)
|
val headers = Set(h1, h2, h3, h4, h5)
|
||||||
|
@ -37,7 +39,7 @@ class ContentHeaderTest extends TestCase {
|
||||||
assertEquals(bytes.length, h.length)
|
assertEquals(bytes.length, h.length)
|
||||||
val (mh, length) = MessageHeader.read(bytes)
|
val (mh, length) = MessageHeader.read(bytes)
|
||||||
val chBytes = bytes.drop(mh.length)
|
val chBytes = bytes.drop(mh.length)
|
||||||
val (header, remaining) = ContentHeader.read(mh, chBytes)
|
val (header, remaining) = messages.header.ContentHeader.read(mh, chBytes)
|
||||||
assertEquals(h, header)
|
assertEquals(h, header)
|
||||||
assertEquals(0, remaining.length)
|
assertEquals(0, remaining.length)
|
||||||
}
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.nutomic.ensichat.core.messages.header
|
||||||
|
|
||||||
|
import com.nutomic.ensichat.core.messages
|
||||||
|
import com.nutomic.ensichat.core.messages.header
|
||||||
|
import com.nutomic.ensichat.core.messages.header.MessageHeaderTest._
|
||||||
|
import com.nutomic.ensichat.core.routing.{Address, AddressTest}
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.junit.Assert._
|
||||||
|
|
||||||
|
object MessageHeaderTest {
|
||||||
|
|
||||||
|
val h1 = new header.MessageHeader(header.ContentHeader.ContentMessageType, AddressTest.a1, AddressTest.a2, 3,
|
||||||
|
0)
|
||||||
|
|
||||||
|
val h2 = new header.MessageHeader(header.ContentHeader.ContentMessageType, Address.Null, Address.Broadcast,
|
||||||
|
header.ContentHeader.SeqNumRange.last, 6, 3)
|
||||||
|
|
||||||
|
val h3 = new header.MessageHeader(header.ContentHeader.ContentMessageType, Address.Broadcast, Address.Null, 0, 3)
|
||||||
|
|
||||||
|
val headers = Set(h1, h2, h3)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageHeaderTest extends TestCase {
|
||||||
|
|
||||||
|
def testSerialize(): Unit = {
|
||||||
|
headers.foreach{h =>
|
||||||
|
val bytes = h.write(0)
|
||||||
|
val (header, length) = messages.header.MessageHeader.read(bytes)
|
||||||
|
assertEquals(h, header)
|
||||||
|
assertEquals(messages.header.MessageHeader.Length, length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.AddressTest._
|
import com.nutomic.ensichat.core.routing.AddressTest._
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.AddressTest
|
import com.nutomic.ensichat.core.routing
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.{DateTime, DateTimeUtils, Duration}
|
import org.joda.time.{DateTime, DateTimeUtils, Duration}
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
@ -10,14 +10,14 @@ class LocalRoutesInfoTest extends TestCase {
|
||||||
private def connections() = Set(AddressTest.a1, AddressTest.a2)
|
private def connections() = Set(AddressTest.a1, AddressTest.a2)
|
||||||
|
|
||||||
def testRoute(): Unit = {
|
def testRoute(): Unit = {
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
||||||
val route = routesInfo.getRoute(AddressTest.a3)
|
val route = routesInfo.getRoute(AddressTest.a3)
|
||||||
assertEquals(AddressTest.a1, route.get.nextHop)
|
assertEquals(AddressTest.a1, route.get.nextHop)
|
||||||
}
|
}
|
||||||
|
|
||||||
def testBestMetric(): Unit = {
|
def testBestMetric(): Unit = {
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a2, 2)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a2, 2)
|
||||||
val route = routesInfo.getRoute(AddressTest.a3)
|
val route = routesInfo.getRoute(AddressTest.a3)
|
||||||
|
@ -25,7 +25,7 @@ class LocalRoutesInfoTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
def testConnectionClosed(): Unit = {
|
def testConnectionClosed(): Unit = {
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
||||||
routesInfo.addRoute(AddressTest.a4, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a4, 0, AddressTest.a1, 1)
|
||||||
// Mark the route as active, because only active routes are returned.
|
// Mark the route as active, because only active routes are returned.
|
||||||
|
@ -36,14 +36,14 @@ class LocalRoutesInfoTest extends TestCase {
|
||||||
|
|
||||||
def testTimeout(): Unit = {
|
def testTimeout(): Unit = {
|
||||||
DateTimeUtils.setCurrentMillisFixed(new DateTime().getMillis)
|
DateTimeUtils.setCurrentMillisFixed(new DateTime().getMillis)
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
||||||
DateTimeUtils.setCurrentMillisFixed(DateTime.now.plus(Duration.standardSeconds(400)).getMillis)
|
DateTimeUtils.setCurrentMillisFixed(DateTime.now.plus(Duration.standardSeconds(400)).getMillis)
|
||||||
assertEquals(None, routesInfo.getRoute(AddressTest.a3))
|
assertEquals(None, routesInfo.getRoute(AddressTest.a3))
|
||||||
}
|
}
|
||||||
|
|
||||||
def testNeighbor(): Unit = {
|
def testNeighbor(): Unit = {
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
val r1 = routesInfo.getRoute(AddressTest.a1)
|
val r1 = routesInfo.getRoute(AddressTest.a1)
|
||||||
assertTrue(r1.isDefined)
|
assertTrue(r1.isDefined)
|
||||||
assertEquals(AddressTest.a1, r1.get.destination)
|
assertEquals(AddressTest.a1, r1.get.destination)
|
||||||
|
@ -51,7 +51,7 @@ class LocalRoutesInfoTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
def testGetAllAvailableRoutes(): Unit = {
|
def testGetAllAvailableRoutes(): Unit = {
|
||||||
val routesInfo = new LocalRoutesInfo(connections)
|
val routesInfo = new routing.LocalRoutesInfo(connections)
|
||||||
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
routesInfo.addRoute(AddressTest.a3, 0, AddressTest.a1, 1)
|
||||||
val destinations = routesInfo.getAllAvailableRoutes.map(_.destination).toSet
|
val destinations = routesInfo.getAllAvailableRoutes.map(_.destination).toSet
|
||||||
assertEquals(connections() + AddressTest.a3, destinations)
|
assertEquals(connections() + AddressTest.a3, destinations)
|
|
@ -1,9 +1,10 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.header.ContentHeader
|
import com.nutomic.ensichat.core._
|
||||||
import com.nutomic.ensichat.core.{Message, Address, MessageTest}
|
import com.nutomic.ensichat.core.messages.MessageTest
|
||||||
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
@ -14,14 +15,14 @@ class MessageBufferTest extends TestCase {
|
||||||
* MessageBuffer checks the time of a message, we have to use the current time or items might
|
* MessageBuffer checks the time of a message, we have to use the current time or items might
|
||||||
* time out.
|
* time out.
|
||||||
*/
|
*/
|
||||||
private def adjustMessageTime(m: Message) =
|
private def adjustMessageTime(m: messages.Message) =
|
||||||
new Message(m.header.asInstanceOf[ContentHeader].copy(time=Some(DateTime.now)), m.body)
|
new messages.Message(m.header.asInstanceOf[ContentHeader].copy(time=Some(DateTime.now)), m.body)
|
||||||
|
|
||||||
val m1 = adjustMessageTime(MessageTest.m1)
|
val m1 = adjustMessageTime(MessageTest.m1)
|
||||||
val m2 = adjustMessageTime(MessageTest.m2)
|
val m2 = adjustMessageTime(MessageTest.m2)
|
||||||
|
|
||||||
def testGetMessages(): Unit = {
|
def testGetMessages(): Unit = {
|
||||||
val buffer = new MessageBuffer(Address.Null, () => _)
|
val buffer = new routing.MessageBuffer(routing.Address.Null, () => _)
|
||||||
buffer.addMessage(m1)
|
buffer.addMessage(m1)
|
||||||
buffer.addMessage(m2)
|
buffer.addMessage(m2)
|
||||||
val msgs = buffer.getMessages(m1.header.target)
|
val msgs = buffer.getMessages(m1.header.target)
|
||||||
|
@ -31,7 +32,7 @@ class MessageBufferTest extends TestCase {
|
||||||
|
|
||||||
def testRetryMessage(): Unit = {
|
def testRetryMessage(): Unit = {
|
||||||
val latch = new CountDownLatch(1)
|
val latch = new CountDownLatch(1)
|
||||||
val buffer = new MessageBuffer(Address.Null, {e =>
|
val buffer = new routing.MessageBuffer(routing.Address.Null, { e =>
|
||||||
assertEquals(m1.header.target, e)
|
assertEquals(m1.header.target, e)
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
})
|
})
|
|
@ -1,8 +1,9 @@
|
||||||
package com.nutomic.ensichat.core.util
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.{RouteReply, RouteRequest}
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.header.MessageHeader
|
import com.nutomic.ensichat.core.messages.body.{RouteReply, RouteRequest}
|
||||||
import com.nutomic.ensichat.core.{AddressTest, Message}
|
import com.nutomic.ensichat.core.messages.header.MessageHeader
|
||||||
|
import com.nutomic.ensichat.core.routing
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.{DateTime, DateTimeUtils, Duration}
|
import org.joda.time.{DateTime, DateTimeUtils, Duration}
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
@ -15,7 +16,7 @@ class RouteMessageInfoTest extends TestCase {
|
||||||
def testSameMessage(): Unit = {
|
def testSameMessage(): Unit = {
|
||||||
val header = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
val header = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
||||||
val msg = new Message(header, new RouteRequest(AddressTest.a3, 2, 3, 1))
|
val msg = new Message(header, new RouteRequest(AddressTest.a3, 2, 3, 1))
|
||||||
val rmi = new RouteMessageInfo()
|
val rmi = new routing.RouteMessageInfo()
|
||||||
assertFalse(rmi.isMessageRedundant(msg))
|
assertFalse(rmi.isMessageRedundant(msg))
|
||||||
assertTrue(rmi.isMessageRedundant(msg))
|
assertTrue(rmi.isMessageRedundant(msg))
|
||||||
}
|
}
|
||||||
|
@ -26,7 +27,7 @@ class RouteMessageInfoTest extends TestCase {
|
||||||
def testSeqNumOlder(): Unit = {
|
def testSeqNumOlder(): Unit = {
|
||||||
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
||||||
val msg1 = new Message(header1, new RouteRequest(AddressTest.a3, 0, 0, 0))
|
val msg1 = new Message(header1, new RouteRequest(AddressTest.a3, 0, 0, 0))
|
||||||
val rmi = new RouteMessageInfo()
|
val rmi = new routing.RouteMessageInfo()
|
||||||
assertFalse(rmi.isMessageRedundant(msg1))
|
assertFalse(rmi.isMessageRedundant(msg1))
|
||||||
|
|
||||||
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 3, 0)
|
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 3, 0)
|
||||||
|
@ -40,7 +41,7 @@ class RouteMessageInfoTest extends TestCase {
|
||||||
def testMetricWorse(): Unit = {
|
def testMetricWorse(): Unit = {
|
||||||
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
||||||
val msg1 = new Message(header1, new RouteRequest(AddressTest.a3, 1, 0, 2))
|
val msg1 = new Message(header1, new RouteRequest(AddressTest.a3, 1, 0, 2))
|
||||||
val rmi = new RouteMessageInfo()
|
val rmi = new routing.RouteMessageInfo()
|
||||||
assertFalse(rmi.isMessageRedundant(msg1))
|
assertFalse(rmi.isMessageRedundant(msg1))
|
||||||
|
|
||||||
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 2, 0)
|
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 2, 0)
|
||||||
|
@ -54,7 +55,7 @@ class RouteMessageInfoTest extends TestCase {
|
||||||
def testMetricBetter(): Unit = {
|
def testMetricBetter(): Unit = {
|
||||||
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
val header1 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
||||||
val msg1 = new Message(header1, new RouteReply(0, 4))
|
val msg1 = new Message(header1, new RouteReply(0, 4))
|
||||||
val rmi = new RouteMessageInfo()
|
val rmi = new routing.RouteMessageInfo()
|
||||||
assertFalse(rmi.isMessageRedundant(msg1))
|
assertFalse(rmi.isMessageRedundant(msg1))
|
||||||
|
|
||||||
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 2, 0)
|
val header2 = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 2, 0)
|
||||||
|
@ -66,7 +67,7 @@ class RouteMessageInfoTest extends TestCase {
|
||||||
* Test that entries are removed after [[RouteMessageInfo.MaxSeqnumLifetime]].
|
* Test that entries are removed after [[RouteMessageInfo.MaxSeqnumLifetime]].
|
||||||
*/
|
*/
|
||||||
def testTimeout(): Unit = {
|
def testTimeout(): Unit = {
|
||||||
val rmi = new RouteMessageInfo()
|
val rmi = new routing.RouteMessageInfo()
|
||||||
DateTimeUtils.setCurrentMillisFixed(DateTime.now.getMillis)
|
DateTimeUtils.setCurrentMillisFixed(DateTime.now.getMillis)
|
||||||
val header = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
val header = new MessageHeader(RouteRequest.Type, AddressTest.a1, AddressTest.a2, 1, 0)
|
||||||
val msg = new Message(header, new RouteRequest(AddressTest.a3, 0, 0, 0))
|
val msg = new Message(header, new RouteRequest(AddressTest.a3, 0, 0, 0))
|
|
@ -1,23 +1,23 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.routing
|
||||||
|
|
||||||
import java.util.GregorianCalendar
|
import java.util.GregorianCalendar
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.{Text, UserInfo}
|
import com.nutomic.ensichat.core.messages.body.{Text, UserInfo}
|
||||||
import com.nutomic.ensichat.core.header.ContentHeader
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
import com.nutomic.ensichat.core.util.LocalRoutesInfo
|
import com.nutomic.ensichat.core.{messages, routing}
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
||||||
class RouterTest extends TestCase {
|
class RouterTest extends TestCase {
|
||||||
|
|
||||||
private def neighbors() = Set[Address](AddressTest.a1, AddressTest.a2, AddressTest.a4)
|
private def neighbors() = Set[routing.Address](AddressTest.a1, AddressTest.a2, AddressTest.a4)
|
||||||
|
|
||||||
def testNoRouteFound(): Unit = {
|
def testNoRouteFound(): Unit = {
|
||||||
val msg = generateMessage(AddressTest.a2, AddressTest.a3, 1)
|
val msg = generateMessage(AddressTest.a2, AddressTest.a3, 1)
|
||||||
val latch = new CountDownLatch(1)
|
val latch = new CountDownLatch(1)
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors),
|
val router = new routing.Router(new LocalRoutesInfo(neighbors),
|
||||||
(_, _) => fail("Message shouldn't be forwarded"), m => {
|
(_, _) => fail("Message shouldn't be forwarded"), m => {
|
||||||
assertEquals(msg, m)
|
assertEquals(msg, m)
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
|
@ -28,8 +28,8 @@ class RouterTest extends TestCase {
|
||||||
|
|
||||||
def testNextHop(): Unit = {
|
def testNextHop(): Unit = {
|
||||||
val msg = generateMessage(AddressTest.a1, AddressTest.a4, 1)
|
val msg = generateMessage(AddressTest.a1, AddressTest.a4, 1)
|
||||||
var sentTo = Set[Address]()
|
var sentTo = Set[routing.Address]()
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors),
|
val router = new routing.Router(new LocalRoutesInfo(neighbors),
|
||||||
(a, m) => {
|
(a, m) => {
|
||||||
sentTo += a
|
sentTo += a
|
||||||
}, _ => ())
|
}, _ => ())
|
||||||
|
@ -40,7 +40,7 @@ class RouterTest extends TestCase {
|
||||||
|
|
||||||
def testMessageSame(): Unit = {
|
def testMessageSame(): Unit = {
|
||||||
val msg = generateMessage(AddressTest.a1, AddressTest.a4, 1)
|
val msg = generateMessage(AddressTest.a1, AddressTest.a4, 1)
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors),
|
val router = new routing.Router(new LocalRoutesInfo(neighbors),
|
||||||
(a, m) => {
|
(a, m) => {
|
||||||
assertEquals(msg.header.origin, m.header.origin)
|
assertEquals(msg.header.origin, m.header.origin)
|
||||||
assertEquals(msg.header.target, m.header.target)
|
assertEquals(msg.header.target, m.header.target)
|
||||||
|
@ -58,31 +58,31 @@ class RouterTest extends TestCase {
|
||||||
* Messages from different senders with the same sequence number should be forwarded.
|
* Messages from different senders with the same sequence number should be forwarded.
|
||||||
*/
|
*/
|
||||||
def testDifferentSenders(): Unit = {
|
def testDifferentSenders(): Unit = {
|
||||||
var sentTo = Set[Address]()
|
var sentTo = Set[routing.Address]()
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors), (a, m) => sentTo += a, _ => ())
|
val router = new routing.Router(new LocalRoutesInfo(neighbors), (a, m) => sentTo += a, _ => ())
|
||||||
|
|
||||||
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, 1))
|
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, 1))
|
||||||
assertEquals(Set(AddressTest.a4), sentTo)
|
assertEquals(Set(AddressTest.a4), sentTo)
|
||||||
|
|
||||||
sentTo = Set[Address]()
|
sentTo = Set[routing.Address]()
|
||||||
router.forwardMessage(generateMessage(AddressTest.a2, AddressTest.a4, 1))
|
router.forwardMessage(generateMessage(AddressTest.a2, AddressTest.a4, 1))
|
||||||
assertEquals(Set(AddressTest.a4), sentTo)
|
assertEquals(Set(AddressTest.a4), sentTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
def testSeqNumComparison(): Unit = {
|
def testSeqNumComparison(): Unit = {
|
||||||
Router.compare(1, ContentHeader.SeqNumRange.last)
|
routing.Router.compare(1, ContentHeader.SeqNumRange.last)
|
||||||
Router.compare(ContentHeader.SeqNumRange.last / 2, ContentHeader.SeqNumRange.last)
|
routing.Router.compare(ContentHeader.SeqNumRange.last / 2, ContentHeader.SeqNumRange.last)
|
||||||
Router.compare(ContentHeader.SeqNumRange.last / 2, 1)
|
routing.Router.compare(ContentHeader.SeqNumRange.last / 2, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
def testDiscardOldIgnores(): Unit = {
|
def testDiscardOldIgnores(): Unit = {
|
||||||
def test(first: Int, second: Int) {
|
def test(first: Int, second: Int) {
|
||||||
var sentTo = Set[Address]()
|
var sentTo = Set[routing.Address]()
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors), (a, m) => sentTo += a, _ => ())
|
val router = new routing.Router(new LocalRoutesInfo(neighbors), (a, m) => sentTo += a, _ => ())
|
||||||
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, first))
|
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, first))
|
||||||
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, second))
|
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, second))
|
||||||
|
|
||||||
sentTo = Set[Address]()
|
sentTo = Set[routing.Address]()
|
||||||
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, first))
|
router.forwardMessage(generateMessage(AddressTest.a1, AddressTest.a4, first))
|
||||||
assertEquals(Set(AddressTest.a4), sentTo)
|
assertEquals(Set(AddressTest.a4), sentTo)
|
||||||
}
|
}
|
||||||
|
@ -93,16 +93,16 @@ class RouterTest extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
def testHopLimit(): Unit = Range(19, 22).foreach { i =>
|
def testHopLimit(): Unit = Range(19, 22).foreach { i =>
|
||||||
val msg = new Message(
|
val msg = new messages.Message(
|
||||||
new ContentHeader(AddressTest.a1, AddressTest.a2, 1, 1, Some(1), Some(DateTime.now), 3, i), new Text(""))
|
new ContentHeader(AddressTest.a1, AddressTest.a2, 1, 1, Some(1), Some(DateTime.now), 3, i), new Text(""))
|
||||||
val router = new Router(new LocalRoutesInfo(neighbors), (a, m) => fail(), _ => ())
|
val router = new routing.Router(new LocalRoutesInfo(neighbors), (a, m) => fail(), _ => ())
|
||||||
router.forwardMessage(msg)
|
router.forwardMessage(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def generateMessage(sender: Address, receiver: Address, seqNum: Int): Message = {
|
private def generateMessage(sender: routing.Address, receiver: routing.Address, seqNum: Int): messages.Message = {
|
||||||
val header = new ContentHeader(sender, receiver, seqNum, UserInfo.Type, Some(5),
|
val header = new ContentHeader(sender, receiver, seqNum, UserInfo.Type, Some(5),
|
||||||
Some(new DateTime(new GregorianCalendar(2014, 6, 10).getTime)), 3)
|
Some(new DateTime(new GregorianCalendar(2014, 6, 10).getTime)), 3)
|
||||||
new Message(header, new UserInfo("", ""))
|
new messages.Message(header, new UserInfo("", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
package com.nutomic.ensichat.core
|
package com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
import com.nutomic.ensichat.core.interfaces.SettingsInterface
|
||||||
|
import com.nutomic.ensichat.core.messages.MessageTest
|
||||||
|
import com.nutomic.ensichat.core.util
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert._
|
import org.junit.Assert._
|
||||||
|
|
||||||
|
@ -14,9 +16,9 @@ object CryptoTest {
|
||||||
override def put[T](key: String, value: T): Unit = map += (key -> value)
|
override def put[T](key: String, value: T): Unit = map += (key -> value)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getCrypto: Crypto = {
|
def getCrypto: util.Crypto = {
|
||||||
val tempFolder = new File(System.getProperty("testDir"), "/crypto/")
|
val tempFolder = new File(System.getProperty("testDir"), "/crypto/")
|
||||||
val crypto = new Crypto(new TestSettings(), tempFolder)
|
val crypto = new util.Crypto(new TestSettings(), tempFolder)
|
||||||
if (!crypto.localKeysExist) {
|
if (!crypto.localKeysExist) {
|
||||||
crypto.generateLocalKeys()
|
crypto.generateLocalKeys()
|
||||||
}
|
}
|
|
@ -4,11 +4,12 @@ import java.io.File
|
||||||
import java.util.GregorianCalendar
|
import java.util.GregorianCalendar
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.Text
|
|
||||||
import com.nutomic.ensichat.core.header.ContentHeader
|
|
||||||
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
||||||
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
|
import com.nutomic.ensichat.core.messages.header.ContentHeader
|
||||||
|
import com.nutomic.ensichat.core.routing.Address
|
||||||
import com.nutomic.ensichat.core.util.DatabaseTest._
|
import com.nutomic.ensichat.core.util.DatabaseTest._
|
||||||
import com.nutomic.ensichat.core.{Address, Message, User}
|
|
||||||
import junit.framework.Assert._
|
import junit.framework.Assert._
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
|
import com.nutomic.ensichat.core.routing.AddressTest
|
||||||
|
import com.nutomic.ensichat.core.util
|
||||||
|
|
||||||
|
object UserTest {
|
||||||
|
|
||||||
|
val u1 = new util.User(AddressTest.a1, "one", "s1")
|
||||||
|
|
||||||
|
val u2 = new util.User(AddressTest.a2, "two", "s2")
|
||||||
|
|
||||||
|
val u3 = new util.User(AddressTest.a3, "three", "s3")
|
||||||
|
|
||||||
|
}
|
|
@ -4,8 +4,9 @@ import java.io.File
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
||||||
import com.nutomic.ensichat.core.util.Database
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.{ConnectionHandler, Crypto, Message}
|
import com.nutomic.ensichat.core.util.{Crypto, Database}
|
||||||
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.nutomic.ensichat.integration.LocalNode._
|
import com.nutomic.ensichat.integration.LocalNode._
|
||||||
|
|
||||||
import scala.concurrent.Await
|
import scala.concurrent.Await
|
||||||
|
|
|
@ -3,9 +3,8 @@ package com.nutomic.ensichat.integration
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
import java.util.concurrent.{CountDownLatch, TimeUnit}
|
||||||
import java.util.{Timer, TimerTask}
|
import java.util.{Timer, TimerTask}
|
||||||
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
import com.nutomic.ensichat.core.Crypto
|
import com.nutomic.ensichat.core.util.Crypto
|
||||||
import com.nutomic.ensichat.core.body.Text
|
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration.Duration
|
import scala.concurrent.duration.Duration
|
||||||
|
|
|
@ -4,10 +4,11 @@ import java.io.File
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
import com.nutomic.ensichat.core.body.Text
|
import com.nutomic.ensichat.core.messages.body.Text
|
||||||
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
|
||||||
import com.nutomic.ensichat.core.util.Database
|
import com.nutomic.ensichat.core.messages.Message
|
||||||
import com.nutomic.ensichat.core.{ConnectionHandler, Crypto, Message}
|
import com.nutomic.ensichat.core.util.{Crypto, Database}
|
||||||
|
import com.nutomic.ensichat.core.ConnectionHandler
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
import scopt.OptionParser
|
import scopt.OptionParser
|
||||||
|
|
||||||
|
|
Reference in a new issue