github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/vm/wasmapi/server.go (about)

     1  package wasmapi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"time"
    11  
    12  	"github.com/gin-gonic/gin"
    13  	"github.com/hibiken/asynq"
    14  	"github.com/pkg/errors"
    15  
    16  	confid "github.com/machinefi/w3bstream/pkg/depends/conf/id"
    17  	confmq "github.com/machinefi/w3bstream/pkg/depends/conf/mq"
    18  	"github.com/machinefi/w3bstream/pkg/depends/conf/redis"
    19  	"github.com/machinefi/w3bstream/pkg/depends/kit/logr"
    20  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx"
    21  	optypes "github.com/machinefi/w3bstream/pkg/modules/operator/pool/types"
    22  	"github.com/machinefi/w3bstream/pkg/modules/vm/wasmapi/async"
    23  	"github.com/machinefi/w3bstream/pkg/modules/vm/wasmapi/handler"
    24  	apitypes "github.com/machinefi/w3bstream/pkg/modules/vm/wasmapi/types"
    25  	"github.com/machinefi/w3bstream/pkg/types"
    26  	"github.com/machinefi/w3bstream/pkg/types/wasm/kvdb"
    27  )
    28  
    29  type Server struct {
    30  	router *gin.Engine
    31  	cli    *asynq.Client
    32  	srv    *asynq.Server
    33  }
    34  
    35  func (s *Server) Call(ctx context.Context, data []byte) *apitypes.HttpResponse {
    36  	_, l := logr.Start(ctx, "vm.Server.Call")
    37  	defer l.End()
    38  
    39  	apiReq := apitypes.HttpRequest{}
    40  	if err := json.Unmarshal(data, &apiReq); err != nil {
    41  		l.Error(errors.Wrap(err, "http request illegal format"))
    42  		return &apitypes.HttpResponse{
    43  			StatusCode: http.StatusBadRequest,
    44  		}
    45  	}
    46  	req, err := http.NewRequestWithContext(ctx, apiReq.Method, apiReq.Url, bytes.NewReader(apiReq.Body))
    47  	if err != nil {
    48  		l.Error(errors.Wrap(err, "build http request failed"))
    49  		return &apitypes.HttpResponse{
    50  			StatusCode: http.StatusBadRequest,
    51  		}
    52  	}
    53  	req.Header = apiReq.Header
    54  
    55  	respRecorder := httptest.NewRecorder()
    56  	s.router.ServeHTTP(respRecorder, req)
    57  
    58  	resp, err := async.ConvHttpResponse(apiReq.Header, respRecorder.Result())
    59  	if err != nil {
    60  		l.Error(errors.Wrap(err, "conv http response failed"))
    61  		return &apitypes.HttpResponse{
    62  			StatusCode: http.StatusInternalServerError,
    63  		}
    64  	}
    65  	return resp
    66  }
    67  
    68  func (s *Server) Shutdown() {
    69  	s.srv.Shutdown()
    70  }
    71  
    72  func newRouter(mgrDB sqlx.DBExecutor, chainConf *types.ChainConfig, opPool optypes.Pool, sfid confid.SFIDGenerator,
    73  	asyncCli *asynq.Client, risc0Conf *types.Risc0Config) *gin.Engine {
    74  	router := gin.New()
    75  	router.Use(gin.Recovery())
    76  	router.Use(handler.ParamValidate())
    77  
    78  	handlers := handler.New(mgrDB, chainConf, opPool, sfid, asyncCli, risc0Conf)
    79  
    80  	router.GET("/system/hello", handlers.Hello)
    81  	router.GET("/system/hello/async", handlers.HelloAsync)
    82  	router.GET("/system/read_tx", handlers.ReadTx)
    83  	router.GET("/system/read_tx/async", handlers.ReadTxAsync)
    84  	router.POST("/system/send_tx", handlers.SendTx)
    85  	router.POST("/system/send_tx/async", handlers.SendTxAsync)
    86  	router.POST("/system/send_tx/async/state", handlers.SendTxAsyncStateCheck)
    87  	router.POST("/system/gen_zk_proof", handlers.GenRisc0Proof)
    88  	router.POST("/system/gen_zk_proof/async", handlers.GenRisc0ProofAsync)
    89  
    90  	return router
    91  }
    92  
    93  func NewServer(redisConf *redis.Redis, mgrDB sqlx.DBExecutor, kv *kvdb.RedisDB, chainConf *types.ChainConfig,
    94  	tasks *confmq.Config, opPool optypes.Pool, sfid confid.SFIDGenerator, risc0Conf *types.Risc0Config) (*Server, error) {
    95  
    96  	redisCli := asynq.RedisClientOpt{
    97  		Network:      redisConf.Protocol,
    98  		Addr:         fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
    99  		Password:     redisConf.Password.String(),
   100  		ReadTimeout:  time.Duration(redisConf.ReadTimeout),
   101  		WriteTimeout: time.Duration(redisConf.WriteTimeout),
   102  		DialTimeout:  time.Duration(redisConf.ConnectTimeout),
   103  		DB:           redisConf.DB,
   104  	}
   105  	asyncCli := asynq.NewClient(redisCli)
   106  	asyncSrv := asynq.NewServer(redisCli, asynq.Config{})
   107  
   108  	router := newRouter(mgrDB, chainConf, opPool, sfid, asyncCli, risc0Conf)
   109  
   110  	mux := asynq.NewServeMux()
   111  	mux.Handle(async.TaskNameApiCall, async.NewApiCallProcessor(router, asyncCli))
   112  	mux.Handle(async.TaskNameApiResult, async.NewApiResultProcessor(mgrDB, kv, tasks, redisConf))
   113  
   114  	if err := asyncSrv.Start(mux); err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	return &Server{
   119  		router: router,
   120  		cli:    asyncCli,
   121  		srv:    asyncSrv,
   122  	}, nil
   123  }