bitcoin-atm
bitcoin atm for pyc inc.
git clone https://9o.is/git/bitcoin-atm.git
commit 8e1794308bcbacbde20bfd5ab9817556ce7746ef parent f085f46b610154584161adedb4af14313169d7cd Author: Jul <jul@9o.is> Date: Fri, 1 Aug 2014 18:57:34 -0700 working validate address, bitcoin balance... no failover Diffstat:
18 files changed, 178 insertions(+), 135 deletions(-)
diff --git a/project/Build.scala b/project/Build.scala @@ -13,15 +13,15 @@ object LiftProjectBuild extends Build { "net.liftmodules" %% ("extras_"+Ver.lift_edition) % "0.4-SNAPSHOT", "com.typesafe.akka" %% "akka-actor" % "2.3.3", "com.typesafe.akka" %% "akka-agent" % "2.3.3", - "com.typesafe.akka" %% "akka-slf4j" % "2.3.3", + //"com.typesafe.akka" %% "akka-slf4j" % "2.3.3", "net.databinder.dispatch" %% "dispatch-core" % "0.11.1", "net.databinder.dispatch" %% "dispatch-lift-json" % "0.11.0", "com.markgoldenstein" %% "bitcoin-akka" % "0.1-SNAPSHOT", "com.palletops" % "java-websocket" % "1.3.1-SNAPSHOT", - "io.kamon" %% "kamon-core" % "0.3.2", - "io.kamon" %% "kamon-log-reporter" % "0.3.2", + //"io.kamon" %% "kamon-core" % "0.3.2", + //"io.kamon" %% "kamon-log-reporter" % "0.3.2", //"io.kamon" %% "kamon-system-metrics" % "0.3.2", - "io.kamon" %% "kamon-statsd" % "0.3.2", + //"io.kamon" %% "kamon-statsd" % "0.3.2", "org.eclipse.jetty" % "jetty-webapp" % Ver.jetty % "container", "ch.qos.logback" % "logback-classic" % "1.0.13", "org.scalatest" %% "scalatest" % "1.9.2" % "test" diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf @@ -16,8 +16,8 @@ blockchain { } akka { - extensions = ["kamon.statsd.StatsD", "kamon.metric.Metrics"] - loglevel = "DEBUG" + #extensions = ["kamon.statsd.StatsD", "kamon.metric.Metrics"] + loglevel = "INFO" log-dead-letters = off } @@ -43,4 +43,31 @@ kamon { trace { ask-pattern-tracing = true } + + weaver { + verbose = false + debug = false + showWeaveInfo = false + showWarn = false + } + + statsd { + + hostname = "54.88.126.106" + port = 8125 + flush-interval = 1 second + max-packet-size = 1024 bytes + report-system-metrics = true + + + includes { + actor = [ "*" ] + trace = [ "*" ] + dispatcher = [ "*" ] + } + + simple-metric-key-generator { + application = "chimera" + } + } } \ No newline at end of file diff --git a/src/main/resources/default.logback.xml b/src/main/resources/default.logback.xml @@ -1,18 +1,32 @@ <?xml version="1.0" encoding="UTF-8"?> -<configuration scan="true"> +<configuration> - <conversionRule + <!-- <conversionRule conversionWord="traceToken" - converterClass="kamon.trace.logging.LogbackTraceTokenConverter"/> + converterClass="kamon.trace.logging.LogbackTraceTokenConverter"/> --> - <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> - <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> - <pattern>[%level] %date{HH:mm:ss.SSS} %-5level [%traceToken][%X{akkaSource}] %logger{36} - %msg%n%nopex</pattern> - </encoder> - </appender> - - <root level="debug"> - <appender-ref ref="STDOUT" /> - </root> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> + <!-- <pattern>[%level] %date{HH:mm:ss.SSS} %-5level [%traceToken][%X{akkaSource}] %logger{36} - %msg%n%nopex</pattern> --> + <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="FILE" class="ch.qos.logback.core.FileAppender"> + <file>console.devmode.log</file> + <append>true</append> + <encoder> + <pattern>[%-5level] %-4relative [%thread] %logger{35} - %msg%n</pattern> + </encoder> + </appender> + + + + <logger name="inc.pyc" level="info" /> + + <root level="warn"> + <appender-ref ref="STDOUT" /> + </root> + </configuration> \ No newline at end of file diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf @@ -1,25 +0,0 @@ -# ==================================== # -# Kamon-StatsD Reference Configuration # -# ==================================== # - -kamon { - statsd { - - hostname = "54.88.126.106" - port = 8125 - flush-interval = 1 second - max-packet-size = 1024 bytes - report-system-metrics = true - - - includes { - actor = [ "*" ] - trace = [ "*" ] - dispatcher = [ "*" ] - } - - simple-metric-key-generator { - application = "chimera" - } - } -} -\ No newline at end of file diff --git a/src/main/scala/bootstrap/liftweb/Boot.scala b/src/main/scala/bootstrap/liftweb/Boot.scala @@ -12,7 +12,8 @@ import Loc._ import inc.pyc.chimera._ import config._ import bitcoin._ - +import PriceTicker.commands._ +import Wallet.commands._ /** * A class that's instantiated early and run. It allows the application @@ -63,5 +64,9 @@ class Boot extends Loggable { BitcoinServices.system.shutdown() Lycia.system.shutdown() } + + // Initialize actors + PriceTicker ! Tick + Wallet ! InitBalance } } diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/PriceTicker.scala b/src/main/scala/inc/pyc/chimera/bitcoin/PriceTicker.scala @@ -71,22 +71,16 @@ class PriceTicker extends Actor with ActorLogging { /** The current service to use to check price. */ - private var service: Option[ActorRef] = None + private var service: ActorRef = createServiceActor(Lycia.servicePriceTicker) - override def preStart(): Unit = { - service = Some(createServiceActor(Lycia.servicePriceTicker)) - service foreach { - context.watch(_) - _ ! Tick - } - } + context.watch(service) /** Price per bitcoin */ private var price: String = "0.00" def receive = { case Tick => - service foreach { _ ! Tick } + service ! Tick case GetPrice => sender ! Price(price) @@ -99,12 +93,10 @@ class PriceTicker extends Actor with ActorLogging { bus.publish(EventUpdate(topics.newPrice, Price(price))) case ChangeBitcoinService(provider) => - service foreach { - context.unwatch(_) - context.stop(_) - } - service = Some(createServiceActor(provider)) - service foreach { context.watch(_) } + context.unwatch(service) + context.stop(service) + service = createServiceActor(provider) + context.watch(service) case _ => log.warning("Received Unknown Message") diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/Wallet.scala b/src/main/scala/inc/pyc/chimera/bitcoin/Wallet.scala @@ -11,6 +11,7 @@ import akka.pattern.{ask, pipe} import BitcoinServices.system.dispatcher import scala.concurrent._, duration._ import net.liftweb.util.Helpers.tryo +import BitcoinJsonRPC._ object Wallet { import BitcoinServices._ @@ -32,7 +33,7 @@ object Wallet { val newBalance = "newBalance" } - object commands extends BitcoinJsonRPC { + object commands { /** * Balance remaining in bitcoin wallet. */ @@ -42,6 +43,11 @@ object Wallet { * Command to send a broadcast of the balance. */ case object GossipBalance + + /** + * Initializes the balance in wallet + */ + case object InitBalance } import commands._ @@ -64,16 +70,15 @@ class Wallet extends Actor with ActorLogging { context.watch(service) - override def preStart(): Unit = { - getBalance().map(newBalance => tryo { - balance = newBalance.toDouble - }) - } - /** Balance remaining in the wallet */ private var balance: Double = 0 def receive = { + case InitBalance => + getBalance().map(newBalance => tryo { + balance = newBalance.toDouble + }) + case GetBalance => sender ! Balance(balance) diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/service/BitcoinPriceTicker.scala b/src/main/scala/inc/pyc/chimera/bitcoin/service/BitcoinPriceTicker.scala @@ -24,9 +24,10 @@ trait HttpBitcoinPriceTicker extends HttpBitcoinService with BitcoinPriceTicker */ protected def buyPrice: String - def priceTicker: Receive = { + val priceTicker: Receive = { case Tick => val price = formatPrice(buyPrice) + log.info("New Price: {}", price) sender ! Price(price) } diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/service/BitcoinWallet.scala b/src/main/scala/inc/pyc/chimera/bitcoin/service/BitcoinWallet.scala @@ -11,13 +11,15 @@ import BitcoinServices.system.dispatcher import akka.util.Timeout import com.typesafe.config.{Config, ConfigFactory} import akka.actor._ +import JsonRPC._ +import BitcoinJsonRPC._ /** * Actor to handle bitcoin wallet communications with JSON-RPC. */ -sealed trait BitcoinWallet extends BitcoinServiceActor with BitcoinJsonRPC { +sealed trait BitcoinWallet extends BitcoinServiceActor { this: Actor with ActorLogging => - + /** Wallet configuration */ protected val config: Config protected val walletUri: String @@ -35,16 +37,16 @@ sealed trait BitcoinWallet extends BitcoinServiceActor with BitcoinJsonRPC { * Checks wallet json response. Throws exception if * response is invalid, else it logs the response. */ - protected def checkWalletResponse(json: JsonResponse) { + protected def checkWalletResponse(json: JsonResponse, method: String = "") { json.either.left.map { case err => - new RuntimeException("Wallet Command Failed: " + err) + new RuntimeException("Wallet Command '"+method+"' Failed: " + err) } json.either.right.map { case r => implicit val formats = DefaultFormats - log.info("Wallet Command Success:\n{}", pretty(render(Extraction.decompose(r)))) + log.info("\nWallet Command '{}' Success:\n{}", method, pretty(render(Extraction.decompose(r)))) } } } @@ -59,42 +61,42 @@ trait HttpBitcoinWallet extends HttpBitcoinService with BitcoinWallet { import dispatch._ - def bitcoinWallet: Receive = { + val bitcoinWallet: Receive = { case CreateRawTransaction(inputs, receivers) => val json = JsonMessage.createRawTransaction(inputs, receivers) - requestExtract(json, _.extract[String]) + sender ! requestExtract(json, _.extract[String]) case GetBalance => val json = JsonMessage.getBalance - requestExtract(json, _.extract[String]) + sender ! requestExtract(json, _.extract[String]) case GetNewAddress => val json = JsonMessage.getNewAddress - requestExtract(json, _.extract[String]) + sender ! requestExtract(json, _.extract[String]) case GetRawTransaction(transactionHash) => val json = JsonMessage.getRawTransaction(transactionHash) - requestExtract(json, _.extract[RawTransaction]) + sender ! requestExtract(json, _.extract[RawTransaction]) case ListUnspentTransactions(minConfirmations, maxConfirmations) => val json = JsonMessage.listUnspentTransactions(minConfirmations, maxConfirmations) - requestExtract(json, _.extract[List[UnspentTransaction]]) + sender ! requestExtract(json, _.extract[List[UnspentTransaction]]) case SendRawTransaction(signedTransaction) => val json = JsonMessage.sendRawTransaction(signedTransaction) - requestExtract(json, _.extract[String]) + sender ! requestExtract(json, _.extract[String]) case SignRawTransaction(transaction) => val json = JsonMessage.signRawTransaction(transaction) - requestExtract(json, _.extract[SignedTransaction]) + sender ! requestExtract(json, _.extract[SignedTransaction]) case WalletPassPhrase(walletPass, timeout) => val json = JsonMessage.walletPassPhrase(walletPass, timeout) - request(post(json)) + request(post(json)) // fire & forget case ValidateAddress(address) => val json = JsonMessage.validateAddress(address) - requestExtract(json, _.extract[AddressValidation]) + sender ! requestExtract(json, _.extract[AddressValidation]) } @@ -105,7 +107,7 @@ trait HttpBitcoinWallet extends HttpBitcoinService with BitcoinWallet { /* All-in-one func: makes request, extracts response, extracts data. */ private def requestExtract[T](req: JsonRequest, extractor: JValue => T): T = { val json = request(post(req)).extract[JsonResponse] - checkWalletResponse(json) + checkWalletResponse(json, req.method) val result = json.result.getOrElse(JNull) extractor(result) } @@ -127,34 +129,34 @@ trait WsBitcoinWallet extends WsBitcoinService with BitcoinWallet { protected def handleNotification: Receive - def bitcoinWallet: Receive = { + val bitcoinWallet: Receive = { case CreateRawTransaction(inputs, receivers) => val json = JsonMessage.createRawTransaction(inputs, receivers) - requestExtract(json.id, json, _.extract[String]) + requestExtract(json.id, json, _.extract[String], "CreateRawTransaction" :: Nil) case GetBalance => val json = JsonMessage.getBalance - requestExtract(json.id, json, _.extract[String]) + requestExtract(json.id, json, _.extract[String], "GetBalance" :: Nil) case GetNewAddress => val json = JsonMessage.getNewAddress - requestExtract(json.id, json, _.extract[String]) + requestExtract(json.id, json, _.extract[String], "GetNewAddress" :: Nil) case GetRawTransaction(transactionHash) => val json = JsonMessage.getRawTransaction(transactionHash) - requestExtract(json.id, json, _.extract[RawTransaction]) + requestExtract(json.id, json, _.extract[RawTransaction], "GetRawTransaction" :: Nil) case ListUnspentTransactions(minConfirmations, maxConfirmations) => val json = JsonMessage.listUnspentTransactions(minConfirmations, maxConfirmations) - requestExtract(json.id, json, _.extract[List[UnspentTransaction]]) + requestExtract(json.id, json, _.extract[List[UnspentTransaction]], "ListUnspentTransactions" :: Nil) case SendRawTransaction(signedTransaction) => val json = JsonMessage.sendRawTransaction(signedTransaction) - requestExtract(json.id, json, _.extract[String]) + requestExtract(json.id, json, _.extract[String], "SendRawTransaction" :: Nil) case SignRawTransaction(transaction) => val json = JsonMessage.signRawTransaction(transaction) - requestExtract(json.id, json, _.extract[SignedTransaction]) + requestExtract(json.id, json, _.extract[SignedTransaction], "SignRawTransaction" :: Nil) case WalletPassPhrase(walletPass, timeout) => val json = JsonMessage.walletPassPhrase(walletPass, timeout) @@ -162,12 +164,12 @@ trait WsBitcoinWallet extends WsBitcoinService with BitcoinWallet { case ValidateAddress(address) => val json = JsonMessage.validateAddress(address) - requestExtract(json.id, json, _.extract[AddressValidation]) + requestExtract(json.id, json, _.extract[AddressValidation], "ValidateAddress" :: Nil) - case json @ JsonResponse(resultOption, errorOption, id) => + case json @ JsonResponse(jsonrpc, id, errorOption, resultOption) => requests.remove(id).foreach(req => { - val (p, extract) = req - checkWalletResponse(json) + val (p, extract, info) = req + checkWalletResponse(json, info.head) json.either.left.map(p tryFailure new RuntimeException(_)) json.either.right.map(p trySuccess extract(_)) }) diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/service/BlockChain.scala b/src/main/scala/inc/pyc/chimera/bitcoin/service/BlockChain.scala @@ -17,7 +17,7 @@ class BlockChain extends Actor this: Actor with ActorLogging => - def receive = bitcoinWallet //orElse priceTicker + def receive = bitcoinWallet orElse priceTicker protected val config: Config = ConfigFactory.load().getConfig("blockchain") protected val walletUri: String = config.getString("wallet-uri") diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/service/JsonRPC.scala b/src/main/scala/inc/pyc/chimera/bitcoin/service/JsonRPC.scala @@ -11,13 +11,13 @@ sealed trait JsonMessage * For more information, visit * http://json-rpc.org/wiki/specification */ -sealed trait JsonRPC { +object JsonRPC { implicit val formats = json.DefaultFormats // JSON-RPC MESSAGES case class JsonNotification(jsonrpc: String, method: String, params: JArray) extends JsonMessage case class JsonRequest(jsonrpc: String, id: String, method: String, params: JArray) extends JsonMessage - case class JsonResponse(result: Option[JValue], error: Option[JValue], id: String) extends JsonMessage { + case class JsonResponse(jsonrpc: String, id: String, error: Option[JValue], result: Option[JValue]) extends JsonMessage { def either: Either[String, JValue] = (result, error) match { case (Some(result), _) => Right(result) @@ -26,8 +26,14 @@ sealed trait JsonRPC { } } - // JsonMessage to JValue implicits - implicit def jsonRequestToJValue(m: JsonRequest): JValue = m.extract[JsonRequest] + // JsonMessage to JValue implicit + implicit def jsonRequestToJValue(r: JsonRequest): JValue = { + JObject(List( + JField("jsonrpc", JString(r.jsonrpc)), + JField("id", JString(r.id)), + JField("method", JString(r.method)), + JField("params", r.params))) + } } trait WalletMessage @@ -37,7 +43,8 @@ trait NotificationMessage extends WalletMessage * For more information, visit * https://en.bitcoin.it/wiki/API_reference_(JSON-RPC) */ -trait BitcoinJsonRPC extends JsonRPC { +object BitcoinJsonRPC { + import JsonRPC._ // BITCOIN TRANSACTIONS case class RawTransaction(hex: String, txid: String, version: BigDecimal, locktime: BigDecimal, vin: Seq[VIn], vout: Seq[VOut]) diff --git a/src/main/scala/inc/pyc/chimera/bitcoin/service/WsBitcoinService.scala b/src/main/scala/inc/pyc/chimera/bitcoin/service/WsBitcoinService.scala @@ -47,7 +47,7 @@ trait WsBitcoinService extends BitcoinServiceActor { * Maps request IDs to the corresponding response promises * and a function that converts the JSON RPC response to the final actor response. */ - protected val requests = mutable.HashMap.empty[String, (Promise[Any], JValue => _)] + protected val requests = mutable.HashMap.empty[String, (Promise[Any], JValue => _, List[String])] /** * Executes on websocket initial connection. @@ -65,11 +65,11 @@ trait WsBitcoinService extends BitcoinServiceActor { * Request and extract promised json response. * Note: Must be an actor making the request to receive response. */ - protected def requestExtract[T](id: String, req: JValue, extractor: JValue => T): Unit = { + protected def requestExtract[T](id: String, req: JValue, extractor: JValue => T, info: List[String] = Nil): Unit = { val p = Promise[Any]() val f = p.future - requests += id -> (p, extractor) + requests += id -> (p, extractor, info) request(req) context.system.scheduler.scheduleOnce(timeout.duration) { @@ -104,7 +104,7 @@ trait WsBitcoinService extends BitcoinServiceActor { /** * Receive when connected. */ - def websocket: Receive = { + val websocket: Receive = { case RemoveWsRequest(id) => requests -= id diff --git a/src/main/scala/inc/pyc/chimera/snippet/PriceTickerComet.scala b/src/main/scala/inc/pyc/chimera/snippet/PriceTickerComet.scala @@ -11,7 +11,7 @@ import net.liftweb._ import http._ import json.JsonAST._ import akka.actor.ActorSystem -import kamon.trace.TraceRecorder +//import kamon.trace.TraceRecorder /** * Snippet to update the price ticker on screen. @@ -26,7 +26,7 @@ class PriceTickerComet extends EventRegister { (PriceTicker.topics.newPrice, initPriceTicker)) def initPriceTicker() = - TraceRecorder.withNewTraceContext("priceticker") { + /*TraceRecorder.withNewTraceContext("priceticker")*/ { PriceTicker ! GossipPrice } @@ -39,19 +39,19 @@ class BitcoinAddressScanner extends RoundTripSnippet { def roundTrips: List[RoundTripInfo] = List("submitAddress" -> submitAddress _) - def submitAddress(json: JValue): JValue = + def submitAddress(json: JValue): Message = for (JString(address) <- json) yield for { validation <- Wallet.validateAddress(address) } yield { + // TODO check website database if address exists // TODO check if address is owned by a user // TODO set LocalTransaction - if (validation.isvalid) - Message("success"): JValue - else - Message("failure"): JValue + + if (validation.isvalid) Message("success") + else Message("failure") } diff --git a/src/main/scala/inc/pyc/chimera/snippet/RoundTripSnippet.scala b/src/main/scala/inc/pyc/chimera/snippet/RoundTripSnippet.scala @@ -15,9 +15,9 @@ import dispatch._, Defaults._ * Shortcut to build lift roundtrips using the pattern 'window.classname' javascript object. */ trait RoundTripSnippet { - implicit def boxedJValueToJValue(in: Box[JValue]): JValue = in openOr JNull - implicit def listJValueToJValue(in: List[JValue]): JValue = in.headOption.getOrElse(JNull) - implicit def listFutureJValueToJValue(in: List[Future[JValue]]): JValue = in.headOption.getOrElse(Future(JNull))() + implicit def boxedMessageToMessage(in: Box[Message]): Message = in openOr Message.fail + implicit def listMessageToMessage(in: List[Message]): Message = in.headOption.getOrElse(Message.fail) + implicit def listFutureMessageToMessage(in: List[Future[Message]]): Message = in.headOption.getOrElse(Future(Message.fail))() def roundTrips: List[RoundTripInfo] @@ -30,11 +30,4 @@ trait RoundTripSnippet { } in } - - /* - * This is used to send messages to client. - */ - case class Message(msg_type: String, msg: Option[String] = None, data: Option[MsgData] = None) - - implicit def messageToJValue(msg: Message): JValue = msg } \ No newline at end of file diff --git a/src/main/scala/inc/pyc/chimera/snippet/UtilSnips.scala b/src/main/scala/inc/pyc/chimera/snippet/UtilSnips.scala @@ -4,6 +4,8 @@ package snippet import scala.xml.NodeSeq import net.liftweb._ import util._ +import json._ +import Serialization.write import net.liftmodules.extras.snippet._ object Assets extends AssetLoader @@ -19,4 +21,12 @@ trait MsgData trait ImplicitSnip { implicit def seqNodeSeqToNodeSeq(in: Seq[NodeSeq]): NodeSeq = in.headOption.getOrElse(NodeSeq.Empty) +} + +/* + * This is used to send messages to client. + */ +case class Message(msg_type: String, msg: Option[String] = None) +object Message { + def fail = Message("failure") } \ No newline at end of file diff --git a/src/main/webapp/app/ActorsBridge.js b/src/main/webapp/app/ActorsBridge.js @@ -22,7 +22,7 @@ window.ActorsBridge = function(sendFunc) { * Updates the price for price ticker. */ self.newPrice = function(message) { - self.broadcast('new-price', message); + self.broadcast('newPrice', message); }; }; \ No newline at end of file diff --git a/src/main/webapp/app/App.js b/src/main/webapp/app/App.js @@ -28,12 +28,20 @@ app.directive('disabler', ['$compile', function($compile) { * Price Ticker shows price per bitcoin. */ app.controller('PriceTickerCtrl', ['$scope', '$rootScope', function($scope, $rootScope) { - $rootScope.$on("new-price", function (event, message) { + $rootScope.$on("newPrice", function (event, message) { $scope.price = message.price; }); }]); -app.controller('WalletScannerCtrl', ['$scope', '$controller', '$timeout', 'WizardHandler', function($scope, $controller, $timeout, WizardHandler) { + +app.controller('MainCtrl', ['$scope', '$rootScope', function($scope, $rootScope) { + + $rootScope.user = {}; + +}]); + + +app.controller('WalletScannerCtrl', ['$scope', '$rootScope', '$controller', '$timeout', 'WizardHandler', function($scope, $rootScope, $controller, $timeout, WizardHandler) { $controller('FormCtrl', {$scope: $scope}); var scanned = false; @@ -47,24 +55,25 @@ app.controller('WalletScannerCtrl', ['$scope', '$controller', '$timeout', 'Wizar }, 1000); }; + $scope.qr_valid = true; + $scope.onSuccess = function(data) { if (data !== 'error decoding QR Code' && !scanned) { setScanned(); scan_sound.play(); var success = function() { - window.console.log("BAM: Success!"); + $scope.qr_valid = true; + $rootScope.user.bitcoin_address = data; WizardHandler.wizard().next(); }; - var failure = function() { - scanned = false; - window.console.log("BAM: FAILED!"); + var failme = function(info) { + window.console.log("Data Failure: "+info); + $scope.qr_valid = false; }; - window.console.log("QR: "+data); - $scope.model = data; - $scope.submit('BitcoinAddressScanner', 'submitAddress', success, failure); + $scope.submit('BitcoinAddressScanner', 'submitAddress', success, failme, data); } }; diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html @@ -1,6 +1,6 @@ <div data-lift="surround?with=base-default;at=content"> -<wizard id="wizard-main" on-finish="finishedWizard()" ng-cloak> +<wizard id="wizard-main" on-finish="finishedWizard()" ng-controller="MainCtrl" ng-cloak> <wz-step title="Start"> <a type="submit" wz-next class="no-design"> <h1>Buy bitcoin</h1> @@ -13,11 +13,15 @@ <div id="wallet-scanner" data-lift="BitcoinAddressScanner" ng-controller="WalletScannerCtrl"> <qr-scanner ng-success="onSuccess(data)" width="400" height="300"></qr> + <div ng-hide="qr_valid" class="padding-top-20 text-center text-danger"> + Invalid Bitcoin Address + </div> </div> </wz-step> - <wz-step title="More steps"> + <wz-step title="Insert Bills"> <h1>More Steps</h1> <p>Even more steps!!</p> + <div>{{ user.bitcoin_address }}</div> <input type="submit" wz-next value="Finish now" class="btn btn-primary" /> </wz-step> </wizard>