github.com/SimplyVC/oasis_api_server/src@v0.0.0-20220105202803-ad2c5a67840e/handlers/scheduler_handler.go (about)

     1  package handlers
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"net/http"
     7  
     8  	"google.golang.org/grpc"
     9  
    10  	lgr "github.com/SimplyVC/oasis_api_server/src/logger"
    11  	"github.com/SimplyVC/oasis_api_server/src/responses"
    12  	"github.com/SimplyVC/oasis_api_server/src/rpc"
    13  	common_namespace "github.com/oasisprotocol/oasis-core/go/common"
    14  	scheduler "github.com/oasisprotocol/oasis-core/go/scheduler/api"
    15  )
    16  
    17  // loadSchedulerClient loads scheduler client and returns it
    18  func loadSchedulerClient(socket string) (*grpc.ClientConn, scheduler.Backend) {
    19  
    20  	// Attempt to load connection with scheduler client
    21  	connection, schedulerClient, err := rpc.SchedulerClient(socket)
    22  	if err != nil {
    23  		lgr.Error.Println(
    24  			"Failed to establish connection to scheduler client : ",
    25  			err)
    26  		return nil, nil
    27  	}
    28  	return connection, schedulerClient
    29  }
    30  
    31  // GetValidators returns vector of consensus validators for given epoch.
    32  func GetValidators(w http.ResponseWriter, r *http.Request) {
    33  
    34  	// Add header so that received knows they're receiving JSON
    35  	w.Header().Add("Content-Type", "application/json")
    36  
    37  	// Retrieving name of node from query request
    38  	nodeName := r.URL.Query().Get("name")
    39  	confirmation, socket := checkNodeName(nodeName)
    40  	if !confirmation  {
    41  
    42  		// Stop code here no need to establish connection and reply
    43  		json.NewEncoder(w).Encode(responses.ErrorResponse{
    44  			Error: "Node name requested doesn't exist"})
    45  		return
    46  	}
    47  
    48  	// Retrieving height of node from query request
    49  	recvHeight := r.URL.Query().Get("height")
    50  	height := checkHeight(recvHeight)
    51  	if height == -1 {
    52  
    53  		// Stop code here no need to establish connection and reply
    54  		json.NewEncoder(w).Encode(responses.ErrorResponse{
    55  			Error: "Unexpected value found, height needs to be " +
    56  				"a string representing an int!"})
    57  		return
    58  	}
    59  
    60  	// Attempt to load connection with scheduler client
    61  	connection, sc := loadSchedulerClient(socket)
    62  
    63  	// Close connection once code underneath executes
    64  	defer connection.Close()
    65  
    66  	// If null object was retrieved send response
    67  	if sc == nil {
    68  
    69  		// Stop code here faild to establish connection and reply
    70  		json.NewEncoder(w).Encode(responses.ErrorResponse{
    71  			Error: "Failed to establish connection using socket: " +
    72  				socket})
    73  		return
    74  	}
    75  
    76  	// Retrieve validators at given block height
    77  	validators, err := sc.GetValidators(context.Background(), height)
    78  	if err != nil {
    79  		json.NewEncoder(w).Encode(responses.ErrorResponse{
    80  			Error: "Failed to get Validators!"})
    81  		lgr.Error.Println("Request at /api/scheduler/validators "+
    82  			"failed to retrieve validators : ", err)
    83  		return
    84  	}
    85  
    86  	// Responding with Validators retrieved from scheduler client
    87  	lgr.Info.Println("Request at /api/scheduler/validators responding " +
    88  		"with Validators!")
    89  	json.NewEncoder(w).Encode(responses.ValidatorsResponse{
    90  		Validators: validators})
    91  }
    92  
    93  // GetCommittees returns vector of committees for given
    94  // runtime ID, at specified block height, and optional callback
    95  // for querying beacon for given epoch/block height.
    96  func GetCommittees(w http.ResponseWriter, r *http.Request) {
    97  
    98  	// Add header so that received knows they're receiving JSON
    99  	w.Header().Add("Content-Type", "application/json")
   100  
   101  	// Retrieving name of node from query request
   102  	nodeName := r.URL.Query().Get("name")
   103  	confirmation, socket := checkNodeName(nodeName)
   104  	if !confirmation  {
   105  		// Stop code here no need to establish connection and reply
   106  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   107  			Error: "Node name requested doesn't exist"})
   108  		return
   109  	}
   110  
   111  	// Retrieving height from query request
   112  	recvHeight := r.URL.Query().Get("height")
   113  	height := checkHeight(recvHeight)
   114  	if height == -1 {
   115  		// Stop code here no need to establish connection and reply
   116  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   117  			Error: "Unexpected value found, height needs to be " +
   118  				"a string representing an int!"})
   119  		return
   120  	}
   121  
   122  	// Note Make sure that private key that is being sent is coded properly
   123  	// Example A1X90rT/WK4AOTh/dJsUlOqNDV/nXM6ZU+h+blS9pto= should be
   124  	// A1X90rT/WK4AOTh/dJsUlOqNDV/nXM6ZU%2Bh%2BblS9pto=
   125  	var nameSpace common_namespace.Namespace
   126  	nmspace := r.URL.Query().Get("namespace")
   127  	if len(nmspace) == 0 {
   128  
   129  		// Stop code here no need to establish connection and reply
   130  		lgr.Warning.Println("Request at /api/scheduler/committees failed" +
   131  			", namespace can't be empty!")
   132  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   133  			Error: "namespace can't be empty!"})
   134  		return
   135  	}
   136  
   137  	// Unmarshal text into namespace object to be used in query
   138  	err := nameSpace.UnmarshalText([]byte(nmspace))
   139  	if err != nil {
   140  		lgr.Error.Println("Failed to UnmarshalText into Namespace", err)
   141  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   142  			Error: "Failed to UnmarshalText into Namespace."})
   143  		return
   144  	}
   145  
   146  	// Attempt to load connection with scheduler client
   147  	connection, sc := loadSchedulerClient(socket)
   148  
   149  	// Close connection once code underneath executes
   150  	defer connection.Close()
   151  
   152  	// If null object was retrieved send response
   153  	if sc == nil {
   154  
   155  		// Stop code here faild to establish connection and reply
   156  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   157  			Error: "Failed to establish connection using socket: " +
   158  				socket})
   159  		return
   160  	}
   161  
   162  	// Create query to be used to retrieve Committees
   163  	query := scheduler.GetCommitteesRequest{Height: height,
   164  		RuntimeID: nameSpace}
   165  
   166  	// Retrieving Committees using query above
   167  	committees, err := sc.GetCommittees(context.Background(), &query)
   168  	if err != nil {
   169  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   170  			Error: "Failed to get Committees!"})
   171  		lgr.Error.Println("Request at /api/scheduler/committees "+
   172  			"failed to retrieve committees : ", err)
   173  		return
   174  	}
   175  
   176  	// Responding with committees that were retrieved from scheduler client
   177  	lgr.Info.Println("Request at /api/scheduler/committees responding " +
   178  		"with Committees!")
   179  	json.NewEncoder(w).Encode(responses.CommitteesResponse{
   180  		Committee: committees})
   181  }
   182  
   183  // GetSchedulerStateToGenesis returns genesis state of scheduler at the
   184  // specified block height.
   185  func GetSchedulerStateToGenesis(w http.ResponseWriter, r *http.Request) {
   186  
   187  	// Add header so that received knows they're receiving JSON
   188  	w.Header().Add("Content-Type", "application/json")
   189  
   190  	// Retrieving name of node from query request
   191  	nodeName := r.URL.Query().Get("name")
   192  	confirmation, socket := checkNodeName(nodeName)
   193  	if !confirmation  {
   194  
   195  		// Stop code here no need to establish connection and reply
   196  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   197  			Error: "Node name requested doesn't exist"})
   198  		return
   199  	}
   200  
   201  	// Retrieving height from query request
   202  	recvHeight := r.URL.Query().Get("height")
   203  	height := checkHeight(recvHeight)
   204  	if height == -1 {
   205  
   206  		// Stop code here no need to establish connection and reply
   207  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   208  			Error: "Unexpected value found, height needs to be " +
   209  				"a string representing an int!"})
   210  		return
   211  	}
   212  
   213  	// Attempt to load connection with scheduler client
   214  	connection, sc := loadSchedulerClient(socket)
   215  
   216  	// Close connection once code underneath executes
   217  	defer connection.Close()
   218  
   219  	// If null object was retrieved send response
   220  	if sc == nil {
   221  
   222  		// Stop code here faild to establish connection and reply
   223  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   224  			Error: "Failed to establish connection using socket: " +
   225  				socket})
   226  		return
   227  	}
   228  
   229  	// Retrieve genesis state of scheduler at specific block height
   230  	gensis, err := sc.StateToGenesis(context.Background(), height)
   231  	if err != nil {
   232  		json.NewEncoder(w).Encode(responses.ErrorResponse{
   233  			Error: "Failed to get Scheduler Genesis State!"})
   234  		lgr.Error.Println("Request at /api/scheduler/genesis failed "+
   235  			"to retrieve Scheduler Genesis State : ", err)
   236  		return
   237  	}
   238  
   239  	// Responding with genesis state retrieved above
   240  	lgr.Info.Println("Request at /api/scheduler/genesis responding with " +
   241  		"scheduler genesis state!")
   242  	json.NewEncoder(w).Encode(responses.SchedulerGenesisState{
   243  		SchedulerGenesisState: gensis})
   244  }