diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala index a20aa20dd9..73ada50499 100644 --- a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala @@ -8,7 +8,7 @@ import org.bitcoins.core.protocol.tlv._ import org.bitcoins.dlc.oracle._ import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig import org.bitcoins.keymanager.WalletStorage -import org.bitcoins.server._ +import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute} import ujson._ import scala.util.{Failure, Success} diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala index 4e4ba98fb9..40a01a62f1 100644 --- a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala @@ -1,7 +1,7 @@ package org.bitcoins.oracle.server import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig -import org.bitcoins.server.{BitcoinSRunner, Server} +import org.bitcoins.server.routes.{BitcoinSRunner, Server} import scala.concurrent.Future diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala new file mode 100644 index 0000000000..8566e69270 --- /dev/null +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala @@ -0,0 +1,329 @@ +package org.bitcoins.oracle.server + +import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.LockUnspentOutputParameter +import org.bitcoins.core.api.wallet.CoinSelectionAlgo +import org.bitcoins.core.protocol.BitcoinAddress +import org.bitcoins.core.protocol.tlv._ +import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint} +import org.bitcoins.core.psbt.PSBT +import org.bitcoins.crypto.AesPassword +import ujson._ + +import java.time.Instant +import scala.util.{Failure, Try} + +case class CreateEvent( + label: String, + maturationTime: Instant, + outcomes: Vector[String]) + +object CreateEvent extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[CreateEvent] = { + jsArr.arr.toList match { + case labelJs :: maturationTimeJs :: outcomesJs :: Nil => + Try { + val label = labelJs.str + val maturationTime: Instant = + Instant.ofEpochSecond(maturationTimeJs.num.toLong) + val outcomes = outcomesJs.arr.map(_.str).toVector + + CreateEvent(label, maturationTime, outcomes) + } + case Nil => + Failure( + new IllegalArgumentException("Missing label and outcome arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 2")) + } + } +} + +case class CreateRangedEvent( + eventName: String, + maturationTime: Instant, + start: Int, + stop: Int, + step: Int, + unit: String, + precision: Int) + +object CreateRangedEvent extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[CreateRangedEvent] = { + jsArr.arr.toList match { + case labelJs :: maturationTimeJs :: startJs :: stopJs :: stepJs :: unitJs :: precisionJs :: Nil => + Try { + val label = labelJs.str + val maturationTime: Instant = + Instant.ofEpochSecond(maturationTimeJs.num.toLong) + val start = startJs.num.toInt + val stop = stopJs.num.toInt + val step = stepJs.num.toInt + val unit = unitJs.str + val precision = precisionJs.num.toInt + + CreateRangedEvent(label, + maturationTime, + start, + stop, + step, + unit, + precision) + } + case Nil => + Failure( + new IllegalArgumentException( + "Missing label, maturationTime, start, stop, and step arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 5")) + } + } +} + +case class CreateDigitDecompEvent( + eventName: String, + maturationTime: Instant, + base: Int, + isSigned: Boolean, + numDigits: Int, + unit: String, + precision: Int) + +object CreateDigitDecompEvent extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[CreateDigitDecompEvent] = { + jsArr.arr.toList match { + case labelJs :: maturationTimeJs :: baseJs :: isSignedJs :: numDigitsJs :: unitJs :: precisionJs :: Nil => + Try { + val label = labelJs.str + val maturationTime: Instant = + Instant.ofEpochSecond(maturationTimeJs.num.toLong) + val base = baseJs.num.toInt + val isSigned = isSignedJs.bool + val numDigits = numDigitsJs.num.toInt + val unit = unitJs.str + val precision = precisionJs.num.toInt + + CreateDigitDecompEvent(label, + maturationTime, + base, + isSigned, + numDigits, + unit, + precision) + } + case Nil => + Failure(new IllegalArgumentException( + "Missing label, maturationTime, base, isSigned, and numDigits arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 5")) + } + } +} + +case class SignEvent(oracleEventTLV: OracleEventV0TLV, outcome: String) + +object SignEvent extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[SignEvent] = { + jsArr.arr.toList match { + case tlvJs :: outcomeJs :: Nil => + Try { + val oracleEventTLV = OracleEventV0TLV(tlvJs.str) + val outcome = outcomeJs.str + + SignEvent(oracleEventTLV, outcome) + } + case Nil => + Failure( + new IllegalArgumentException( + "Missing oracle event tlv and outcome arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 2")) + } + } +} + +case class SignForRange(oracleEventTLV: OracleEventV0TLV, num: Long) + +object SignForRange extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[SignForRange] = { + jsArr.arr.toList match { + case tlvJs :: numJs :: Nil => + Try { + val oracleEventTLV = OracleEventV0TLV(tlvJs.str) + val num = numJs match { + case num: Num => num.value + case str: Str => str.value.toDouble + case _: Value => + throw new IllegalArgumentException( + s"Unable to parse $numJs as a number") + } + + SignForRange(oracleEventTLV, num.toLong) + } + case Nil => + Failure( + new IllegalArgumentException( + "Missing oracle event tlv and num arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 2")) + } + } +} + +case class SignDigits(oracleEventTLV: OracleEventV0TLV, num: Long) + +object SignDigits extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[SignDigits] = { + jsArr.arr.toList match { + case tlvJs :: numJs :: Nil => + Try { + val oracleEventTLV = OracleEventV0TLV(tlvJs.str) + val num = numJs match { + case num: Num => num.value + case str: Str => str.value.toDouble + case _: Value => + throw new IllegalArgumentException( + s"Unable to parse $numJs as a number") + } + + SignDigits(oracleEventTLV, num.toLong) + } + case Nil => + Failure( + new IllegalArgumentException( + "Missing oracle event tlv and num arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 2")) + } + } +} + +case class GetEvent(oracleEventTLV: OracleEventV0TLV) + +object GetEvent extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[GetEvent] = { + require(jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + Try { + val oracleEventTLV = OracleEventV0TLV(jsArr.arr.head.str) + + GetEvent(oracleEventTLV) + } + } +} + +case class KeyManagerPassphraseChange( + oldPassword: AesPassword, + newPassword: AesPassword) + +object KeyManagerPassphraseChange extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[KeyManagerPassphraseChange] = { + jsArr.arr.toList match { + case oldPassJs :: newPassJs :: Nil => + Try { + val oldPass = AesPassword.fromString(oldPassJs.str) + val newPass = AesPassword.fromString(newPassJs.str) + + KeyManagerPassphraseChange(oldPass, newPass) + } + case Nil => + Failure( + new IllegalArgumentException( + "Missing old password and new password arguments")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 2")) + } + } +} + +case class KeyManagerPassphraseSet(password: AesPassword) + +object KeyManagerPassphraseSet extends ServerJsonModels { + + def fromJsArr(jsArr: ujson.Arr): Try[KeyManagerPassphraseSet] = { + jsArr.arr.toList match { + case passJs :: Nil => + Try { + val pass = AesPassword.fromString(passJs.str) + + KeyManagerPassphraseSet(pass) + } + case Nil => + Failure(new IllegalArgumentException("Missing password argument")) + case other => + Failure( + new IllegalArgumentException( + s"Bad number of arguments: ${other.length}. Expected: 1")) + } + } +} + +trait ServerJsonModels { + + def jsToBitcoinAddress(js: Value): BitcoinAddress = { + try { + BitcoinAddress.fromString(js.str) + } catch { + case _: IllegalArgumentException => + throw Value.InvalidData(js, "Expected a valid address") + } + } + + def jsToPSBTSeq(js: Value): Seq[PSBT] = { + js.arr.foldLeft(Seq.empty[PSBT])((seq, psbt) => seq :+ jsToPSBT(psbt)) + } + + def jsToPSBT(js: Value): PSBT = PSBT.fromString(js.str) + + def jsToTransactionOutPointSeq(js: Value): Seq[TransactionOutPoint] = { + js.arr.foldLeft(Seq.empty[TransactionOutPoint])((seq, outPoint) => + seq :+ jsToTransactionOutPoint(outPoint)) + } + + def jsToTransactionOutPoint(js: Value): TransactionOutPoint = + TransactionOutPoint(js.str) + + def jsToLockUnspentOutputParameter(js: Value): LockUnspentOutputParameter = + LockUnspentOutputParameter.fromJson(js) + + def jsToLockUnspentOutputParameters( + js: Value): Seq[LockUnspentOutputParameter] = { + js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) => + seq :+ jsToLockUnspentOutputParameter(outPoint)) + } + + def jsToCoinSelectionAlgo(js: Value): CoinSelectionAlgo = + CoinSelectionAlgo + .fromString(js.str) + + def jsToTx(js: Value): Transaction = Transaction.fromHex(js.str) + + def nullToOpt(value: Value): Option[Value] = + value match { + case Null => None + case Arr(arr) if arr.isEmpty => None + case Arr(arr) if arr.size == 1 => Some(arr.head) + case _: Value => Some(value) + } +} diff --git a/app/server/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala b/app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala similarity index 100% rename from app/server/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala rename to app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoinSRunner.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala similarity index 99% rename from app/server/src/main/scala/org/bitcoins/server/BitcoinSRunner.scala rename to app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala index 1254ffcbb5..d7b4cbf23e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSRunner.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala @@ -1,4 +1,4 @@ -package org.bitcoins.server +package org.bitcoins.server.routes import akka.actor.ActorSystem import com.typesafe.config.{Config, ConfigFactory} diff --git a/app/server/src/main/scala/org/bitcoins/server/HttpError.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala similarity index 89% rename from app/server/src/main/scala/org/bitcoins/server/HttpError.scala rename to app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala index 36e4c299a9..3e33f1bfc9 100644 --- a/app/server/src/main/scala/org/bitcoins/server/HttpError.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala @@ -1,4 +1,4 @@ -package org.bitcoins.server +package org.bitcoins.server.routes /** HTTP errors our server knows how to handle. * These gets picked up by the exceptions handler diff --git a/app/server/src/main/scala/org/bitcoins/server/HttpLogger.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpLogger.scala similarity index 79% rename from app/server/src/main/scala/org/bitcoins/server/HttpLogger.scala rename to app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpLogger.scala index 796542e1cb..dde816f72d 100644 --- a/app/server/src/main/scala/org/bitcoins/server/HttpLogger.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpLogger.scala @@ -1,4 +1,4 @@ -package org.bitcoins.server +package org.bitcoins.server.routes import grizzled.slf4j.Logging diff --git a/app/server/src/main/scala/org/bitcoins/server/Server.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala similarity index 98% rename from app/server/src/main/scala/org/bitcoins/server/Server.scala rename to app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala index 224d28a68e..6da5a5fe52 100644 --- a/app/server/src/main/scala/org/bitcoins/server/Server.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala @@ -1,4 +1,4 @@ -package org.bitcoins.server +package org.bitcoins.server.routes import akka.actor.ActorSystem import akka.event.Logging @@ -59,7 +59,7 @@ case class Server( } } - val route = + val route: Route = // TODO implement better logging DebuggingDirectives.logRequestResult("http-rpc-server", Logging.InfoLevel) { withErrorHandling { diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerCommand.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerCommand.scala new file mode 100644 index 0000000000..858fd08da8 --- /dev/null +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerCommand.scala @@ -0,0 +1,26 @@ +package org.bitcoins.server.routes + +import ujson._ +import upickle.default._ + +// TODO ID? +case class ServerCommand(method: String, params: ujson.Arr) + +object ServerCommand { + + implicit val rw: ReadWriter[ServerCommand] = + readwriter[ujson.Value].bimap[ServerCommand]( + cmd => { + if (cmd.params.arr.isEmpty) + Obj("method" -> Str(cmd.method)) + else Obj("method" -> Str(cmd.method), "params" -> cmd.params) + }, + json => { + val obj = json.obj + val method = obj("method").str + if (obj.contains("params")) + ServerCommand(method, obj("params").arr) + else ServerCommand(method, Arr()) + } + ) +} diff --git a/app/server/src/main/scala/org/bitcoins/server/ServerRoute.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerRoute.scala similarity index 79% rename from app/server/src/main/scala/org/bitcoins/server/ServerRoute.scala rename to app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerRoute.scala index 78cc3d6898..2fa1f7b765 100644 --- a/app/server/src/main/scala/org/bitcoins/server/ServerRoute.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/ServerRoute.scala @@ -1,4 +1,4 @@ -package org.bitcoins.server +package org.bitcoins.server.routes import akka.http.scaladsl.server.StandardRoute diff --git a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala index 83bdbc8825..0e4e9ce620 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala @@ -35,6 +35,7 @@ import org.bitcoins.crypto.{ } import org.bitcoins.node.Node import org.bitcoins.server.BitcoinSAppConfig.implicitToWalletConf +import org.bitcoins.server.routes.ServerCommand import org.bitcoins.testkit.BitcoinSTestAppConfig import org.bitcoins.wallet.MockWalletApi import org.scalamock.scalatest.MockFactory diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala index 7663ea2f62..f1cf6bed63 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala @@ -3,6 +3,7 @@ package org.bitcoins.server import akka.actor.ActorSystem import akka.dispatch.Dispatchers import akka.http.scaladsl.Http +import grizzled.slf4j.Logging import org.bitcoins.chain.blockchain.ChainHandler import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.chain.models._ @@ -18,13 +19,15 @@ import org.bitcoins.feeprovider._ import org.bitcoins.node._ import org.bitcoins.node.config.NodeAppConfig import org.bitcoins.node.models.Peer +import org.bitcoins.server.routes.{BitcoinSRunner, Server} import org.bitcoins.wallet.Wallet import org.bitcoins.wallet.config.WalletAppConfig import scala.concurrent.{ExecutionContext, Future, Promise} class BitcoinSServerMain(override val args: Array[String]) - extends BitcoinSRunner { + extends BitcoinSRunner + with Logging { override val actorSystemName = "bitcoin-s-server" @@ -288,26 +291,24 @@ class BitcoinSServerMain(override val args: Array[String]) val server = { rpcPortOpt match { case Some(rpcport) => - Server.apply(conf = nodeConf, - handlers = - Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), - rpcbindOpt = rpcbindOpt, - rpcport = rpcport) + Server(conf = nodeConf, + handlers = + Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), + rpcbindOpt = rpcbindOpt, + rpcport = rpcport) case None => conf.rpcPortOpt match { case Some(rpcport) => - Server.apply( - conf = nodeConf, - handlers = - Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), - rpcbindOpt = rpcbindOpt, - rpcport = rpcport) + Server(conf = nodeConf, + handlers = + Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), + rpcbindOpt = rpcbindOpt, + rpcport = rpcport) case None => - Server.apply( - conf = nodeConf, - handlers = - Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), - rpcbindOpt = rpcbindOpt) + Server(conf = nodeConf, + handlers = + Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes), + rpcbindOpt = rpcbindOpt) } } } diff --git a/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala index cfddb661ab..2399d5f36d 100644 --- a/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala @@ -7,6 +7,7 @@ import org.bitcoins.commons.jsonmodels.BitcoinSServerInfo import org.bitcoins.commons.serializers.Picklers._ import org.bitcoins.core.api.chain.ChainApi import org.bitcoins.core.config.BitcoinNetwork +import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute} import scodec.bits.ByteVector import ujson._ diff --git a/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala index d8f31c883f..41bceeb5e4 100644 --- a/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala @@ -5,6 +5,7 @@ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server._ import org.bitcoins.commons.jsonmodels.{SerializedPSBT, SerializedTransaction} import org.bitcoins.core.api.core.CoreApi +import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute} import ujson._ import scala.collection.mutable diff --git a/app/server/src/main/scala/org/bitcoins/server/NodeRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/NodeRoutes.scala index 80d2bf3363..ddb224228e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/NodeRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/NodeRoutes.scala @@ -7,6 +7,7 @@ import org.bitcoins.commons.serializers.Picklers._ import org.bitcoins.core.api.node.NodeApi import org.bitcoins.node.Node import org.bitcoins.rpc.client.common.BitcoindRpcClient +import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute} import scala.concurrent.duration.DurationInt import scala.util.{Failure, Success} diff --git a/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala b/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala index 59429a5abd..f4f5a44cf0 100644 --- a/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala +++ b/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala @@ -1,12 +1,10 @@ package org.bitcoins.server -import java.time.Instant import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.LockUnspentOutputParameter import org.bitcoins.core.api.wallet.CoinSelectionAlgo import org.bitcoins.core.crypto._ import org.bitcoins.core.currency.{Bitcoins, Satoshis} import org.bitcoins.core.protocol.BlockStamp.BlockHeight -import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint} import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp} import org.bitcoins.core.psbt.PSBT @@ -14,32 +12,9 @@ import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.utxo.AddressLabelTag import org.bitcoins.crypto.{AesPassword, DoubleSha256DigestBE} import ujson._ -import upickle.default._ import scala.util.{Failure, Try} -// TODO ID? -case class ServerCommand(method: String, params: ujson.Arr) - -object ServerCommand { - - implicit val rw: ReadWriter[ServerCommand] = - readwriter[ujson.Value].bimap[ServerCommand]( - cmd => { - if (cmd.params.arr.isEmpty) - Obj("method" -> Str(cmd.method)) - else Obj("method" -> Str(cmd.method), "params" -> cmd.params) - }, - json => { - val obj = json.obj - val method = obj("method").str - if (obj.contains("params")) - ServerCommand(method, obj("params").arr) - else ServerCommand(method, Arr()) - } - ) -} - case class GetNewAddress(labelOpt: Option[AddressLabelTag]) object GetNewAddress extends ServerJsonModels { @@ -741,226 +716,6 @@ object BumpFee extends ServerJsonModels { } } -// Oracle Models - -case class CreateEvent( - label: String, - maturationTime: Instant, - outcomes: Vector[String]) - -object CreateEvent extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[CreateEvent] = { - jsArr.arr.toList match { - case labelJs :: maturationTimeJs :: outcomesJs :: Nil => - Try { - val label = labelJs.str - val maturationTime: Instant = - Instant.ofEpochSecond(maturationTimeJs.num.toLong) - val outcomes = outcomesJs.arr.map(_.str).toVector - - CreateEvent(label, maturationTime, outcomes) - } - case Nil => - Failure( - new IllegalArgumentException("Missing label and outcome arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) - } - } -} - -case class CreateRangedEvent( - eventName: String, - maturationTime: Instant, - start: Int, - stop: Int, - step: Int, - unit: String, - precision: Int) - -object CreateRangedEvent extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[CreateRangedEvent] = { - jsArr.arr.toList match { - case labelJs :: maturationTimeJs :: startJs :: stopJs :: stepJs :: unitJs :: precisionJs :: Nil => - Try { - val label = labelJs.str - val maturationTime: Instant = - Instant.ofEpochSecond(maturationTimeJs.num.toLong) - val start = startJs.num.toInt - val stop = stopJs.num.toInt - val step = stepJs.num.toInt - val unit = unitJs.str - val precision = precisionJs.num.toInt - - CreateRangedEvent(label, - maturationTime, - start, - stop, - step, - unit, - precision) - } - case Nil => - Failure( - new IllegalArgumentException( - "Missing label, maturationTime, start, stop, and step arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 5")) - } - } -} - -case class CreateDigitDecompEvent( - eventName: String, - maturationTime: Instant, - base: Int, - isSigned: Boolean, - numDigits: Int, - unit: String, - precision: Int) - -object CreateDigitDecompEvent extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[CreateDigitDecompEvent] = { - jsArr.arr.toList match { - case labelJs :: maturationTimeJs :: baseJs :: isSignedJs :: numDigitsJs :: unitJs :: precisionJs :: Nil => - Try { - val label = labelJs.str - val maturationTime: Instant = - Instant.ofEpochSecond(maturationTimeJs.num.toLong) - val base = baseJs.num.toInt - val isSigned = isSignedJs.bool - val numDigits = numDigitsJs.num.toInt - val unit = unitJs.str - val precision = precisionJs.num.toInt - - CreateDigitDecompEvent(label, - maturationTime, - base, - isSigned, - numDigits, - unit, - precision) - } - case Nil => - Failure(new IllegalArgumentException( - "Missing label, maturationTime, base, isSigned, and numDigits arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 5")) - } - } -} - -case class SignEvent(oracleEventTLV: OracleEventV0TLV, outcome: String) - -object SignEvent extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[SignEvent] = { - jsArr.arr.toList match { - case tlvJs :: outcomeJs :: Nil => - Try { - val oracleEventTLV = OracleEventV0TLV(tlvJs.str) - val outcome = outcomeJs.str - - SignEvent(oracleEventTLV, outcome) - } - case Nil => - Failure( - new IllegalArgumentException( - "Missing oracle event tlv and outcome arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) - } - } -} - -case class SignForRange(oracleEventTLV: OracleEventV0TLV, num: Long) - -object SignForRange extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[SignForRange] = { - jsArr.arr.toList match { - case tlvJs :: numJs :: Nil => - Try { - val oracleEventTLV = OracleEventV0TLV(tlvJs.str) - val num = numJs match { - case num: Num => num.value - case str: Str => str.value.toDouble - case _: Value => - throw new IllegalArgumentException( - s"Unable to parse $numJs as a number") - } - - SignForRange(oracleEventTLV, num.toLong) - } - case Nil => - Failure( - new IllegalArgumentException( - "Missing oracle event tlv and num arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) - } - } -} - -case class SignDigits(oracleEventTLV: OracleEventV0TLV, num: Long) - -object SignDigits extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[SignDigits] = { - jsArr.arr.toList match { - case tlvJs :: numJs :: Nil => - Try { - val oracleEventTLV = OracleEventV0TLV(tlvJs.str) - val num = numJs match { - case num: Num => num.value - case str: Str => str.value.toDouble - case _: Value => - throw new IllegalArgumentException( - s"Unable to parse $numJs as a number") - } - - SignDigits(oracleEventTLV, num.toLong) - } - case Nil => - Failure( - new IllegalArgumentException( - "Missing oracle event tlv and num arguments")) - case other => - Failure( - new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) - } - } -} - -case class GetEvent(oracleEventTLV: OracleEventV0TLV) - -object GetEvent extends ServerJsonModels { - - def fromJsArr(jsArr: ujson.Arr): Try[GetEvent] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") - Try { - val oracleEventTLV = OracleEventV0TLV(jsArr.arr.head.str) - - GetEvent(oracleEventTLV) - } - } -} - trait ServerJsonModels { def jsToBitcoinAddress(js: Value): BitcoinAddress = { diff --git a/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala index 83ef4b612c..2eb2168b1b 100644 --- a/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala @@ -12,6 +12,7 @@ import org.bitcoins.core.wallet.utxo.{AddressLabelTagType, TxoState} import org.bitcoins.crypto.NetworkElement import org.bitcoins.keymanager._ import org.bitcoins.keymanager.config.KeyManagerAppConfig +import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute} import org.bitcoins.wallet.config.WalletAppConfig import ujson._ diff --git a/build.sbt b/build.sbt index 44feaac350..7ebc3fb2c8 100644 --- a/build.sbt +++ b/build.sbt @@ -80,7 +80,8 @@ lazy val `bitcoin-s` = project appCommonsTest, testkit, zmq, - oracleServer + oracleServer, + serverRoutes ) .dependsOn( secp256k1jni, @@ -117,7 +118,8 @@ lazy val `bitcoin-s` = project appCommonsTest, testkit, zmq, - oracleServer + oracleServer, + serverRoutes ) .settings(CommonSettings.settings: _*) // unidoc aggregates Scaladocs for all subprojects into one big doc @@ -281,13 +283,20 @@ lazy val oracleServer = project .settings(CommonSettings.prodSettings: _*) .dependsOn( dlcOracle, - appServer + serverRoutes ) +lazy val serverRoutes = project + .in(file("app/server-routes")) + .settings(CommonSettings.prodSettings: _*) + .settings(libraryDependencies ++= Deps.serverRoutes) + .dependsOn(appCommons, dbCommons) + lazy val appServer = project .in(file("app/server")) .settings(CommonSettings.prodSettings: _*) .dependsOn( + serverRoutes, appCommons, node, chain, diff --git a/project/Deps.scala b/project/Deps.scala index 4d440e9298..6b6c71e254 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -430,4 +430,11 @@ object Deps { Compile.newMicroJson, Compile.logback ) + + val serverRoutes = List( + Compile.akkaHttp, + Compile.akkaActor, + Compile.akkaSlf4j, + Compile.akkaStream + ) }