Use SLF4J for logging.

This commit is contained in:
Felix Ableitner 2016-05-04 07:03:02 +02:00
parent 8bafd62e35
commit 2cc4928a99
17 changed files with 82 additions and 148 deletions

View file

@ -17,6 +17,7 @@ dependencies {
compile 'com.mobsandgeeks:adapter-kit:0.5.3' compile 'com.mobsandgeeks:adapter-kit:0.5.3'
compile 'com.google.zxing:android-integration:3.2.1' compile 'com.google.zxing:android-integration:3.2.1'
compile 'com.google.zxing:core:3.2.1' compile 'com.google.zxing:core:3.2.1'
compile 'org.slf4j:slf4j-android:1.7.21'
compile project(path: ':core') compile project(path: ':core')
androidTestCompile 'com.android.support:multidex-instrumentation:1.0.1', androidTestCompile 'com.android.support:multidex-instrumentation:1.0.1',
{ exclude module: 'multidex' } { exclude module: 'multidex' }

View file

@ -1,14 +1,12 @@
package com.nutomic.ensichat package com.nutomic.ensichat
import android.support.multidex.MultiDexApplication import android.support.multidex.MultiDexApplication
import com.nutomic.ensichat.core.interfaces.Log import com.nutomic.ensichat.util.PRNGFixes
import com.nutomic.ensichat.util.{Logging, PRNGFixes}
class App extends MultiDexApplication { class App extends MultiDexApplication {
override def onCreate(): Unit = { override def onCreate(): Unit = {
super.onCreate() super.onCreate()
Log.setLogInstance(new Logging())
PRNGFixes.apply() PRNGFixes.apply()
} }

View file

@ -1,13 +0,0 @@
package com.nutomic.ensichat.util
import android.util
import com.nutomic.ensichat.core.interfaces.Log
class Logging extends Log {
def v(tag: String, message: String, tr: Throwable = null) = util.Log.v(tag, message, tr)
def d(tag: String, message: String, tr: Throwable = null) = util.Log.d(tag, message, tr)
def i(tag: String, message: String, tr: Throwable = null) = util.Log.i(tag, message, tr)
def w(tag: String, message: String, tr: Throwable = null) = util.Log.w(tag, message, tr)
def e(tag: String, message: String, tr: Throwable = null) = util.Log.e(tag, message, tr)
}

View file

@ -4,6 +4,7 @@ dependencies {
compile 'org.scala-lang:scala-library:2.11.7' compile 'org.scala-lang:scala-library:2.11.7'
compile 'com.h2database:h2:1.4.191' compile 'com.h2database:h2:1.4.191'
compile 'com.typesafe.slick:slick_2.11:3.1.1' compile 'com.typesafe.slick:slick_2.11:3.1.1'
compile 'com.typesafe.scala-logging:scala-logging_2.11:3.4.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
} }

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<target>System.out</target>
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="slick" level="INFO" />
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

View file

@ -7,6 +7,7 @@ import com.nutomic.ensichat.core.header.ContentHeader
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.util.{Database, FutureHelper} import com.nutomic.ensichat.core.util.{Database, FutureHelper}
import com.typesafe.scalalogging.Logger
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -20,7 +21,7 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
callbacks: CallbackInterface, crypto: Crypto, callbacks: CallbackInterface, crypto: Crypto,
maxInternetConnections: Int) { maxInternetConnections: Int) {
private val Tag = "ConnectionHandler" private val logger = Logger(this.getClass)
private var transmissionInterfaces = Set[TransmissionInterface]() private var transmissionInterfaces = Set[TransmissionInterface]()
@ -45,8 +46,8 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
additionalInterfaces.foreach(transmissionInterfaces += _) additionalInterfaces.foreach(transmissionInterfaces += _)
FutureHelper { FutureHelper {
crypto.generateLocalKeys() crypto.generateLocalKeys()
Log.i(Tag, "Service started, address is " + crypto.localAddress) logger.info("Service started, address is " + crypto.localAddress)
Log.i(Tag, "Local user is " + settings.get(SettingsInterface.KeyUserName, "none") + logger.info("Local user is " + settings.get(SettingsInterface.KeyUserName, "none") +
" with status '" + settings.get(SettingsInterface.KeyUserStatus, "") + "'") " with status '" + settings.get(SettingsInterface.KeyUserStatus, "") + "'")
transmissionInterfaces += new InternetInterface(this, crypto, settings, maxInternetConnections) transmissionInterfaces += new InternetInterface(this, crypto, settings, maxInternetConnections)
transmissionInterfaces.foreach(_.create()) transmissionInterfaces.foreach(_.create())
@ -83,11 +84,11 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
*/ */
def onMessageReceived(msg: Message): Unit = { def onMessageReceived(msg: Message): Unit = {
if (router.isMessageSeen(msg)) { if (router.isMessageSeen(msg)) {
Log.v(Tag, "Ignoring message from " + msg.header.origin + " that we already received") logger.trace("Ignoring message from " + msg.header.origin + " that we already received")
} else if (msg.header.target == crypto.localAddress) { } else if (msg.header.target == crypto.localAddress) {
crypto.verifyAndDecrypt(msg) match { crypto.verifyAndDecrypt(msg) match {
case Some(m) => onNewMessage(m) case Some(m) => onNewMessage(m)
case None => Log.i(Tag, "Ignoring message with invalid signature from " + msg.header.origin) case None => logger.info("Ignoring message with invalid signature from " + msg.header.origin)
} }
} else { } else {
router.forwardMessage(msg) router.forwardMessage(msg)
@ -127,34 +128,34 @@ final class ConnectionHandler(settings: SettingsInterface, database: Database,
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) {
Log.i(Tag, "Maximum number of connections reached") logger.info("Maximum number of connections reached")
return false return false
} }
val info = msg.body.asInstanceOf[ConnectionInfo] val info = msg.body.asInstanceOf[ConnectionInfo]
val sender = crypto.calculateAddress(info.key) val sender = crypto.calculateAddress(info.key)
if (sender == Address.Broadcast || sender == Address.Null) { if (sender == Address.Broadcast || sender == Address.Null) {
Log.i(Tag, "Ignoring ConnectionInfo message with invalid sender " + sender) logger.info("Ignoring ConnectionInfo message with invalid sender " + sender)
return false return false
} }
if (crypto.havePublicKey(sender) && !crypto.verify(msg, Option(crypto.getPublicKey(sender)))) { if (crypto.havePublicKey(sender) && !crypto.verify(msg, Option(crypto.getPublicKey(sender)))) {
Log.i(Tag, "Ignoring ConnectionInfo message with invalid signature") logger.info("Ignoring ConnectionInfo message with invalid signature")
return false return false
} }
synchronized { synchronized {
if (!crypto.havePublicKey(sender)) { if (!crypto.havePublicKey(sender)) {
crypto.addPublicKey(sender, info.key) crypto.addPublicKey(sender, info.key)
Log.i(Tag, "Added public key for new device " + sender.toString) logger.info("Added public key for new device " + sender.toString)
} }
} }
// Log with username if we know it. // Log with username if we know it.
if (allKnownUsers().map(_.address).contains(sender)) if (allKnownUsers().map(_.address).contains(sender))
Log.i(Tag, "Node " + getUser(sender).name + " (" + sender + ") connected") logger.info("Node " + getUser(sender).name + " (" + sender + ") connected")
else else
Log.i(Tag, "Node " + sender + " connected") logger.info("Node " + sender + " connected")
sendTo(sender, new UserInfo(settings.get(SettingsInterface.KeyUserName, ""), sendTo(sender, new UserInfo(settings.get(SettingsInterface.KeyUserName, ""),
settings.get(SettingsInterface.KeyUserStatus, ""))) settings.get(SettingsInterface.KeyUserStatus, "")))

View file

@ -9,7 +9,8 @@ import javax.crypto.{Cipher, CipherOutputStream, KeyGenerator, SecretKey}
import com.nutomic.ensichat.core.Crypto._ import com.nutomic.ensichat.core.Crypto._
import com.nutomic.ensichat.core.body._ import com.nutomic.ensichat.core.body._
import com.nutomic.ensichat.core.header.ContentHeader import com.nutomic.ensichat.core.header.ContentHeader
import com.nutomic.ensichat.core.interfaces.{Log, SettingsInterface} import com.nutomic.ensichat.core.interfaces.SettingsInterface
import com.typesafe.scalalogging.Logger
object Crypto { object Crypto {
@ -76,7 +77,7 @@ object Crypto {
*/ */
class Crypto(settings: SettingsInterface, keyFolder: File) { class Crypto(settings: SettingsInterface, keyFolder: File) {
private val Tag = "Crypto" private val logger = Logger(this.getClass)
/** /**
* Generates a new key pair using [[keyFolder]] with [[PublicKeySize]] bits and stores the * Generates a new key pair using [[keyFolder]] with [[PublicKeySize]] bits and stores the
@ -104,7 +105,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
saveKey(PrivateKeyAlias, keyPair.getPrivate) saveKey(PrivateKeyAlias, keyPair.getPrivate)
saveKey(PublicKeyAlias, keyPair.getPublic) saveKey(PublicKeyAlias, keyPair.getPublic)
Log.i(Tag, "Generated cryptographic keys, address is " + address) logger.info("Generated cryptographic keys, address is " + address)
} }
/** /**
@ -184,7 +185,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
fos = Option(new FileOutputStream(path)) fos = Option(new FileOutputStream(path))
fos.foreach(_.write(key.getEncoded)) fos.foreach(_.write(key.getEncoded))
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to save key for alias " + alias, e) case e: IOException => logger.warn("Failed to save key for alias " + alias, e)
} finally { } finally {
fos.foreach(_.close()) fos.foreach(_.close())
} }
@ -212,7 +213,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
data = new Array[Byte](path.length().asInstanceOf[Int]) data = new Array[Byte](path.length().asInstanceOf[Int])
fis.foreach(_.read(data)) fis.foreach(_.read(data))
} catch { } catch {
case e: IOException => Log.e(Tag, "Failed to load key for alias " + alias, e) case e: IOException => logger.error("Failed to load key for alias " + alias, e)
} finally { } finally {
fis.foreach(_.close()) fis.foreach(_.close())
} }
@ -240,7 +241,7 @@ class Crypto(settings: SettingsInterface, keyFolder: File) {
None None
} catch { } catch {
case e: InvalidKeyException => case e: InvalidKeyException =>
Log.w(Tag, "Failed to verify or decrypt message", e) logger.warn("Failed to verify or decrypt message", e)
None None
} }
} }

View file

@ -1,25 +0,0 @@
package com.nutomic.ensichat.core.interfaces
object Log {
def setLogInstance(log: Log) = instance = Option(log)
private var instance: Option[Log] = None
def v(tag: String, message: String, tr: Throwable = null) = instance.foreach(_.v(tag, message, tr))
def d(tag: String, message: String, tr: Throwable = null) = instance.foreach(_.d(tag, message, tr))
def i(tag: String, message: String, tr: Throwable = null) = instance.foreach(_.i(tag, message, tr))
def w(tag: String, message: String, tr: Throwable = null) = instance.foreach(_.w(tag, message, tr))
def e(tag: String, message: String, tr: Throwable = null) = instance.foreach(_.e(tag, message, tr))
}
trait Log {
def v(tag: String, message: String, tr: Throwable = null)
def d(tag: String, message: String, tr: Throwable = null)
def i(tag: String, message: String, tr: Throwable = null)
def w(tag: String, message: String, tr: Throwable = null)
def e(tag: String, message: String, tr: Throwable = null)
}

View file

@ -6,8 +6,8 @@ import java.net.{InetAddress, Socket}
import com.nutomic.ensichat.core.Message.ReadMessageException import com.nutomic.ensichat.core.Message.ReadMessageException
import com.nutomic.ensichat.core.body.ConnectionInfo import com.nutomic.ensichat.core.body.ConnectionInfo
import com.nutomic.ensichat.core.header.MessageHeader import com.nutomic.ensichat.core.header.MessageHeader
import com.nutomic.ensichat.core.interfaces.Log
import com.nutomic.ensichat.core.{Address, Crypto, Message} import com.nutomic.ensichat.core.{Address, Crypto, Message}
import com.typesafe.scalalogging.Logger
/** /**
* Encapsulates an active connection to another node. * Encapsulates an active connection to another node.
@ -15,14 +15,14 @@ import com.nutomic.ensichat.core.{Address, Crypto, Message}
class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (InternetConnectionThread) => Unit, class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (InternetConnectionThread) => Unit,
onReceive: (Message, InternetConnectionThread) => Unit) extends Thread { onReceive: (Message, InternetConnectionThread) => Unit) extends Thread {
private val Tag = "InternetConnectionThread" private val logger = Logger(this.getClass)
private val inStream: InputStream = private val inStream: InputStream =
try { try {
socket.getInputStream socket.getInputStream
} catch { } catch {
case e: IOException => case e: IOException =>
Log.e(Tag, "Failed to open stream", e) logger.error("Failed to open stream", e)
close() close()
null null
} }
@ -32,7 +32,7 @@ class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (
socket.getOutputStream socket.getOutputStream
} catch { } catch {
case e: IOException => case e: IOException =>
Log.e(Tag, "Failed to open stream", e) logger.error("Failed to open stream", e)
close() close()
null null
} }
@ -42,7 +42,7 @@ class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (
} }
override def run(): Unit = { override def run(): Unit = {
Log.i(Tag, "Connection opened to " + socket.getInetAddress) logger.info("Connection opened to " + socket.getInetAddress)
send(crypto.sign(new Message(new MessageHeader(ConnectionInfo.Type, send(crypto.sign(new Message(new MessageHeader(ConnectionInfo.Type,
Address.Null, Address.Null, 0), new ConnectionInfo(crypto.getLocalPublicKey)))) Address.Null, Address.Null, 0), new ConnectionInfo(crypto.getLocalPublicKey))))
@ -51,13 +51,13 @@ class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (
socket.setKeepAlive(true) socket.setKeepAlive(true)
while (socket.isConnected) { while (socket.isConnected) {
val msg = Message.read(inStream) val msg = Message.read(inStream)
Log.v(Tag, "Received " + msg) logger.trace("Received " + msg)
onReceive(msg, this) onReceive(msg, this)
} }
} catch { } catch {
case e @ (_: ReadMessageException | _: IOException) => case e @ (_: ReadMessageException | _: IOException) =>
Log.w(Tag, "Failed to read incoming message", e) logger.warn("Failed to read incoming message", e)
close() close()
return return
} }
@ -68,7 +68,7 @@ class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (
try { try {
outStream.write(msg.write) outStream.write(msg.write)
} catch { } catch {
case e: IOException => Log.e(Tag, "Failed to write message", e) case e: IOException => logger.error("Failed to write message", e)
} }
} }
@ -76,9 +76,9 @@ class InternetConnectionThread(socket: Socket, crypto: Crypto, onDisconnected: (
try { try {
socket.close() socket.close()
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to close socket", e) case e: IOException => logger.warn("Failed to close socket", e)
} }
Log.d(Tag, "Connection to " + socket.getInetAddress + " closed") logger.debug("Connection to " + socket.getInetAddress + " closed")
onDisconnected(this) onDisconnected(this)
} }

View file

@ -1,14 +1,15 @@
package com.nutomic.ensichat.core.internet package com.nutomic.ensichat.core.internet
import java.io.IOException
import java.net.{InetAddress, Socket} import java.net.{InetAddress, Socket}
import com.nutomic.ensichat.core.body.ConnectionInfo import com.nutomic.ensichat.core.body.ConnectionInfo
import com.nutomic.ensichat.core.interfaces.{Log, SettingsInterface, TransmissionInterface} import com.nutomic.ensichat.core.interfaces.{SettingsInterface, TransmissionInterface}
import com.nutomic.ensichat.core.util.FutureHelper import com.nutomic.ensichat.core.util.FutureHelper
import com.nutomic.ensichat.core.{Address, ConnectionHandler, Crypto, Message} import com.nutomic.ensichat.core.{Address, ConnectionHandler, Crypto, Message}
import com.typesafe.scalalogging.Logger
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Random import scala.util.Random
object InternetInterface { object InternetInterface {
@ -26,7 +27,7 @@ class InternetInterface(connectionHandler: ConnectionHandler, crypto: Crypto,
settings: SettingsInterface, maxConnections: Int) settings: SettingsInterface, maxConnections: Int)
extends TransmissionInterface { extends TransmissionInterface {
private val Tag = "InternetInterface" private val logger = Logger(this.getClass)
private lazy val serverThread = private lazy val serverThread =
new InternetServerThread(crypto, onConnected, onDisconnected, onReceiveMessage) new InternetServerThread(crypto, onConnected, onDisconnected, onReceiveMessage)
@ -83,15 +84,14 @@ class InternetInterface(connectionHandler: ConnectionHandler, crypto: Crypto,
* Opens connection to the specified IP address in client mode. * Opens connection to the specified IP address in client mode.
*/ */
private def openConnection(address: String, port: Int): Unit = { private def openConnection(address: String, port: Int): Unit = {
Log.i(Tag, s"Attempting connection to $address:$port") logger.info(s"Attempting connection to $address:$port")
try { Future {
val socket = new Socket(InetAddress.getByName(address), port) val socket = new Socket(InetAddress.getByName(address), port)
val ct = new InternetConnectionThread(socket, crypto, onDisconnected, onReceiveMessage) val ct = new InternetConnectionThread(socket, crypto, onDisconnected, onReceiveMessage)
connections += ct connections += ct
ct.start() ct.start()
} catch { }.onFailure { case e =>
case e: IOException => logger.warn("Failed to open connection to " + address + ":" + port, e)
Log.w(Tag, "Failed to open connection to " + address + ":" + port, e)
} }
} }
@ -101,7 +101,7 @@ class InternetInterface(connectionHandler: ConnectionHandler, crypto: Crypto,
private def onDisconnected(connectionThread: InternetConnectionThread): Unit = { private def onDisconnected(connectionThread: InternetConnectionThread): Unit = {
addressDeviceMap.find(_._2 == connectionThread).foreach { ad => addressDeviceMap.find(_._2 == connectionThread).foreach { ad =>
Log.d(Tag, "Connection closed to " + ad._1) logger.trace("Connection closed to " + ad._1)
connections -= connectionThread connections -= connectionThread
addressDeviceMap -= ad._1 addressDeviceMap -= ad._1
connectionHandler.onConnectionClosed() connectionHandler.onConnectionClosed()
@ -112,7 +112,7 @@ class InternetInterface(connectionHandler: ConnectionHandler, crypto: Crypto,
case info: ConnectionInfo => case info: ConnectionInfo =>
val address = crypto.calculateAddress(info.key) val address = crypto.calculateAddress(info.key)
if (address == crypto.localAddress) { if (address == crypto.localAddress) {
Log.i(Tag, "Address " + address + " is me, not connecting to myself") logger.info("Address " + address + " is me, not connecting to myself")
thread.close() thread.close()
return return
} }
@ -141,7 +141,7 @@ class InternetInterface(connectionHandler: ConnectionHandler, crypto: Crypto,
def connectionChanged(): Unit = { def connectionChanged(): Unit = {
FutureHelper { FutureHelper {
Log.i(Tag, "Network has changed. Closing all connections and connecting to bootstrap nodes again") logger.info("Network has changed. Closing all connections and connecting to bootstrap nodes again")
connections.foreach(_.close()) connections.foreach(_.close())
openAllConnections(maxConnections) openAllConnections(maxConnections)
} }

View file

@ -3,19 +3,19 @@ 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.interfaces.Log
import com.nutomic.ensichat.core.{Crypto, Message} import com.nutomic.ensichat.core.{Crypto, Message}
import com.typesafe.scalalogging.Logger
class InternetServerThread(crypto: Crypto, onConnected: (InternetConnectionThread) => Unit, class InternetServerThread(crypto: Crypto, onConnected: (InternetConnectionThread) => Unit,
onDisconnected: (InternetConnectionThread) => Unit, onReceive: (Message, InternetConnectionThread) => Unit) extends Thread { onDisconnected: (InternetConnectionThread) => Unit, onReceive: (Message, InternetConnectionThread) => Unit) extends Thread {
private val Tag = "InternetServerThread" private val logger = Logger(this.getClass)
private lazy val socket: Option[ServerSocket] = try { private lazy val socket: Option[ServerSocket] = try {
Option(new ServerSocket(InternetInterface.ServerPort)) Option(new ServerSocket(InternetInterface.ServerPort))
} catch { } catch {
case e: IOException => case e: IOException =>
Log.w(Tag, "Failed to create server socket", e) logger.warn("Failed to create server socket", e)
None None
} }
@ -27,7 +27,7 @@ class InternetServerThread(crypto: Crypto, onConnected: (InternetConnectionThrea
connection.start() connection.start()
} }
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to accept connection", e) case e: IOException => logger.warn("Failed to accept connection", e)
} }
} }
@ -35,7 +35,7 @@ class InternetServerThread(crypto: Crypto, onConnected: (InternetConnectionThrea
try { try {
socket.get.close() socket.get.close()
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to close socket", e) case e: IOException => logger.warn("Failed to close socket", e)
} }
} }

View file

@ -5,10 +5,10 @@ import java.util.Date
import com.nutomic.ensichat.core.body.Text import com.nutomic.ensichat.core.body.Text
import com.nutomic.ensichat.core.header.ContentHeader import com.nutomic.ensichat.core.header.ContentHeader
import com.nutomic.ensichat.core.interfaces.{Log, CallbackInterface} import com.nutomic.ensichat.core.interfaces.CallbackInterface
import com.nutomic.ensichat.core.{Address, Message, User} import com.nutomic.ensichat.core.{Address, Message, User}
import com.typesafe.scalalogging.Logger
import slick.driver.H2Driver.api._ import slick.driver.H2Driver.api._
import slick.jdbc.meta.MTable
import scala.concurrent.Await import scala.concurrent.Await
import scala.concurrent.duration.Duration import scala.concurrent.duration.Duration
@ -21,7 +21,7 @@ import scala.concurrent.duration.Duration
*/ */
class Database(path: File, callbackInterface: CallbackInterface) { class Database(path: File, callbackInterface: CallbackInterface) {
private val Tag = "Database" private val logger = Logger(this.getClass)
private class Messages(tag: Tag) extends Table[Message](tag, "MESSAGES") { private class Messages(tag: Tag) extends Table[Message](tag, "MESSAGES") {
def id = primaryKey("id", (origin, messageId)) def id = primaryKey("id", (origin, messageId))
@ -63,7 +63,7 @@ class Database(path: File, callbackInterface: CallbackInterface) {
// H2 appends a .mv.db suffix to the path which we can't change, so we have to check that file. // H2 appends a .mv.db suffix to the path which we can't change, so we have to check that file.
val dbFile = new File(path.getAbsolutePath + ".mv.db") val dbFile = new File(path.getAbsolutePath + ".mv.db")
if (!dbFile.exists()) { if (!dbFile.exists()) {
Log.i(Tag, "Database does not exist, creating tables") logger.info("Database does not exist, creating tables")
Await.result(db.run((messages.schema ++ contacts.schema).create), Duration.Inf) Await.result(db.run((messages.schema ++ contacts.schema).create), Duration.Inf)
} }
} }

View file

@ -1,6 +1,6 @@
package com.nutomic.ensichat.core.util package com.nutomic.ensichat.core.util
import com.nutomic.ensichat.core.interfaces.Log import com.typesafe.scalalogging.Logger
import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.{ExecutionContext, Future}
@ -11,7 +11,7 @@ import scala.concurrent.{ExecutionContext, Future}
*/ */
object FutureHelper { object FutureHelper {
private val Tag = "FutureHelper" private val logger = Logger(this.getClass)
def apply[A](action: => A)(implicit executor: ExecutionContext): Future[A] = { def apply[A](action: => A)(implicit executor: ExecutionContext): Future[A] = {
val f = Future(action) val f = Future(action)
@ -20,7 +20,7 @@ object FutureHelper {
// HACK: Android does not close app when crash occurs in background thread, and there's no // HACK: Android does not close app when crash occurs in background thread, and there's no
// cross-platform way to execute on the foreground thread. // cross-platform way to execute on the foreground thread.
// We use this to make sure exceptions are not hidden in the logs. // We use this to make sure exceptions are not hidden in the logs.
Log.e(Tag, "Exception in Future", e) logger.error("Exception in Future", e)
//System.exit(-1) //System.exit(-1)
} }
f f

View file

@ -5,6 +5,7 @@ dependencies {
compile 'org.scala-lang:scala-library:2.11.7' compile 'org.scala-lang:scala-library:2.11.7'
compile project(path: ':core') compile project(path: ':core')
compile 'com.github.scopt:scopt_2.10:3.3.0' compile 'com.github.scopt:scopt_2.10:3.3.0'
compile 'ch.qos.logback:logback-classic:1.1.7'
} }
mainClassName = 'com.nutomic.ensichat.server.Main' mainClassName = 'com.nutomic.ensichat.server.Main'

View file

@ -1,42 +0,0 @@
package com.nutomic.ensichat.server
import java.io.{PrintWriter, StringWriter}
import java.text.DateFormat
import java.util.{Date, Locale}
import com.nutomic.ensichat.core.interfaces.Log
import scala.collection.mutable
class Logging extends Log {
private val logs = new mutable.Queue[String]()
def dequeue(): Seq[String] = logs.dequeueAll((String) => true)
private def enqueue(tag: String, message: String, tr: Option[Throwable]): Unit = {
val df = DateFormat.getTimeInstance(DateFormat.DEFAULT, Locale.UK)
val throwableString = tr.map { tr =>
val sw = new StringWriter()
tr.printStackTrace(new PrintWriter(sw))
"\n" + sw.toString
}
logs.enqueue(df.format(new Date()) + " " + tag + ": " + message + throwableString.getOrElse(""))
}
def v(tag: String, message: String, tr: Throwable = null): Unit =
enqueue("V/" + tag, message, Option(tr))
def d(tag: String, message: String, tr: Throwable = null): Unit =
enqueue("D/" + tag, message, Option(tr))
def i(tag: String, message: String, tr: Throwable = null): Unit =
enqueue("I/" + tag, message, Option(tr))
def w(tag: String, message: String, tr: Throwable = null): Unit =
enqueue("W/" + tag, message, Option(tr))
def e(tag: String, message: String, tr: Throwable = null): Unit =
enqueue("E/" + tag, message, Option(tr))
}

View file

@ -5,24 +5,21 @@ 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.body.Text
import com.nutomic.ensichat.core.interfaces.SettingsInterface._ import com.nutomic.ensichat.core.interfaces.{CallbackInterface, SettingsInterface}
import com.nutomic.ensichat.core.interfaces.{CallbackInterface, Log, SettingsInterface}
import com.nutomic.ensichat.core.util.Database import com.nutomic.ensichat.core.util.Database
import com.nutomic.ensichat.core.{ConnectionHandler, Crypto, Message} import com.nutomic.ensichat.core.{ConnectionHandler, Crypto, Message}
import com.typesafe.scalalogging.Logger
import scopt.OptionParser import scopt.OptionParser
object Main extends App with CallbackInterface { object Main extends App with CallbackInterface {
private val Tag = "Main" private val logger = Logger(this.getClass)
private val ConfigFolder = Paths.get("").toFile.getAbsoluteFile private val ConfigFolder = Paths.get("").toFile.getAbsoluteFile
private val ConfigFile = new File(ConfigFolder, "config.properties") private val ConfigFile = new File(ConfigFolder, "config.properties")
private val DatabaseFile = new File(ConfigFolder, "database") private val DatabaseFile = new File(ConfigFolder, "database")
private val KeyFolder = new File(ConfigFolder, "keys") private val KeyFolder = new File(ConfigFolder, "keys")
private val LogInterval = TimeUnit.SECONDS.toMillis(1)
private lazy val logInstance = new Logging()
private lazy val settings = new Settings(ConfigFile) private lazy val settings = new Settings(ConfigFile)
private lazy val crypto = new Crypto(settings, KeyFolder) private lazy val crypto = new Crypto(settings, KeyFolder)
private lazy val database = new Database(DatabaseFile, this) private lazy val database = new Database(DatabaseFile, this)
@ -38,7 +35,6 @@ object Main extends App with CallbackInterface {
private def init(): Unit = { private def init(): Unit = {
ConfigFolder.mkdirs() ConfigFolder.mkdirs()
KeyFolder.mkdirs() KeyFolder.mkdirs()
Log.setLogInstance(logInstance)
sys.addShutdownHook(connectionHandler.stop()) sys.addShutdownHook(connectionHandler.stop())
val parser = new OptionParser[Config]("ensichat") { val parser = new OptionParser[Config]("ensichat") {
@ -64,8 +60,7 @@ object Main extends App with CallbackInterface {
// Keep alive and print logs // Keep alive and print logs
while (true) { while (true) {
Thread.sleep(LogInterval) Thread.sleep(TimeUnit.SECONDS.toMillis(1))
logInstance.dequeue().foreach(System.out.println)
} }
} }
@ -78,9 +73,9 @@ object Main extends App with CallbackInterface {
val address = msg.header.origin val address = msg.header.origin
val name = connectionHandler.getUser(address).name val name = connectionHandler.getUser(address).name
connectionHandler.sendTo(address, new Text("Hello " + name)) connectionHandler.sendTo(address, new Text("Hello " + name))
Log.i(Tag, "Received text: " + text.text) logger.info("Received text: " + text.text)
case _ => case _ =>
Log.i(Tag, "Received msg: " + msg.body) logger.info("Received msg: " + msg.body)
} }
} }

View file

@ -3,13 +3,14 @@ package com.nutomic.ensichat.server
import java.io._ import java.io._
import java.util.Properties import java.util.Properties
import com.nutomic.ensichat.core.interfaces.{Log, SettingsInterface} import com.nutomic.ensichat.core.interfaces.SettingsInterface
import com.typesafe.scalalogging.Logger
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
class Settings(file: File) extends SettingsInterface { class Settings(file: File) extends SettingsInterface {
private val Tag = "Settings" private val logger = Logger(this.getClass)
if (!file.exists()) { if (!file.exists()) {
file.createNewFile() file.createNewFile()
@ -23,7 +24,7 @@ class Settings(file: File) extends SettingsInterface {
p.load(fis) p.load(fis)
fis.close() fis.close()
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to load settings from " + file, e) case e: IOException => logger.warn("Failed to load settings from " + file, e)
} }
p p
} }
@ -35,7 +36,7 @@ class Settings(file: File) extends SettingsInterface {
props.store(fos, "") props.store(fos, "")
fos.close() fos.close()
} catch { } catch {
case e: IOException => Log.w(Tag, "Failed to write preference for key " + key, e) case e: IOException => logger.warn("Failed to write preference for key " + key, e)
} }
} }