github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/walletapi/rpcserver.go (about)

     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  
    17  // the rpc server is an extension of walletapi and doesnot employ any global variables
    18  // so a number can be simultaneously active ( based on resources)
    19  package walletapi
    20  
    21  import "io"
    22  
    23  //import "fmt"
    24  import "time"
    25  import "sync"
    26  import "log"
    27  import "strings"
    28  import "net/http"
    29  
    30  //import "github.com/intel-go/fastjson"
    31  import "github.com/osamingo/jsonrpc"
    32  
    33  import "github.com/deroproject/derosuite/globals"
    34  import "github.com/deroproject/derosuite/structures"
    35  
    36  // all components requiring access to wallet must use , this struct to communicate
    37  // this structure must be update while mutex
    38  type RPCServer struct {
    39  	address          string
    40  	srv              *http.Server
    41  	mux              *http.ServeMux
    42  	mr               *jsonrpc.MethodRepository
    43  	Exit_Event       chan bool // wallet is shutting down and we must quit ASAP
    44  	Exit_In_Progress bool
    45  
    46  	w *Wallet // reference to the wallet which is open
    47  	sync.RWMutex
    48  }
    49  
    50  func RPCServer_Start(w *Wallet, address string) (*RPCServer, error) {
    51  
    52  	//var err error
    53  	var r RPCServer
    54  
    55  	//_ = err
    56  
    57  	r.Exit_Event = make(chan bool)
    58  	r.w = w
    59  	r.address = address
    60  
    61  	go r.Run()
    62  	//logger.Infof("RPC server started")
    63  
    64  	return &r, nil
    65  }
    66  
    67  // shutdown the rpc server component
    68  func (r *RPCServer) RPCServer_Stop() {
    69  	r.srv.Shutdown(nil) // shutdown the server
    70  	r.Exit_In_Progress = true
    71  	close(r.Exit_Event) // send signal to all connections to exit
    72  	// TODO we  must wait for connections to kill themselves
    73  	time.Sleep(1 * time.Second)
    74  	//logger.Infof("RPC Shutdown")
    75  
    76  }
    77  
    78  func (r *RPCServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    79  
    80  	basic_auth_enabled := false
    81  	var parts []string
    82  
    83  	if globals.Arguments["--rpc-login"] != nil {
    84  		userpass := globals.Arguments["--rpc-login"].(string)
    85  		parts = strings.SplitN(userpass, ":", 2)
    86  
    87  		basic_auth_enabled = true
    88  		/*if len(parts) != 2 { // these checks are done and verified during program init
    89  		  globals.Logger.Warnf("RPC user name or password invalid")
    90  		  return
    91  		 }*/
    92  		//log.Infof("RPC username \"%s\" password \"%s\" ", parts[0],parts[1])
    93  	}
    94  
    95  	if basic_auth_enabled {
    96  		u, p, ok := req.BasicAuth()
    97  		if !ok {
    98  			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
    99  			return
   100  		}
   101  		if u != parts[0] || p != parts[1] {
   102  			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
   103  			return
   104  		}
   105  
   106  	}
   107  	// log.Printf("basic_auth_handler") serve if everything looks okay
   108  	r.mr.ServeHTTP(w, req)
   109  }
   110  
   111  // setup handlers
   112  func (r *RPCServer) Run() {
   113  
   114  	mr := jsonrpc.NewMethodRepository()
   115  	r.mr = mr
   116  
   117  	// install getbalance handler
   118  	if err := mr.RegisterMethod("getbalance", GetBalance_Handler{r: r}, structures.GetBalance_Params{}, structures.GetBalance_Result{}); err != nil {
   119  		log.Fatalln(err)
   120  	}
   121  
   122  	// install getaddress handler
   123  	if err := mr.RegisterMethod("getaddress", GetAddress_Handler{r: r}, structures.GetAddress_Params{}, structures.GetBalance_Result{}); err != nil {
   124  		log.Fatalln(err)
   125  	}
   126  
   127  	// install getheight handler
   128  	if err := mr.RegisterMethod("getheight", GetHeight_Handler{r: r}, structures.GetHeight_Params{}, structures.GetBalance_Result{}); err != nil {
   129  		log.Fatalln(err)
   130  	}
   131  
   132  	// install transfer handler
   133  	if err := mr.RegisterMethod("transfer", Transfer_Handler{r: r}, structures.Transfer_Params{}, structures.Transfer_Result{}); err != nil {
   134  		log.Fatalln(err)
   135  	}
   136  	// install transfer_split handler
   137  	if err := mr.RegisterMethod("transfer_split", TransferSplit_Handler{r: r}, structures.TransferSplit_Params{}, structures.TransferSplit_Result{}); err != nil {
   138  		log.Fatalln(err)
   139  	}
   140  
   141  	// install get_bulk_payments handler
   142  	if err := mr.RegisterMethod("get_bulk_payments", Get_Bulk_Payments_Handler{r: r}, structures.Get_Bulk_Payments_Params{}, structures.Get_Bulk_Payments_Result{}); err != nil {
   143  		log.Fatalln(err)
   144  	}
   145  
   146  	// install query_key handler
   147  	if err := mr.RegisterMethod("query_key", Query_Key_Handler{r: r}, structures.Query_Key_Params{}, structures.Query_Key_Result{}); err != nil {
   148  		log.Fatalln(err)
   149  	}
   150  
   151  	// install make_integrated_address handler
   152  	if err := mr.RegisterMethod("make_integrated_address", Make_Integrated_Address_Handler{r: r}, structures.Make_Integrated_Address_Params{}, structures.Make_Integrated_Address_Result{}); err != nil {
   153  		log.Fatalln(err)
   154  	}
   155  
   156  	// install split_integrated_address handler
   157  	if err := mr.RegisterMethod("split_integrated_address", Split_Integrated_Address_Handler{r: r}, structures.Split_Integrated_Address_Params{}, structures.Split_Integrated_Address_Result{}); err != nil {
   158  		log.Fatalln(err)
   159  	}
   160  
   161  	// install get_transfer_by_txid handler
   162  	if err := mr.RegisterMethod("get_transfer_by_txid", Get_Transfer_By_TXID_Handler{r: r}, structures.Get_Transfer_By_TXID_Params{}, structures.Get_Transfer_By_TXID_Result{}); err != nil {
   163  		log.Fatalln(err)
   164  	}
   165  
   166  	// install get_transfers
   167  	if err := mr.RegisterMethod("get_transfers", Get_Transfers_Handler{r: r}, structures.Get_Transfers_Params{}, structures.Get_Transfers_Result{}); err != nil {
   168  		log.Fatalln(err)
   169  	}
   170  
   171  	/*
   172  		if err := mr.RegisterMethod("Main.Echo", EchoHandler{}, EchoParams{}, EchoResult{}); err != nil {
   173  			log.Fatalln(err)
   174  		}
   175  
   176  		// install getblockcount handler
   177  		if err := mr.RegisterMethod("getblockcount", GetBlockCount_Handler{}, structures.GetBlockCount_Params{}, structures.GetBlockCount_Result{}); err != nil {
   178  			log.Fatalln(err)
   179  		}
   180  
   181  		// install on_getblockhash
   182  		if err := mr.RegisterMethod("on_getblockhash", On_GetBlockHash_Handler{}, structures.On_GetBlockHash_Params{}, structures.On_GetBlockHash_Result{}); err != nil {
   183  			log.Fatalln(err)
   184  		}
   185  
   186  		// install getblocktemplate handler
   187  		if err := mr.RegisterMethod("getblocktemplate", GetBlockTemplate_Handler{}, structures.GetBlockTemplate_Params{}, structures.GetBlockTemplate_Result{}); err != nil {
   188  			log.Fatalln(err)
   189  		}
   190  
   191  		// submitblock handler
   192  		if err := mr.RegisterMethod("submitblock", SubmitBlock_Handler{}, structures.SubmitBlock_Params{}, structures.SubmitBlock_Result{}); err != nil {
   193  			log.Fatalln(err)
   194  		}
   195  
   196  		if err := mr.RegisterMethod("getlastblockheader", GetLastBlockHeader_Handler{}, structures.GetLastBlockHeader_Params{}, structures.GetLastBlockHeader_Result{}); err != nil {
   197  			log.Fatalln(err)
   198  		}
   199  
   200  		if err := mr.RegisterMethod("getblockheaderbyhash", GetBlockHeaderByHash_Handler{}, structures.GetBlockHeaderByHash_Params{}, structures.GetBlockHeaderByHash_Result{}); err != nil {
   201  			log.Fatalln(err)
   202  		}
   203  
   204  		if err := mr.RegisterMethod("getblockheaderbyheight", GetBlockHeaderByHeight_Handler{}, structures.GetBlockHeaderByHeight_Params{}, structures.GetBlockHeaderByHeight_Result{}); err != nil {
   205  			log.Fatalln(err)
   206  		}
   207  		if err := mr.RegisterMethod("getblock", GetBlock_Handler{}, structures.GetBlock_Params{}, structures.GetBlock_Result{}); err != nil {
   208  			log.Fatalln(err)
   209  		}
   210  
   211  		if err := mr.RegisterMethod("get_info", GetInfo_Handler{}, structures.GetInfo_Params{}, structures.GetInfo_Result{}); err != nil {
   212  			log.Fatalln(err)
   213  		}
   214  
   215  		if err := mr.RegisterMethod("gettxpool", GetTxPool_Handler{}, structures.GetTxPool_Params{}, structures.GetTxPool_Result{}); err != nil {
   216  			log.Fatalln(err)
   217  		}
   218  
   219  	*/
   220  	// create a new mux
   221  	r.mux = http.NewServeMux()
   222  	r.srv = &http.Server{Addr: r.address, Handler: r.mux}
   223  
   224  	r.mux.HandleFunc("/", hello)
   225  	r.mux.Handle("/json_rpc", r)
   226  	/*
   227  	   	// handle nasty http requests
   228  	   	r.mux.HandleFunc("/getoutputs.bin", getoutputs) // stream any outputs to server, can make wallet work offline
   229  	   	r.mux.HandleFunc("/gettransactions", gettransactions)
   230  	           r.mux.HandleFunc("/sendrawtransaction", SendRawTransaction_Handler)
   231  	*/
   232  	//r.mux.HandleFunc("/json_rpc/debug", mr.ServeDebug)
   233  
   234  	if err := r.srv.ListenAndServe(); err != http.ErrServerClosed {
   235  		log.Fatalf("ERR listening to address err %s", err)
   236  	}
   237  
   238  }
   239  
   240  func hello(w http.ResponseWriter, r *http.Request) {
   241  	io.WriteString(w, "Hello world!")
   242  }