mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
130 lines
3.1 KiB
Go
130 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/daglabs/btcd/rpcclient"
|
|
)
|
|
|
|
type server struct {
|
|
cfg *config
|
|
rpcConnConfig *rpcclient.ConnConfig
|
|
|
|
httpServer *http.Server
|
|
rpcClient *rpcclient.Client
|
|
}
|
|
|
|
func newServer(cfg *config) (*server, error) {
|
|
server := server{
|
|
cfg: cfg,
|
|
}
|
|
|
|
server.rpcConnConfig = &rpcclient.ConnConfig{
|
|
Host: cfg.Host,
|
|
Endpoint: "ws",
|
|
User: cfg.RPCUser,
|
|
Pass: cfg.RPCPass,
|
|
DisableTLS: cfg.DisableTLS,
|
|
}
|
|
if !cfg.DisableTLS {
|
|
certificate, err := ioutil.ReadFile(cfg.RPCCert)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
server.rpcConnConfig.Certificates = certificate
|
|
}
|
|
|
|
return &server, nil
|
|
}
|
|
|
|
func (s *server) start() error {
|
|
log.Printf("Connecting RPC client to %s", s.cfg.Host)
|
|
|
|
rpcClient, err := rpcclient.New(s.rpcConnConfig, nil)
|
|
if err != nil {
|
|
return errors.New(fmt.Sprintf("failed to create RPC client: %s", err))
|
|
}
|
|
s.rpcClient = rpcClient
|
|
|
|
log.Printf("Starting server on port %d", s.cfg.ListenPort)
|
|
|
|
handler := http.NewServeMux()
|
|
handler.HandleFunc("/", s.handleRequest)
|
|
|
|
s.httpServer = &http.Server{
|
|
Addr: fmt.Sprintf(":%d", s.cfg.ListenPort),
|
|
Handler: handler,
|
|
}
|
|
|
|
return s.httpServer.ListenAndServe()
|
|
}
|
|
|
|
func (s *server) handleRequest(responseWriter http.ResponseWriter, request *http.Request) {
|
|
s.allowCrossOrigin(responseWriter)
|
|
if request.Method == "OPTIONS" {
|
|
// OPTIONS must stop here or else CORS protection will throw a tantrum.
|
|
return
|
|
}
|
|
|
|
if request.Method != "POST" {
|
|
responseWriter.WriteHeader(404)
|
|
return
|
|
}
|
|
|
|
forwardedResponse, err := s.forwardRequest(request)
|
|
if err != nil {
|
|
responseWriter.WriteHeader(500)
|
|
log.Printf("failed to forward request: %s", err)
|
|
return
|
|
}
|
|
|
|
_, err = responseWriter.Write([]byte(forwardedResponse))
|
|
if err != nil {
|
|
responseWriter.WriteHeader(500)
|
|
log.Printf("failed to write response: %s", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s *server) allowCrossOrigin(responseWriter http.ResponseWriter) {
|
|
responseWriter.Header().Set("Access-Control-Allow-Origin", "*")
|
|
responseWriter.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
|
responseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
|
}
|
|
|
|
func (s *server) forwardRequest(request *http.Request) ([]byte, error) {
|
|
jsonRPCMethod := strings.TrimPrefix(request.URL.Path, "/")
|
|
|
|
requestBody, err := ioutil.ReadAll(request.Body)
|
|
if err != nil {
|
|
return nil, errors.New(fmt.Sprintf("failed to read request body: %s", err))
|
|
}
|
|
|
|
var jsonRPCParams []json.RawMessage
|
|
err = json.Unmarshal(requestBody, &jsonRPCParams)
|
|
if err != nil {
|
|
return nil, errors.New(fmt.Sprintf("failed to parse params: %s", err))
|
|
}
|
|
|
|
response, err := s.rpcClient.RawRequest(jsonRPCMethod, jsonRPCParams)
|
|
if err != nil {
|
|
return nil, errors.New(fmt.Sprintf("request to rpc server failed: %s", err))
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (s *server) stop() error {
|
|
log.Printf("Disconnecting RPC client")
|
|
s.rpcClient.Disconnect()
|
|
|
|
log.Printf("Stopping server")
|
|
return s.httpServer.Close()
|
|
}
|