You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.0 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package main
  17. /* this file handles communication with the daemon
  18. * this includes receiving output information
  19. * *
  20. */
  21. import "io"
  22. import "fmt"
  23. import "net"
  24. import "time"
  25. import "sync"
  26. import "net/http"
  27. import "compress/gzip"
  28. //import "github.com/romana/rlog"
  29. //import "github.com/pierrec/lz4"
  30. import "github.com/ybbus/jsonrpc"
  31. import "github.com/arnaucode/derosuite/globals"
  32. import "github.com/arnaucode/derosuite/blockchain/rpcserver"
  33. var Wallet_Height uint64 // height of wallet
  34. var Daemon_Height uint64 // height of daemon
  35. var Connected bool = true
  36. var rpcClient *jsonrpc.RPCClient
  37. var netClient *http.Client
  38. var endpoint string
  39. var output_lock sync.Mutex
  40. // this is as simple as it gets
  41. // single threaded communication to get the daemon status and height
  42. func Run_Communication_Engine() {
  43. // check if user specified daemon address explicitly
  44. if globals.Arguments["--daemon-address"] != nil {
  45. daemon_address := globals.Arguments["--daemon-address"].(string)
  46. remote_end, err := net.ResolveTCPAddr("tcp", daemon_address)
  47. if err != nil {
  48. globals.Logger.Warnf("Daemon address \"%s\" is invalid. parse err %s", daemon_address, err)
  49. } else {
  50. fmt.Printf("%+v\n", remote_end.IP)
  51. if remote_end.IP == nil || remote_end.IP.IsUnspecified() { // user never provided an ipaddress, use loopback
  52. globals.Logger.Debugf("Setting loopback ip on daemon endpoint")
  53. remote_end.IP = net.IPv4(127, 0, 0, 1)
  54. }
  55. endpoint = remote_end.String()
  56. }
  57. }
  58. // if user provided endpoint has error, use default
  59. if endpoint == "" {
  60. endpoint = "127.0.0.1:9999"
  61. if !globals.IsMainnet() {
  62. endpoint = "127.0.0.1:28091"
  63. }
  64. }
  65. globals.Logger.Debugf("Daemon endpoint %s", endpoint)
  66. // TODO enable socks support here
  67. var netTransport = &http.Transport{
  68. Dial: (&net.Dialer{
  69. Timeout: 5 * time.Second, // 5 second timeout
  70. }).Dial,
  71. TLSHandshakeTimeout: 5 * time.Second,
  72. }
  73. netClient = &http.Client{
  74. Timeout: time.Second * 10,
  75. Transport: netTransport,
  76. }
  77. // create client
  78. rpcClient = jsonrpc.NewRPCClient("http://" + endpoint + "/json_rpc")
  79. for {
  80. time.Sleep(1 * time.Second) // ping server every second
  81. // execute rpc to service
  82. response, err := rpcClient.Call("get_info")
  83. // notify user of any state change
  84. // if daemon connection breaks or comes live again
  85. if err == nil {
  86. if !Connected {
  87. globals.Logger.Infof("Connection to RPC server successful")
  88. Connected = true
  89. }
  90. } else {
  91. if Connected {
  92. globals.Logger.Warnf("Connection to RPC server Failed err %s", err)
  93. Connected = false
  94. }
  95. continue // try next time
  96. }
  97. var info rpcserver.GetInfo_Result
  98. err = response.GetObject(&info)
  99. if err != nil {
  100. globals.Logger.Warnf("Daemon getinfo RPC parsing error err: %s\n", err)
  101. continue
  102. }
  103. // detect whether both are in different modes
  104. // daemon is in testnet and wallet in mainnet or
  105. // daemon
  106. if info.Testnet != !globals.IsMainnet() {
  107. globals.Logger.Warnf("Mainnet/TestNet is different between wallet/daemon.Please run daemon/wallet without --testnet")
  108. }
  109. Daemon_Height = info.Height
  110. }
  111. }
  112. // get the outputs from the daemon, requesting specfic outputs
  113. // the range can be anything
  114. // if stop is zero,
  115. // the daemon will flush out everything it has ASAP
  116. // the stream can be saved and used later on
  117. func Get_Outputs(start uint64, stop uint64) {
  118. output_lock.Lock()
  119. defer output_lock.Unlock()
  120. if Connected { // only execute query if we are connected
  121. response, err := http.Get(fmt.Sprintf("http://%s/getoutputs.bin?start=%d", endpoint, start))
  122. if err != nil {
  123. globals.Logger.Warnf("Error while requesting outputs from daemon err %s", err)
  124. // os.Exit(1)
  125. } else {
  126. defer response.Body.Close()
  127. // lz4reader := lz4.NewReader(response.Body)
  128. // io.Copy(pipe_writer, lz4reader)
  129. gzipreader, err := gzip.NewReader(response.Body)
  130. if err != nil {
  131. globals.Logger.Warnf("Error while decompressing output from daemon err: %s ", err)
  132. return
  133. }
  134. defer gzipreader.Close()
  135. io.Copy(pipe_writer, gzipreader)
  136. }
  137. // contents, err := ioutil.ReadAll(response.Body)
  138. }
  139. }