// Copyright 2017-2018 DERO Project. All rights reserved. // Use of this source code in any form is governed by RESEARCH license. // license can be found in the LICENSE file. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 // // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package main /* this file handles communication with the daemon * this includes receiving output information * * */ import "io" import "fmt" import "net" import "time" import "sync" import "net/http" import "compress/gzip" //import "github.com/romana/rlog" //import "github.com/pierrec/lz4" import "github.com/ybbus/jsonrpc" import "github.com/arnaucode/derosuite/globals" import "github.com/arnaucode/derosuite/blockchain/rpcserver" var Wallet_Height uint64 // height of wallet var Daemon_Height uint64 // height of daemon var Connected bool = true var rpcClient *jsonrpc.RPCClient var netClient *http.Client var endpoint string var output_lock sync.Mutex // this is as simple as it gets // single threaded communication to get the daemon status and height func Run_Communication_Engine() { // check if user specified daemon address explicitly if globals.Arguments["--daemon-address"] != nil { daemon_address := globals.Arguments["--daemon-address"].(string) remote_end, err := net.ResolveTCPAddr("tcp", daemon_address) if err != nil { globals.Logger.Warnf("Daemon address \"%s\" is invalid. parse err %s", daemon_address, err) } else { fmt.Printf("%+v\n", remote_end.IP) if remote_end.IP == nil || remote_end.IP.IsUnspecified() { // user never provided an ipaddress, use loopback globals.Logger.Debugf("Setting loopback ip on daemon endpoint") remote_end.IP = net.IPv4(127, 0, 0, 1) } endpoint = remote_end.String() } } // if user provided endpoint has error, use default if endpoint == "" { endpoint = "127.0.0.1:9999" if !globals.IsMainnet() { endpoint = "127.0.0.1:28091" } } globals.Logger.Debugf("Daemon endpoint %s", endpoint) // TODO enable socks support here var netTransport = &http.Transport{ Dial: (&net.Dialer{ Timeout: 5 * time.Second, // 5 second timeout }).Dial, TLSHandshakeTimeout: 5 * time.Second, } netClient = &http.Client{ Timeout: time.Second * 10, Transport: netTransport, } // create client rpcClient = jsonrpc.NewRPCClient("http://" + endpoint + "/json_rpc") for { time.Sleep(1 * time.Second) // ping server every second // execute rpc to service response, err := rpcClient.Call("get_info") // notify user of any state change // if daemon connection breaks or comes live again if err == nil { if !Connected { globals.Logger.Infof("Connection to RPC server successful") Connected = true } } else { if Connected { globals.Logger.Warnf("Connection to RPC server Failed err %s", err) Connected = false } continue // try next time } var info rpcserver.GetInfo_Result err = response.GetObject(&info) if err != nil { globals.Logger.Warnf("Daemon getinfo RPC parsing error err: %s\n", err) continue } // detect whether both are in different modes // daemon is in testnet and wallet in mainnet or // daemon if info.Testnet != !globals.IsMainnet() { globals.Logger.Warnf("Mainnet/TestNet is different between wallet/daemon.Please run daemon/wallet without --testnet") } Daemon_Height = info.Height } } // get the outputs from the daemon, requesting specfic outputs // the range can be anything // if stop is zero, // the daemon will flush out everything it has ASAP // the stream can be saved and used later on func Get_Outputs(start uint64, stop uint64) { output_lock.Lock() defer output_lock.Unlock() if Connected { // only execute query if we are connected response, err := http.Get(fmt.Sprintf("http://%s/getoutputs.bin?start=%d", endpoint, start)) if err != nil { globals.Logger.Warnf("Error while requesting outputs from daemon err %s", err) // os.Exit(1) } else { defer response.Body.Close() // lz4reader := lz4.NewReader(response.Body) // io.Copy(pipe_writer, lz4reader) gzipreader, err := gzip.NewReader(response.Body) if err != nil { globals.Logger.Warnf("Error while decompressing output from daemon err: %s ", err) return } defer gzipreader.Close() io.Copy(pipe_writer, gzipreader) } // contents, err := ioutil.ReadAll(response.Body) } }