diff --git a/Dockerfile b/Dockerfile index 802a0a3..8542441 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,6 @@ FROM alpine:3.22.2 RUN apk add --no-cache ca-certificates aws-cli curl tree mongodb-tools nodejs npm RUN rm -rf /var/cache/apk/* COPY --from=builder /go/bin/* /usr/local/bin/ -COPY --from=builder /src/swagger /apps/data/swagger #configure container VOLUME /apps/data diff --git a/api/design/api_design.go b/api/design/api_design.go deleted file mode 100644 index 62bf447..0000000 --- a/api/design/api_design.go +++ /dev/null @@ -1,58 +0,0 @@ -package design - -import ( - . "goa.design/goa/v3/dsl" - cors "goa.design/plugins/v3/cors/dsl" - _ "goa.design/plugins/v3/docs" -) - -var _ = Service("Injective Price Oracle API", func() { - Description("Injective-Price-Oracle services API doc") - - HTTP(func() { - Path("/api/price-oracle/v1") - }) - - cors.Origin("*", func() { - cors.Methods("POST") - cors.Headers("Content-Type", "X-Api-Key") - }) - - Error("invalid_arg", ErrorResult, "Invalid argument") - Error("not_found", ErrorResult, "Not found") - Error("internal", ErrorResult, "Internal Server Error") - Error("unauthorized", ErrorResult, "Unauthorized") - - Method("probe", func() { - Security(APIKeyAuth) - Description("Validate TOML file") - Payload(func() { - APIKey("api_key", "key", String, "API key for authentication") - Field(1, "content", Bytes, "TOML file contents") - Required("content") - }) - - Result(ProbeResponse) - - HTTP(func() { - Header("key:X-Api-Key") - POST("/probe") - MultipartRequest() - Response(StatusOK) - Response("invalid_arg", StatusBadRequest) - Response("internal", StatusInternalServerError) - Response("unauthorized", StatusUnauthorized) - - }) - }) -}) - -var ProbeResponse = Type("ProbeResponse", func() { - Field(1, "result", String, func() { - Description("Result of the probe") - }) - - Required( - "result", - ) -}) diff --git a/api/design/api_security.go b/api/design/api_security.go deleted file mode 100644 index 3e0527a..0000000 --- a/api/design/api_security.go +++ /dev/null @@ -1,10 +0,0 @@ -package design - -import ( - . "goa.design/goa/v3/dsl" -) - -// APIKeyAuth defines our security scheme -var APIKeyAuth = APIKeySecurity("api_key", func() { - Scope("api:read", "Read-only access") -}) diff --git a/api/design/api_server.go b/api/design/api_server.go deleted file mode 100644 index 769f36c..0000000 --- a/api/design/api_server.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:generate goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ -package design - -import ( - . "goa.design/goa/v3/dsl" - _ "goa.design/plugins/v3/docs" -) - -// API describes the global properties of the API server. -var _ = API("PriceOracle", func() { - Title("PriceOracle Service") - Description("HTTP server for the Price Oracle API") - - Server("PriceOracle", func() { - Host("mainnet", func() { - URI("https://k8s.mainnet.eu.price-oracle.injective.network") - }) - Host("testnet", func() { - URI("https://k8s.testnet.price-oracle.injective.network") - }) - Host("staging-mainnet", func() { - URI("https://k8s.mainnet.staging.price-oracle.injective.network") - }) - }) -}) - -var _ = Service("Swagger", func() { - Description("The API Swagger specification") - - HTTP(func() { - Path("/swagger") - }) - - Files("/index.html", "./swagger/index.html", func() { - Description("Provide Swagger-UI html document") - }) - - Files("/{*path}", "./swagger/", func() { - Description("Serve static content.") - }) -}) diff --git a/api/design/health_service.go b/api/design/health_service.go deleted file mode 100644 index 58e0a6a..0000000 --- a/api/design/health_service.go +++ /dev/null @@ -1,77 +0,0 @@ -package design - -import ( - . "goa.design/goa/v3/dsl" - cors "goa.design/plugins/v3/cors/dsl" - _ "goa.design/plugins/v3/docs" -) - -var _ = Service("health", func() { - Description("HealthAPI allows to check if backend data is up-to-date and reliable or not.") - - Error("internal", ErrorResult, "Internal Server Error") - - HTTP(func() { - Path("/api/health/v1") - }) - GRPC(func() { - Package("injective.price.oracle.api.v1") - }) - // Sets CORS response headers for requests with Origin header matching the string "localhost" - cors.Origin("*", func() { - cors.Methods("GET") - cors.Headers("Content-Type") - }) - - Method("GetStatus", func() { - Description("Get current backend health status") - - Result(HealthStatusResponse) - - HTTP(func() { - GET("/status") - - Response(StatusOK) - Response("internal", StatusInternalServerError) - }) - - GRPC(func() { - Response(CodeOK) - Response("internal", CodeInternal) - }) - }) - -}) - -var HealthStatusResponse = Type("HealthStatusResponse", func() { - Reference(BaseHealthResponse) - Field(1, "s") - Field(2, "errmsg") - Field(3, "data", HealthStatus) - Field(4, "status") - - Required("s", "status") -}) - -var HealthStatus = Type("HealthStatus", func() { - Description("Status defines the structure for health information") -}) - -var BaseHealthResponse = Type("BaseHealthResponse", func() { - Description("Base response of Health API.") - - Field(1, "s", String, func() { - Description("Status of the response.") - Example("error") - Enum( - "ok", - "error", - "no_data", - ) - }) - - Field(2, "errmsg", String, func() { - Description("Error message.") - Example("Something has failed") - }) -}) diff --git a/api/gen/docs.json b/api/gen/docs.json deleted file mode 100644 index 1b1cfcd..0000000 --- a/api/gen/docs.json +++ /dev/null @@ -1 +0,0 @@ -{"api":{"name":"PriceOracle","title":"PriceOracle Service","description":"HTTP server for the Price Oracle API","servers":{"PriceOracle":{"name":"PriceOracle","services":["Injective Price Oracle API","Swagger","health"],"hosts":{"mainnet":{"name":"mainnet","server":"PriceOracle","uris":["https://k8s.mainnet.eu.price-oracle.injective.network","grpc://localhost:8080"]},"staging-mainnet":{"name":"staging-mainnet","server":"PriceOracle","uris":["https://k8s.mainnet.staging.price-oracle.injective.network","grpc://localhost:8080"]},"testnet":{"name":"testnet","server":"PriceOracle","uris":["https://k8s.testnet.price-oracle.injective.network","grpc://localhost:8080"]}}}}},"services":{"Injective Price Oracle API":{"name":"Injective Price Oracle API","description":"Injective-Price-Oracle services API doc","methods":{"probe":{"name":"probe","description":"Validate TOML file","payload":{"type":{"$ref":"#/definitions/ProbePayload","required":["content"]},"example":{"content":"RG9sb3JlIGV0IHNlZCBtb2xlc3RpYXMgZXN0IGxhdWRhbnRpdW0gaXBzdW0u","key":"Consequatur quod expedita quisquam eaque perspiciatis."}},"result":{"type":{"$ref":"#/definitions/ProbeResponse"},"example":{"result":"Dolorem est qui voluptas amet."}},"requirements":[{"schemes":[{"type":"APIKey","name":"","in":"","scheme":"api_key"}],"scopes":null}]}}},"Swagger":{"name":"Swagger","description":"The API Swagger specification"},"health":{"name":"health","description":"HealthAPI allows to check if backend data is up-to-date and reliable or not.","methods":{"GetStatus":{"name":"GetStatus","description":"Get current backend health status","result":{"type":{"$ref":"#/definitions/HealthStatusResponse"},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Consequatur ea voluptatem in."}}}}}},"definitions":{"Error":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Error response result type (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"HealthGetStatusInternalResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Internal Server Error (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"HealthGetStatusResponseBody":{"title":"HealthGetStatusResponseBody","type":"object","properties":{"data":{"$ref":"#/definitions/HealthStatusResponseBody"},"errmsg":{"type":"string","description":"Error message.","example":"Something has failed"},"s":{"type":"string","description":"Status of the response.","example":"error","enum":["ok","error","no_data"]},"status":{"type":"string","example":"Est ut consequatur."}},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Non dolor rerum."},"required":["s","status"]},"HealthStatus":{"title":"HealthStatus","type":"object","description":"Status defines the structure for health information","example":{}},"HealthStatusResponse":{"title":"HealthStatusResponse","type":"object","properties":{"data":{"$ref":"#/definitions/HealthStatus"},"errmsg":{"type":"string","description":"Error message.","example":"Something has failed"},"s":{"type":"string","description":"Status of the response.","example":"error","enum":["ok","error","no_data"]},"status":{"type":"string","example":"Amet ducimus quaerat."}},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Temporibus eum occaecati."},"required":["s","status"]},"HealthStatusResponseBody":{"title":"HealthStatusResponseBody","type":"object","description":"Status defines the structure for health information","example":{}},"InjectivePriceOracleAPIProbeInternalResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Internal Server Error (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"InjectivePriceOracleAPIProbeInvalidArgResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Invalid argument (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"InjectivePriceOracleAPIProbeRequestBody":{"title":"InjectivePriceOracleAPIProbeRequestBody","type":"object","properties":{"content":{"type":"string","description":"TOML file contents","example":"TW9sZXN0aWFzIHV0IHByYWVzZW50aXVtIHBvcnJvIG5vbiBzaW50IG5lc2NpdW50Lg==","format":"byte"}},"example":{"content":"RG9sb3JlbXF1ZSBxdWlhIHNlZCBlb3Mu"},"required":["content"]},"InjectivePriceOracleAPIProbeResponseBody":{"title":"InjectivePriceOracleAPIProbeResponseBody","type":"object","properties":{"result":{"type":"string","description":"Result of the probe","example":"Ea corrupti."}},"example":{"result":"Inventore non explicabo cumque possimus molestiae enim."},"required":["result"]},"InjectivePriceOracleAPIProbeUnauthorizedResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"Unauthorized (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"ProbePayload":{"title":"ProbePayload","type":"object","properties":{"content":{"type":"string","description":"TOML file contents","example":"Q29uc2VxdWF0dXIgZXQgZXQgaXBzYW0u","format":"byte"},"key":{"type":"string","description":"API key for authentication","example":"Impedit aliquid ab."}},"example":{"content":"RXQgZWEgaW1wZWRpdCBuYXR1cyB2aXRhZSBlYXF1ZS4=","key":"Ut repudiandae cumque labore hic."},"required":["content"]},"ProbeResponse":{"title":"ProbeResponse","type":"object","properties":{"result":{"type":"string","description":"Result of the probe","example":"Totam illum cumque."}},"example":{"result":"Illum perferendis id doloribus."},"required":["result"]}}} \ No newline at end of file diff --git a/api/gen/grpc/cli/price_oracle/cli.go b/api/gen/grpc/cli/price_oracle/cli.go deleted file mode 100644 index f5c4b36..0000000 --- a/api/gen/grpc/cli/price_oracle/cli.go +++ /dev/null @@ -1,141 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// PriceOracle gRPC client CLI support package -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package cli - -import ( - "flag" - "fmt" - "os" - - healthc "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/client" - goa "goa.design/goa/v3/pkg" - grpc "google.golang.org/grpc" -) - -// UsageCommands returns the set of commands and sub-commands using the format -// -// command (subcommand1|subcommand2|...) -func UsageCommands() string { - return `health get-status -` -} - -// UsageExamples produces an example of a valid invocation of the CLI tool. -func UsageExamples() string { - return os.Args[0] + ` health get-status` + "\n" + - "" -} - -// ParseEndpoint returns the endpoint and payload as specified on the command -// line. -func ParseEndpoint(cc *grpc.ClientConn, opts ...grpc.CallOption) (goa.Endpoint, interface{}, error) { - var ( - healthFlags = flag.NewFlagSet("health", flag.ContinueOnError) - - healthGetStatusFlags = flag.NewFlagSet("get-status", flag.ExitOnError) - ) - healthFlags.Usage = healthUsage - healthGetStatusFlags.Usage = healthGetStatusUsage - - if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { - return nil, nil, err - } - - if flag.NArg() < 2 { // two non flag args are required: SERVICE and ENDPOINT (aka COMMAND) - return nil, nil, fmt.Errorf("not enough arguments") - } - - var ( - svcn string - svcf *flag.FlagSet - ) - { - svcn = flag.Arg(0) - switch svcn { - case "health": - svcf = healthFlags - default: - return nil, nil, fmt.Errorf("unknown service %q", svcn) - } - } - if err := svcf.Parse(flag.Args()[1:]); err != nil { - return nil, nil, err - } - - var ( - epn string - epf *flag.FlagSet - ) - { - epn = svcf.Arg(0) - switch svcn { - case "health": - switch epn { - case "get-status": - epf = healthGetStatusFlags - - } - - } - } - if epf == nil { - return nil, nil, fmt.Errorf("unknown %q endpoint %q", svcn, epn) - } - - // Parse endpoint flags if any - if svcf.NArg() > 1 { - if err := epf.Parse(svcf.Args()[1:]); err != nil { - return nil, nil, err - } - } - - var ( - data interface{} - endpoint goa.Endpoint - err error - ) - { - switch svcn { - case "health": - c := healthc.NewClient(cc, opts...) - switch epn { - case "get-status": - endpoint = c.GetStatus() - data = nil - } - } - } - if err != nil { - return nil, nil, err - } - - return endpoint, data, nil -} - -// healthUsage displays the usage of the health command and its subcommands. -func healthUsage() { - fmt.Fprintf(os.Stderr, `HealthAPI allows to check if backend data is up-to-date and reliable or not. -Usage: - %[1]s [globalflags] health COMMAND [flags] - -COMMAND: - get-status: Get current backend health status - -Additional help: - %[1]s health COMMAND --help -`, os.Args[0]) -} -func healthGetStatusUsage() { - fmt.Fprintf(os.Stderr, `%[1]s [flags] health get-status - -Get current backend health status - -Example: - %[1]s health get-status -`, os.Args[0]) -} diff --git a/api/gen/grpc/health/client/cli.go b/api/gen/grpc/health/client/cli.go deleted file mode 100644 index 102fa43..0000000 --- a/api/gen/grpc/health/client/cli.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC client CLI support package -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client diff --git a/api/gen/grpc/health/client/client.go b/api/gen/grpc/health/client/client.go deleted file mode 100644 index f1d0b2e..0000000 --- a/api/gen/grpc/health/client/client.go +++ /dev/null @@ -1,53 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC client -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "context" - - healthpb "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - goagrpc "goa.design/goa/v3/grpc" - goapb "goa.design/goa/v3/grpc/pb" - goa "goa.design/goa/v3/pkg" - "google.golang.org/grpc" -) - -// Client lists the service endpoint gRPC clients. -type Client struct { - grpccli healthpb.HealthClient - opts []grpc.CallOption -} - -// NewClient instantiates gRPC client for all the health service servers. -func NewClient(cc *grpc.ClientConn, opts ...grpc.CallOption) *Client { - return &Client{ - grpccli: healthpb.NewHealthClient(cc), - opts: opts, - } -} - -// GetStatus calls the "GetStatus" function in healthpb.HealthClient interface. -func (c *Client) GetStatus() goa.Endpoint { - return func(ctx context.Context, v interface{}) (interface{}, error) { - inv := goagrpc.NewInvoker( - BuildGetStatusFunc(c.grpccli, c.opts...), - nil, - DecodeGetStatusResponse) - res, err := inv.Invoke(ctx, v) - if err != nil { - resp := goagrpc.DecodeError(err) - switch message := resp.(type) { - case *goapb.ErrorResponse: - return nil, goagrpc.NewServiceError(message) - default: - return nil, goa.Fault(err.Error()) - } - } - return res, nil - } -} diff --git a/api/gen/grpc/health/client/encode_decode.go b/api/gen/grpc/health/client/encode_decode.go deleted file mode 100644 index fbe8314..0000000 --- a/api/gen/grpc/health/client/encode_decode.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC client encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "context" - - healthpb "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - goagrpc "goa.design/goa/v3/grpc" - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" -) - -// BuildGetStatusFunc builds the remote method to invoke for "health" service -// "GetStatus" endpoint. -func BuildGetStatusFunc(grpccli healthpb.HealthClient, cliopts ...grpc.CallOption) goagrpc.RemoteFunc { - return func(ctx context.Context, reqpb interface{}, opts ...grpc.CallOption) (interface{}, error) { - for _, opt := range cliopts { - opts = append(opts, opt) - } - if reqpb != nil { - return grpccli.GetStatus(ctx, reqpb.(*healthpb.GetStatusRequest), opts...) - } - return grpccli.GetStatus(ctx, &healthpb.GetStatusRequest{}, opts...) - } -} - -// DecodeGetStatusResponse decodes responses from the health GetStatus endpoint. -func DecodeGetStatusResponse(ctx context.Context, v interface{}, hdr, trlr metadata.MD) (interface{}, error) { - message, ok := v.(*healthpb.GetStatusResponse) - if !ok { - return nil, goagrpc.ErrInvalidType("health", "GetStatus", "*healthpb.GetStatusResponse", v) - } - if err := ValidateGetStatusResponse(message); err != nil { - return nil, err - } - res := NewGetStatusResult(message) - return res, nil -} diff --git a/api/gen/grpc/health/client/types.go b/api/gen/grpc/health/client/types.go deleted file mode 100644 index 94ce14c..0000000 --- a/api/gen/grpc/health/client/types.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC client types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - healthpb "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goa "goa.design/goa/v3/pkg" -) - -// NewProtoGetStatusRequest builds the gRPC request type from the payload of -// the "GetStatus" endpoint of the "health" service. -func NewProtoGetStatusRequest() *healthpb.GetStatusRequest { - message := &healthpb.GetStatusRequest{} - return message -} - -// NewGetStatusResult builds the result type of the "GetStatus" endpoint of the -// "health" service from the gRPC response type. -func NewGetStatusResult(message *healthpb.GetStatusResponse) *health.HealthStatusResponse { - result := &health.HealthStatusResponse{ - S: message.S, - Status: message.Status, - } - if message.Errmsg != "" { - result.Errmsg = &message.Errmsg - } - if message.Data != nil { - result.Data = protobufHealthpbHealthStatusToHealthHealthStatus(message.Data) - } - return result -} - -// ValidateGetStatusResponse runs the validations defined on GetStatusResponse. -func ValidateGetStatusResponse(message *healthpb.GetStatusResponse) (err error) { - if !(message.S == "ok" || message.S == "error" || message.S == "no_data") { - err = goa.MergeErrors(err, goa.InvalidEnumValueError("message.s", message.S, []interface{}{"ok", "error", "no_data"})) - } - return -} - -// ValidateHealthStatus runs the validations defined on HealthStatus. -func ValidateHealthStatus(message *healthpb.HealthStatus) (err error) { - - return -} - -// svcHealthHealthStatusToHealthpbHealthStatus builds a value of type -// *healthpb.HealthStatus from a value of type *health.HealthStatus. -func svcHealthHealthStatusToHealthpbHealthStatus(v *health.HealthStatus) *healthpb.HealthStatus { - if v == nil { - return nil - } - res := &healthpb.HealthStatus{} - - return res -} - -// protobufHealthpbHealthStatusToHealthHealthStatus builds a value of type -// *health.HealthStatus from a value of type *healthpb.HealthStatus. -func protobufHealthpbHealthStatusToHealthHealthStatus(v *healthpb.HealthStatus) *health.HealthStatus { - if v == nil { - return nil - } - res := &health.HealthStatus{} - - return res -} diff --git a/api/gen/grpc/health/pb/goadesign_goagen_health.pb.go b/api/gen/grpc/health/pb/goadesign_goagen_health.pb.go deleted file mode 100644 index 0a0226d..0000000 --- a/api/gen/grpc/health/pb/goadesign_goagen_health.pb.go +++ /dev/null @@ -1,301 +0,0 @@ -// Code generated with goa v3.7.0, DO NOT EDIT. -// -// health protocol buffer definition -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.30.0 -// protoc v4.24.4 -// source: goadesign_goagen_health.proto - -package injective_price_oracle_api_v1pb - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type GetStatusRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetStatusRequest) Reset() { - *x = GetStatusRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_goadesign_goagen_health_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetStatusRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetStatusRequest) ProtoMessage() {} - -func (x *GetStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_goadesign_goagen_health_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetStatusRequest.ProtoReflect.Descriptor instead. -func (*GetStatusRequest) Descriptor() ([]byte, []int) { - return file_goadesign_goagen_health_proto_rawDescGZIP(), []int{0} -} - -type GetStatusResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Status of the response. - S string `protobuf:"bytes,1,opt,name=s,proto3" json:"s,omitempty"` - // Error message. - Errmsg string `protobuf:"bytes,2,opt,name=errmsg,proto3" json:"errmsg,omitempty"` - Data *HealthStatus `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` -} - -func (x *GetStatusResponse) Reset() { - *x = GetStatusResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_goadesign_goagen_health_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetStatusResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetStatusResponse) ProtoMessage() {} - -func (x *GetStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_goadesign_goagen_health_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetStatusResponse.ProtoReflect.Descriptor instead. -func (*GetStatusResponse) Descriptor() ([]byte, []int) { - return file_goadesign_goagen_health_proto_rawDescGZIP(), []int{1} -} - -func (x *GetStatusResponse) GetS() string { - if x != nil { - return x.S - } - return "" -} - -func (x *GetStatusResponse) GetErrmsg() string { - if x != nil { - return x.Errmsg - } - return "" -} - -func (x *GetStatusResponse) GetData() *HealthStatus { - if x != nil { - return x.Data - } - return nil -} - -func (x *GetStatusResponse) GetStatus() string { - if x != nil { - return x.Status - } - return "" -} - -// Status defines the structure for health information -type HealthStatus struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *HealthStatus) Reset() { - *x = HealthStatus{} - if protoimpl.UnsafeEnabled { - mi := &file_goadesign_goagen_health_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HealthStatus) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HealthStatus) ProtoMessage() {} - -func (x *HealthStatus) ProtoReflect() protoreflect.Message { - mi := &file_goadesign_goagen_health_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HealthStatus.ProtoReflect.Descriptor instead. -func (*HealthStatus) Descriptor() ([]byte, []int) { - return file_goadesign_goagen_health_proto_rawDescGZIP(), []int{2} -} - -var File_goadesign_goagen_health_proto protoreflect.FileDescriptor - -var file_goadesign_goagen_health_proto_rawDesc = []byte{ - 0x0a, 0x1d, 0x67, 0x6f, 0x61, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x67, 0x6f, 0x61, 0x67, - 0x65, 0x6e, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x1d, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, - 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x22, 0x12, - 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x92, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x01, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6d, 0x73, 0x67, 0x12, 0x3f, - 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x69, - 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x6f, - 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x0e, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x78, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x12, 0x6e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2f, - 0x2e, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, - 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x30, 0x2e, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x42, 0x22, 0x5a, 0x20, 0x2f, 0x69, 0x6e, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2e, - 0x70, 0x72, 0x69, 0x63, 0x65, 0x2e, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x31, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_goadesign_goagen_health_proto_rawDescOnce sync.Once - file_goadesign_goagen_health_proto_rawDescData = file_goadesign_goagen_health_proto_rawDesc -) - -func file_goadesign_goagen_health_proto_rawDescGZIP() []byte { - file_goadesign_goagen_health_proto_rawDescOnce.Do(func() { - file_goadesign_goagen_health_proto_rawDescData = protoimpl.X.CompressGZIP(file_goadesign_goagen_health_proto_rawDescData) - }) - return file_goadesign_goagen_health_proto_rawDescData -} - -var file_goadesign_goagen_health_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_goadesign_goagen_health_proto_goTypes = []interface{}{ - (*GetStatusRequest)(nil), // 0: injective.price.oracle.api.v1.GetStatusRequest - (*GetStatusResponse)(nil), // 1: injective.price.oracle.api.v1.GetStatusResponse - (*HealthStatus)(nil), // 2: injective.price.oracle.api.v1.HealthStatus -} -var file_goadesign_goagen_health_proto_depIdxs = []int32{ - 2, // 0: injective.price.oracle.api.v1.GetStatusResponse.data:type_name -> injective.price.oracle.api.v1.HealthStatus - 0, // 1: injective.price.oracle.api.v1.Health.GetStatus:input_type -> injective.price.oracle.api.v1.GetStatusRequest - 1, // 2: injective.price.oracle.api.v1.Health.GetStatus:output_type -> injective.price.oracle.api.v1.GetStatusResponse - 2, // [2:3] is the sub-list for method output_type - 1, // [1:2] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_goadesign_goagen_health_proto_init() } -func file_goadesign_goagen_health_proto_init() { - if File_goadesign_goagen_health_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_goadesign_goagen_health_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetStatusRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_goadesign_goagen_health_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetStatusResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_goadesign_goagen_health_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HealthStatus); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_goadesign_goagen_health_proto_rawDesc, - NumEnums: 0, - NumMessages: 3, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_goadesign_goagen_health_proto_goTypes, - DependencyIndexes: file_goadesign_goagen_health_proto_depIdxs, - MessageInfos: file_goadesign_goagen_health_proto_msgTypes, - }.Build() - File_goadesign_goagen_health_proto = out.File - file_goadesign_goagen_health_proto_rawDesc = nil - file_goadesign_goagen_health_proto_goTypes = nil - file_goadesign_goagen_health_proto_depIdxs = nil -} diff --git a/api/gen/grpc/health/pb/goadesign_goagen_health.proto b/api/gen/grpc/health/pb/goadesign_goagen_health.proto deleted file mode 100644 index 5518bb8..0000000 --- a/api/gen/grpc/health/pb/goadesign_goagen_health.proto +++ /dev/null @@ -1,33 +0,0 @@ -// Code generated with goa v3.7.0, DO NOT EDIT. -// -// health protocol buffer definition -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -syntax = "proto3"; - -package injective.price.oracle.api.v1; - -option go_package = "/injective.price.oracle.api.v1pb"; - -// HealthAPI allows to check if backend data is up-to-date and reliable or not. -service Health { - // Get current backend health status - rpc GetStatus (GetStatusRequest) returns (GetStatusResponse); -} - -message GetStatusRequest { -} - -message GetStatusResponse { - // Status of the response. - string s = 1; - // Error message. - string errmsg = 2; - HealthStatus data = 3; - string status = 4; -} -// Status defines the structure for health information -message HealthStatus { -} diff --git a/api/gen/grpc/health/pb/goadesign_goagen_health_grpc.pb.go b/api/gen/grpc/health/pb/goadesign_goagen_health_grpc.pb.go deleted file mode 100644 index cc6aaea..0000000 --- a/api/gen/grpc/health/pb/goadesign_goagen_health_grpc.pb.go +++ /dev/null @@ -1,107 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v4.24.4 -// source: goadesign_goagen_health.proto - -package injective_price_oracle_api_v1pb - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// HealthClient is the client API for Health service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type HealthClient interface { - // Get current backend health status - GetStatus(ctx context.Context, in *GetStatusRequest, opts ...grpc.CallOption) (*GetStatusResponse, error) -} - -type healthClient struct { - cc grpc.ClientConnInterface -} - -func NewHealthClient(cc grpc.ClientConnInterface) HealthClient { - return &healthClient{cc} -} - -func (c *healthClient) GetStatus(ctx context.Context, in *GetStatusRequest, opts ...grpc.CallOption) (*GetStatusResponse, error) { - out := new(GetStatusResponse) - err := c.cc.Invoke(ctx, "/injective.price.oracle.api.v1.Health/GetStatus", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// HealthServer is the server API for Health service. -// All implementations must embed UnimplementedHealthServer -// for forward compatibility -type HealthServer interface { - // Get current backend health status - GetStatus(context.Context, *GetStatusRequest) (*GetStatusResponse, error) - mustEmbedUnimplementedHealthServer() -} - -// UnimplementedHealthServer must be embedded to have forward compatible implementations. -type UnimplementedHealthServer struct { -} - -func (UnimplementedHealthServer) GetStatus(context.Context, *GetStatusRequest) (*GetStatusResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented") -} -func (UnimplementedHealthServer) mustEmbedUnimplementedHealthServer() {} - -// UnsafeHealthServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to HealthServer will -// result in compilation errors. -type UnsafeHealthServer interface { - mustEmbedUnimplementedHealthServer() -} - -func RegisterHealthServer(s grpc.ServiceRegistrar, srv HealthServer) { - s.RegisterService(&Health_ServiceDesc, srv) -} - -func _Health_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetStatusRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(HealthServer).GetStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/injective.price.oracle.api.v1.Health/GetStatus", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HealthServer).GetStatus(ctx, req.(*GetStatusRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Health_ServiceDesc is the grpc.ServiceDesc for Health service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Health_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "injective.price.oracle.api.v1.Health", - HandlerType: (*HealthServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetStatus", - Handler: _Health_GetStatus_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "goadesign_goagen_health.proto", -} diff --git a/api/gen/grpc/health/server/encode_decode.go b/api/gen/grpc/health/server/encode_decode.go deleted file mode 100644 index 059e33d..0000000 --- a/api/gen/grpc/health/server/encode_decode.go +++ /dev/null @@ -1,27 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC server encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goagrpc "goa.design/goa/v3/grpc" - "google.golang.org/grpc/metadata" -) - -// EncodeGetStatusResponse encodes responses from the "health" service -// "GetStatus" endpoint. -func EncodeGetStatusResponse(ctx context.Context, v interface{}, hdr, trlr *metadata.MD) (interface{}, error) { - result, ok := v.(*health.HealthStatusResponse) - if !ok { - return nil, goagrpc.ErrInvalidType("health", "GetStatus", "*health.HealthStatusResponse", v) - } - resp := NewProtoGetStatusResponse(result) - return resp, nil -} diff --git a/api/gen/grpc/health/server/server.go b/api/gen/grpc/health/server/server.go deleted file mode 100644 index 0ee62d7..0000000 --- a/api/gen/grpc/health/server/server.go +++ /dev/null @@ -1,66 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC server -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "errors" - - healthpb "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goagrpc "goa.design/goa/v3/grpc" - goa "goa.design/goa/v3/pkg" - "google.golang.org/grpc/codes" -) - -// Server implements the healthpb.HealthServer interface. -type Server struct { - GetStatusH goagrpc.UnaryHandler - healthpb.UnimplementedHealthServer -} - -// ErrorNamer is an interface implemented by generated error structs that -// exposes the name of the error as defined in the expr. -type ErrorNamer interface { - ErrorName() string -} - -// New instantiates the server struct with the health service endpoints. -func New(e *health.Endpoints, uh goagrpc.UnaryHandler) *Server { - return &Server{ - GetStatusH: NewGetStatusHandler(e.GetStatus, uh), - } -} - -// NewGetStatusHandler creates a gRPC handler which serves the "health" service -// "GetStatus" endpoint. -func NewGetStatusHandler(endpoint goa.Endpoint, h goagrpc.UnaryHandler) goagrpc.UnaryHandler { - if h == nil { - h = goagrpc.NewUnaryHandler(endpoint, nil, EncodeGetStatusResponse) - } - return h -} - -// GetStatus implements the "GetStatus" method in healthpb.HealthServer -// interface. -func (s *Server) GetStatus(ctx context.Context, message *healthpb.GetStatusRequest) (*healthpb.GetStatusResponse, error) { - ctx = context.WithValue(ctx, goa.MethodKey, "GetStatus") - ctx = context.WithValue(ctx, goa.ServiceKey, "health") - resp, err := s.GetStatusH.Handle(ctx, message) - if err != nil { - var en ErrorNamer - if errors.As(err, &en) { - switch en.ErrorName() { - case "internal": - return nil, goagrpc.NewStatusError(codes.Internal, err, goagrpc.NewErrorResponse(err)) - } - } - return nil, goagrpc.EncodeError(err) - } - return resp.(*healthpb.GetStatusResponse), nil -} diff --git a/api/gen/grpc/health/server/types.go b/api/gen/grpc/health/server/types.go deleted file mode 100644 index a080b53..0000000 --- a/api/gen/grpc/health/server/types.go +++ /dev/null @@ -1,51 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health gRPC server types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - healthpb "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" -) - -// NewProtoGetStatusResponse builds the gRPC response type from the result of -// the "GetStatus" endpoint of the "health" service. -func NewProtoGetStatusResponse(result *health.HealthStatusResponse) *healthpb.GetStatusResponse { - message := &healthpb.GetStatusResponse{ - S: result.S, - Status: result.Status, - } - if result.Errmsg != nil { - message.Errmsg = *result.Errmsg - } - if result.Data != nil { - message.Data = svcHealthHealthStatusToHealthpbHealthStatus(result.Data) - } - return message -} - -// svcHealthHealthStatusToHealthpbHealthStatus builds a value of type -// *healthpb.HealthStatus from a value of type *health.HealthStatus. -func svcHealthHealthStatusToHealthpbHealthStatus(v *health.HealthStatus) *healthpb.HealthStatus { - if v == nil { - return nil - } - res := &healthpb.HealthStatus{} - - return res -} - -// protobufHealthpbHealthStatusToHealthHealthStatus builds a value of type -// *health.HealthStatus from a value of type *healthpb.HealthStatus. -func protobufHealthpbHealthStatusToHealthHealthStatus(v *healthpb.HealthStatus) *health.HealthStatus { - if v == nil { - return nil - } - res := &health.HealthStatus{} - - return res -} diff --git a/api/gen/health/client.go b/api/gen/health/client.go deleted file mode 100644 index 1a84bdf..0000000 --- a/api/gen/health/client.go +++ /dev/null @@ -1,36 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health client -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package health - -import ( - "context" - - goa "goa.design/goa/v3/pkg" -) - -// Client is the "health" service client. -type Client struct { - GetStatusEndpoint goa.Endpoint -} - -// NewClient initializes a "health" service client given the endpoints. -func NewClient(getStatus goa.Endpoint) *Client { - return &Client{ - GetStatusEndpoint: getStatus, - } -} - -// GetStatus calls the "GetStatus" endpoint of the "health" service. -func (c *Client) GetStatus(ctx context.Context) (res *HealthStatusResponse, err error) { - var ires interface{} - ires, err = c.GetStatusEndpoint(ctx, nil) - if err != nil { - return - } - return ires.(*HealthStatusResponse), nil -} diff --git a/api/gen/health/endpoints.go b/api/gen/health/endpoints.go deleted file mode 100644 index 0a90f6f..0000000 --- a/api/gen/health/endpoints.go +++ /dev/null @@ -1,39 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health endpoints -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package health - -import ( - "context" - - goa "goa.design/goa/v3/pkg" -) - -// Endpoints wraps the "health" service endpoints. -type Endpoints struct { - GetStatus goa.Endpoint -} - -// NewEndpoints wraps the methods of the "health" service with endpoints. -func NewEndpoints(s Service) *Endpoints { - return &Endpoints{ - GetStatus: NewGetStatusEndpoint(s), - } -} - -// Use applies the given middleware to all the "health" service endpoints. -func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { - e.GetStatus = m(e.GetStatus) -} - -// NewGetStatusEndpoint returns an endpoint function that calls the method -// "GetStatus" of service "health". -func NewGetStatusEndpoint(s Service) goa.Endpoint { - return func(ctx context.Context, req interface{}) (interface{}, error) { - return s.GetStatus(ctx) - } -} diff --git a/api/gen/health/service.go b/api/gen/health/service.go deleted file mode 100644 index 890ba6f..0000000 --- a/api/gen/health/service.go +++ /dev/null @@ -1,54 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health service -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package health - -import ( - "context" - - goa "goa.design/goa/v3/pkg" -) - -// HealthAPI allows to check if backend data is up-to-date and reliable or not. -type Service interface { - // Get current backend health status - GetStatus(context.Context) (res *HealthStatusResponse, err error) -} - -// ServiceName is the name of the service as defined in the design. This is the -// same value that is set in the endpoint request contexts under the ServiceKey -// key. -const ServiceName = "health" - -// MethodNames lists the service method names as defined in the design. These -// are the same values that are set in the endpoint request contexts under the -// MethodKey key. -var MethodNames = [1]string{"GetStatus"} - -// Status defines the structure for health information -type HealthStatus struct { -} - -// HealthStatusResponse is the result type of the health service GetStatus -// method. -type HealthStatusResponse struct { - // Status of the response. - S string - // Error message. - Errmsg *string - Data *HealthStatus - Status string -} - -// MakeInternal builds a goa.ServiceError from an error. -func MakeInternal(err error) *goa.ServiceError { - return &goa.ServiceError{ - Name: "internal", - ID: goa.NewErrorID(), - Message: err.Error(), - } -} diff --git a/api/gen/http/cli/price_oracle/cli.go b/api/gen/http/cli/price_oracle/cli.go deleted file mode 100644 index 7b17ae8..0000000 --- a/api/gen/http/cli/price_oracle/cli.go +++ /dev/null @@ -1,207 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// PriceOracle HTTP client CLI support package -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package cli - -import ( - "flag" - "fmt" - "net/http" - "os" - - healthc "github.com/InjectiveLabs/injective-price-oracle/api/gen/http/health/client" - injectivepriceoracleapic "github.com/InjectiveLabs/injective-price-oracle/api/gen/http/injective_price_oracle_api/client" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" -) - -// UsageCommands returns the set of commands and sub-commands using the format -// -// command (subcommand1|subcommand2|...) -func UsageCommands() string { - return `injective-price-oracle-api probe -health get-status -` -} - -// UsageExamples produces an example of a valid invocation of the CLI tool. -func UsageExamples() string { - return os.Args[0] + ` injective-price-oracle-api probe --body '{ - "content": "RmFjaWxpcyBvZmZpY2lpcy4=" - }' --key "Atque omnis."` + "\n" + - os.Args[0] + ` health get-status` + "\n" + - "" -} - -// ParseEndpoint returns the endpoint and payload as specified on the command -// line. -func ParseEndpoint( - scheme, host string, - doer goahttp.Doer, - enc func(*http.Request) goahttp.Encoder, - dec func(*http.Response) goahttp.Decoder, - restore bool, - injectivePriceOracleAPIProbeEncoderFn injectivepriceoracleapic.InjectivePriceOracleAPIProbeEncoderFunc, -) (goa.Endpoint, interface{}, error) { - var ( - injectivePriceOracleAPIFlags = flag.NewFlagSet("injective-price-oracle-api", flag.ContinueOnError) - - injectivePriceOracleAPIProbeFlags = flag.NewFlagSet("probe", flag.ExitOnError) - injectivePriceOracleAPIProbeBodyFlag = injectivePriceOracleAPIProbeFlags.String("body", "REQUIRED", "") - injectivePriceOracleAPIProbeKeyFlag = injectivePriceOracleAPIProbeFlags.String("key", "", "") - - healthFlags = flag.NewFlagSet("health", flag.ContinueOnError) - - healthGetStatusFlags = flag.NewFlagSet("get-status", flag.ExitOnError) - ) - injectivePriceOracleAPIFlags.Usage = injectivePriceOracleAPIUsage - injectivePriceOracleAPIProbeFlags.Usage = injectivePriceOracleAPIProbeUsage - - healthFlags.Usage = healthUsage - healthGetStatusFlags.Usage = healthGetStatusUsage - - if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { - return nil, nil, err - } - - if flag.NArg() < 2 { // two non flag args are required: SERVICE and ENDPOINT (aka COMMAND) - return nil, nil, fmt.Errorf("not enough arguments") - } - - var ( - svcn string - svcf *flag.FlagSet - ) - { - svcn = flag.Arg(0) - switch svcn { - case "injective-price-oracle-api": - svcf = injectivePriceOracleAPIFlags - case "health": - svcf = healthFlags - default: - return nil, nil, fmt.Errorf("unknown service %q", svcn) - } - } - if err := svcf.Parse(flag.Args()[1:]); err != nil { - return nil, nil, err - } - - var ( - epn string - epf *flag.FlagSet - ) - { - epn = svcf.Arg(0) - switch svcn { - case "injective-price-oracle-api": - switch epn { - case "probe": - epf = injectivePriceOracleAPIProbeFlags - - } - - case "health": - switch epn { - case "get-status": - epf = healthGetStatusFlags - - } - - } - } - if epf == nil { - return nil, nil, fmt.Errorf("unknown %q endpoint %q", svcn, epn) - } - - // Parse endpoint flags if any - if svcf.NArg() > 1 { - if err := epf.Parse(svcf.Args()[1:]); err != nil { - return nil, nil, err - } - } - - var ( - data interface{} - endpoint goa.Endpoint - err error - ) - { - switch svcn { - case "injective-price-oracle-api": - c := injectivepriceoracleapic.NewClient(scheme, host, doer, enc, dec, restore) - switch epn { - case "probe": - endpoint = c.Probe(injectivePriceOracleAPIProbeEncoderFn) - data, err = injectivepriceoracleapic.BuildProbePayload(*injectivePriceOracleAPIProbeBodyFlag, *injectivePriceOracleAPIProbeKeyFlag) - } - case "health": - c := healthc.NewClient(scheme, host, doer, enc, dec, restore) - switch epn { - case "get-status": - endpoint = c.GetStatus() - data = nil - } - } - } - if err != nil { - return nil, nil, err - } - - return endpoint, data, nil -} - -// injective-price-oracle-apiUsage displays the usage of the -// injective-price-oracle-api command and its subcommands. -func injectivePriceOracleAPIUsage() { - fmt.Fprintf(os.Stderr, `Injective-Price-Oracle services API doc -Usage: - %[1]s [globalflags] injective-price-oracle-api COMMAND [flags] - -COMMAND: - probe: Validate TOML file - -Additional help: - %[1]s injective-price-oracle-api COMMAND --help -`, os.Args[0]) -} -func injectivePriceOracleAPIProbeUsage() { - fmt.Fprintf(os.Stderr, `%[1]s [flags] injective-price-oracle-api probe -body JSON -key STRING - -Validate TOML file - -body JSON: - -key STRING: - -Example: - %[1]s injective-price-oracle-api probe --body '{ - "content": "RmFjaWxpcyBvZmZpY2lpcy4=" - }' --key "Atque omnis." -`, os.Args[0]) -} - -// healthUsage displays the usage of the health command and its subcommands. -func healthUsage() { - fmt.Fprintf(os.Stderr, `HealthAPI allows to check if backend data is up-to-date and reliable or not. -Usage: - %[1]s [globalflags] health COMMAND [flags] - -COMMAND: - get-status: Get current backend health status - -Additional help: - %[1]s health COMMAND --help -`, os.Args[0]) -} -func healthGetStatusUsage() { - fmt.Fprintf(os.Stderr, `%[1]s [flags] health get-status - -Get current backend health status - -Example: - %[1]s health get-status -`, os.Args[0]) -} diff --git a/api/gen/http/health/client/cli.go b/api/gen/http/health/client/cli.go deleted file mode 100644 index 0d51a6c..0000000 --- a/api/gen/http/health/client/cli.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP client CLI support package -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client diff --git a/api/gen/http/health/client/client.go b/api/gen/http/health/client/client.go deleted file mode 100644 index 3db9f74..0000000 --- a/api/gen/http/health/client/client.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health client HTTP transport -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "context" - "net/http" - - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" -) - -// Client lists the health service endpoint HTTP clients. -type Client struct { - // GetStatus Doer is the HTTP client used to make requests to the GetStatus - // endpoint. - GetStatusDoer goahttp.Doer - - // CORS Doer is the HTTP client used to make requests to the endpoint. - CORSDoer goahttp.Doer - - // RestoreResponseBody controls whether the response bodies are reset after - // decoding so they can be read again. - RestoreResponseBody bool - - scheme string - host string - encoder func(*http.Request) goahttp.Encoder - decoder func(*http.Response) goahttp.Decoder -} - -// NewClient instantiates HTTP clients for all the health service servers. -func NewClient( - scheme string, - host string, - doer goahttp.Doer, - enc func(*http.Request) goahttp.Encoder, - dec func(*http.Response) goahttp.Decoder, - restoreBody bool, -) *Client { - return &Client{ - GetStatusDoer: doer, - CORSDoer: doer, - RestoreResponseBody: restoreBody, - scheme: scheme, - host: host, - decoder: dec, - encoder: enc, - } -} - -// GetStatus returns an endpoint that makes HTTP requests to the health service -// GetStatus server. -func (c *Client) GetStatus() goa.Endpoint { - var ( - decodeResponse = DecodeGetStatusResponse(c.decoder, c.RestoreResponseBody) - ) - return func(ctx context.Context, v interface{}) (interface{}, error) { - req, err := c.BuildGetStatusRequest(ctx, v) - if err != nil { - return nil, err - } - resp, err := c.GetStatusDoer.Do(req) - if err != nil { - return nil, goahttp.ErrRequestError("health", "GetStatus", err) - } - return decodeResponse(resp) - } -} diff --git a/api/gen/http/health/client/encode_decode.go b/api/gen/http/health/client/encode_decode.go deleted file mode 100644 index 16ca3c8..0000000 --- a/api/gen/http/health/client/encode_decode.go +++ /dev/null @@ -1,102 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP client encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "bytes" - "context" - "io/ioutil" - "net/http" - "net/url" - - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goahttp "goa.design/goa/v3/http" -) - -// BuildGetStatusRequest instantiates a HTTP request object with method and -// path set to call the "health" service "GetStatus" endpoint -func (c *Client) BuildGetStatusRequest(ctx context.Context, v interface{}) (*http.Request, error) { - u := &url.URL{Scheme: c.scheme, Host: c.host, Path: GetStatusHealthPath()} - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return nil, goahttp.ErrInvalidURL("health", "GetStatus", u.String(), err) - } - if ctx != nil { - req = req.WithContext(ctx) - } - - return req, nil -} - -// DecodeGetStatusResponse returns a decoder for responses returned by the -// health GetStatus endpoint. restoreBody controls whether the response body -// should be restored after having been read. -// DecodeGetStatusResponse may return the following errors: -// - "internal" (type *goa.ServiceError): http.StatusInternalServerError -// - error: internal error -func DecodeGetStatusResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { - return func(resp *http.Response) (interface{}, error) { - if restoreBody { - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - defer func() { - resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - }() - } else { - defer resp.Body.Close() - } - switch resp.StatusCode { - case http.StatusOK: - var ( - body GetStatusResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("health", "GetStatus", err) - } - err = ValidateGetStatusResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("health", "GetStatus", err) - } - res := NewGetStatusHealthStatusResponseOK(&body) - return res, nil - case http.StatusInternalServerError: - var ( - body GetStatusInternalResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("health", "GetStatus", err) - } - err = ValidateGetStatusInternalResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("health", "GetStatus", err) - } - return nil, NewGetStatusInternal(&body) - default: - body, _ := ioutil.ReadAll(resp.Body) - return nil, goahttp.ErrInvalidResponse("health", "GetStatus", resp.StatusCode, string(body)) - } - } -} - -// unmarshalHealthStatusResponseBodyToHealthHealthStatus builds a value of type -// *health.HealthStatus from a value of type *HealthStatusResponseBody. -func unmarshalHealthStatusResponseBodyToHealthHealthStatus(v *HealthStatusResponseBody) *health.HealthStatus { - if v == nil { - return nil - } - res := &health.HealthStatus{} - - return res -} diff --git a/api/gen/http/health/client/paths.go b/api/gen/http/health/client/paths.go deleted file mode 100644 index a2194e4..0000000 --- a/api/gen/http/health/client/paths.go +++ /dev/null @@ -1,13 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the health service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -// GetStatusHealthPath returns the URL path to the health service GetStatus HTTP endpoint. -func GetStatusHealthPath() string { - return "/api/health/v1/status" -} diff --git a/api/gen/http/health/client/types.go b/api/gen/http/health/client/types.go deleted file mode 100644 index c375d66..0000000 --- a/api/gen/http/health/client/types.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP client types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goa "goa.design/goa/v3/pkg" -) - -// GetStatusResponseBody is the type of the "health" service "GetStatus" -// endpoint HTTP response body. -type GetStatusResponseBody struct { - // Status of the response. - S *string `form:"s,omitempty" json:"s,omitempty" xml:"s,omitempty"` - // Error message. - Errmsg *string `form:"errmsg,omitempty" json:"errmsg,omitempty" xml:"errmsg,omitempty"` - Data *HealthStatusResponseBody `form:"data,omitempty" json:"data,omitempty" xml:"data,omitempty"` - Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` -} - -// GetStatusInternalResponseBody is the type of the "health" service -// "GetStatus" endpoint HTTP response body for the "internal" error. -type GetStatusInternalResponseBody struct { - // Name is the name of this class of errors. - Name *string `form:"name,omitempty" json:"name,omitempty" xml:"name,omitempty"` - // ID is a unique identifier for this particular occurrence of the problem. - ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message *string `form:"message,omitempty" json:"message,omitempty" xml:"message,omitempty"` - // Is the error temporary? - Temporary *bool `form:"temporary,omitempty" json:"temporary,omitempty" xml:"temporary,omitempty"` - // Is the error a timeout? - Timeout *bool `form:"timeout,omitempty" json:"timeout,omitempty" xml:"timeout,omitempty"` - // Is the error a server-side fault? - Fault *bool `form:"fault,omitempty" json:"fault,omitempty" xml:"fault,omitempty"` -} - -// HealthStatusResponseBody is used to define fields on response body types. -type HealthStatusResponseBody struct { -} - -// NewGetStatusHealthStatusResponseOK builds a "health" service "GetStatus" -// endpoint result from a HTTP "OK" response. -func NewGetStatusHealthStatusResponseOK(body *GetStatusResponseBody) *health.HealthStatusResponse { - v := &health.HealthStatusResponse{ - S: *body.S, - Errmsg: body.Errmsg, - Status: *body.Status, - } - if body.Data != nil { - v.Data = unmarshalHealthStatusResponseBodyToHealthHealthStatus(body.Data) - } - - return v -} - -// NewGetStatusInternal builds a health service GetStatus endpoint internal -// error. -func NewGetStatusInternal(body *GetStatusInternalResponseBody) *goa.ServiceError { - v := &goa.ServiceError{ - Name: *body.Name, - ID: *body.ID, - Message: *body.Message, - Temporary: *body.Temporary, - Timeout: *body.Timeout, - Fault: *body.Fault, - } - - return v -} - -// ValidateGetStatusResponseBody runs the validations defined on -// GetStatusResponseBody -func ValidateGetStatusResponseBody(body *GetStatusResponseBody) (err error) { - if body.S == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("s", "body")) - } - if body.Status == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("status", "body")) - } - if body.S != nil { - if !(*body.S == "ok" || *body.S == "error" || *body.S == "no_data") { - err = goa.MergeErrors(err, goa.InvalidEnumValueError("body.s", *body.S, []interface{}{"ok", "error", "no_data"})) - } - } - return -} - -// ValidateGetStatusInternalResponseBody runs the validations defined on -// GetStatus_internal_Response_Body -func ValidateGetStatusInternalResponseBody(body *GetStatusInternalResponseBody) (err error) { - if body.Name == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("name", "body")) - } - if body.ID == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) - } - if body.Message == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("message", "body")) - } - if body.Temporary == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("temporary", "body")) - } - if body.Timeout == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("timeout", "body")) - } - if body.Fault == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("fault", "body")) - } - return -} diff --git a/api/gen/http/health/server/encode_decode.go b/api/gen/http/health/server/encode_decode.go deleted file mode 100644 index 47bd119..0000000 --- a/api/gen/http/health/server/encode_decode.go +++ /dev/null @@ -1,70 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP server encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "errors" - "net/http" - - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" -) - -// EncodeGetStatusResponse returns an encoder for responses returned by the -// health GetStatus endpoint. -func EncodeGetStatusResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { - return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { - res, _ := v.(*health.HealthStatusResponse) - enc := encoder(ctx, w) - body := NewGetStatusResponseBody(res) - w.WriteHeader(http.StatusOK) - return enc.Encode(body) - } -} - -// EncodeGetStatusError returns an encoder for errors returned by the GetStatus -// health endpoint. -func EncodeGetStatusError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error { - encodeError := goahttp.ErrorEncoder(encoder, formatter) - return func(ctx context.Context, w http.ResponseWriter, v error) error { - var en ErrorNamer - if !errors.As(v, &en) { - return encodeError(ctx, w, v) - } - switch en.ErrorName() { - case "internal": - var res *goa.ServiceError - errors.As(v, &res) - enc := encoder(ctx, w) - var body interface{} - if formatter != nil { - body = formatter(res) - } else { - body = NewGetStatusInternalResponseBody(res) - } - w.Header().Set("goa-error", res.ErrorName()) - w.WriteHeader(http.StatusInternalServerError) - return enc.Encode(body) - default: - return encodeError(ctx, w, v) - } - } -} - -// marshalHealthHealthStatusToHealthStatusResponseBody builds a value of type -// *HealthStatusResponseBody from a value of type *health.HealthStatus. -func marshalHealthHealthStatusToHealthStatusResponseBody(v *health.HealthStatus) *HealthStatusResponseBody { - if v == nil { - return nil - } - res := &HealthStatusResponseBody{} - - return res -} diff --git a/api/gen/http/health/server/paths.go b/api/gen/http/health/server/paths.go deleted file mode 100644 index e44caba..0000000 --- a/api/gen/http/health/server/paths.go +++ /dev/null @@ -1,13 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the health service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -// GetStatusHealthPath returns the URL path to the health service GetStatus HTTP endpoint. -func GetStatusHealthPath() string { - return "/api/health/v1/status" -} diff --git a/api/gen/http/health/server/server.go b/api/gen/http/health/server/server.go deleted file mode 100644 index 6ae5c45..0000000 --- a/api/gen/http/health/server/server.go +++ /dev/null @@ -1,170 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP server -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "net/http" - - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" - "goa.design/plugins/v3/cors" -) - -// Server lists the health service endpoint HTTP handlers. -type Server struct { - Mounts []*MountPoint - GetStatus http.Handler - CORS http.Handler -} - -// ErrorNamer is an interface implemented by generated error structs that -// exposes the name of the error as defined in the design. -type ErrorNamer interface { - ErrorName() string -} - -// MountPoint holds information about the mounted endpoints. -type MountPoint struct { - // Method is the name of the service method served by the mounted HTTP handler. - Method string - // Verb is the HTTP method used to match requests to the mounted handler. - Verb string - // Pattern is the HTTP request path pattern used to match requests to the - // mounted handler. - Pattern string -} - -// New instantiates HTTP handlers for all the health service endpoints using -// the provided encoder and decoder. The handlers are mounted on the given mux -// using the HTTP verb and path defined in the design. errhandler is called -// whenever a response fails to be encoded. formatter is used to format errors -// returned by the service methods prior to encoding. Both errhandler and -// formatter are optional and can be nil. -func New( - e *health.Endpoints, - mux goahttp.Muxer, - decoder func(*http.Request) goahttp.Decoder, - encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, - errhandler func(context.Context, http.ResponseWriter, error), - formatter func(err error) goahttp.Statuser, -) *Server { - return &Server{ - Mounts: []*MountPoint{ - {"GetStatus", "GET", "/api/health/v1/status"}, - {"CORS", "OPTIONS", "/api/health/v1/status"}, - }, - GetStatus: NewGetStatusHandler(e.GetStatus, mux, decoder, encoder, errhandler, formatter), - CORS: NewCORSHandler(), - } -} - -// Service returns the name of the service served. -func (s *Server) Service() string { return "health" } - -// Use wraps the server handlers with the given middleware. -func (s *Server) Use(m func(http.Handler) http.Handler) { - s.GetStatus = m(s.GetStatus) - s.CORS = m(s.CORS) -} - -// Mount configures the mux to serve the health endpoints. -func Mount(mux goahttp.Muxer, h *Server) { - MountGetStatusHandler(mux, h.GetStatus) - MountCORSHandler(mux, h.CORS) -} - -// Mount configures the mux to serve the health endpoints. -func (s *Server) Mount(mux goahttp.Muxer) { - Mount(mux, s) -} - -// MountGetStatusHandler configures the mux to serve the "health" service -// "GetStatus" endpoint. -func MountGetStatusHandler(mux goahttp.Muxer, h http.Handler) { - f, ok := HandleHealthOrigin(h).(http.HandlerFunc) - if !ok { - f = func(w http.ResponseWriter, r *http.Request) { - h.ServeHTTP(w, r) - } - } - mux.Handle("GET", "/api/health/v1/status", f) -} - -// NewGetStatusHandler creates a HTTP handler which loads the HTTP request and -// calls the "health" service "GetStatus" endpoint. -func NewGetStatusHandler( - endpoint goa.Endpoint, - mux goahttp.Muxer, - decoder func(*http.Request) goahttp.Decoder, - encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, - errhandler func(context.Context, http.ResponseWriter, error), - formatter func(err error) goahttp.Statuser, -) http.Handler { - var ( - encodeResponse = EncodeGetStatusResponse(encoder) - encodeError = EncodeGetStatusError(encoder, formatter) - ) - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) - ctx = context.WithValue(ctx, goa.MethodKey, "GetStatus") - ctx = context.WithValue(ctx, goa.ServiceKey, "health") - var err error - res, err := endpoint(ctx, nil) - if err != nil { - if err := encodeError(ctx, w, err); err != nil { - errhandler(ctx, w, err) - } - return - } - if err := encodeResponse(ctx, w, res); err != nil { - errhandler(ctx, w, err) - } - }) -} - -// MountCORSHandler configures the mux to serve the CORS endpoints for the -// service health. -func MountCORSHandler(mux goahttp.Muxer, h http.Handler) { - h = HandleHealthOrigin(h) - mux.Handle("OPTIONS", "/api/health/v1/status", h.ServeHTTP) -} - -// NewCORSHandler creates a HTTP handler which returns a simple 200 response. -func NewCORSHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - }) -} - -// HandleHealthOrigin applies the CORS response headers corresponding to the -// origin for the service health. -func HandleHealthOrigin(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - origin := r.Header.Get("Origin") - if origin == "" { - // Not a CORS request - h.ServeHTTP(w, r) - return - } - if cors.MatchOrigin(origin, "*") { - w.Header().Set("Access-Control-Allow-Origin", origin) - w.Header().Set("Vary", "Origin") - if acrm := r.Header.Get("Access-Control-Request-Method"); acrm != "" { - // We are handling a preflight request - w.Header().Set("Access-Control-Allow-Methods", "GET") - w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - } - h.ServeHTTP(w, r) - return - } - h.ServeHTTP(w, r) - return - }) -} diff --git a/api/gen/http/health/server/types.go b/api/gen/http/health/server/types.go deleted file mode 100644 index 8207d7d..0000000 --- a/api/gen/http/health/server/types.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// health HTTP server types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - health "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - goa "goa.design/goa/v3/pkg" -) - -// GetStatusResponseBody is the type of the "health" service "GetStatus" -// endpoint HTTP response body. -type GetStatusResponseBody struct { - // Status of the response. - S string `form:"s" json:"s" xml:"s"` - // Error message. - Errmsg *string `form:"errmsg,omitempty" json:"errmsg,omitempty" xml:"errmsg,omitempty"` - Data *HealthStatusResponseBody `form:"data,omitempty" json:"data,omitempty" xml:"data,omitempty"` - Status string `form:"status" json:"status" xml:"status"` -} - -// GetStatusInternalResponseBody is the type of the "health" service -// "GetStatus" endpoint HTTP response body for the "internal" error. -type GetStatusInternalResponseBody struct { - // Name is the name of this class of errors. - Name string `form:"name" json:"name" xml:"name"` - // ID is a unique identifier for this particular occurrence of the problem. - ID string `form:"id" json:"id" xml:"id"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message string `form:"message" json:"message" xml:"message"` - // Is the error temporary? - Temporary bool `form:"temporary" json:"temporary" xml:"temporary"` - // Is the error a timeout? - Timeout bool `form:"timeout" json:"timeout" xml:"timeout"` - // Is the error a server-side fault? - Fault bool `form:"fault" json:"fault" xml:"fault"` -} - -// HealthStatusResponseBody is used to define fields on response body types. -type HealthStatusResponseBody struct { -} - -// NewGetStatusResponseBody builds the HTTP response body from the result of -// the "GetStatus" endpoint of the "health" service. -func NewGetStatusResponseBody(res *health.HealthStatusResponse) *GetStatusResponseBody { - body := &GetStatusResponseBody{ - S: res.S, - Errmsg: res.Errmsg, - Status: res.Status, - } - if res.Data != nil { - body.Data = marshalHealthHealthStatusToHealthStatusResponseBody(res.Data) - } - return body -} - -// NewGetStatusInternalResponseBody builds the HTTP response body from the -// result of the "GetStatus" endpoint of the "health" service. -func NewGetStatusInternalResponseBody(res *goa.ServiceError) *GetStatusInternalResponseBody { - body := &GetStatusInternalResponseBody{ - Name: res.Name, - ID: res.ID, - Message: res.Message, - Temporary: res.Temporary, - Timeout: res.Timeout, - Fault: res.Fault, - } - return body -} diff --git a/api/gen/http/injective_price_oracle_api/client/cli.go b/api/gen/http/injective_price_oracle_api/client/cli.go deleted file mode 100644 index bb8febe..0000000 --- a/api/gen/http/injective_price_oracle_api/client/cli.go +++ /dev/null @@ -1,47 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP client CLI support package -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "encoding/json" - "fmt" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goa "goa.design/goa/v3/pkg" -) - -// BuildProbePayload builds the payload for the Injective Price Oracle API -// probe endpoint from CLI flags. -func BuildProbePayload(injectivePriceOracleAPIProbeBody string, injectivePriceOracleAPIProbeKey string) (*injectivepriceoracleapi.ProbePayload, error) { - var err error - var body ProbeRequestBody - { - err = json.Unmarshal([]byte(injectivePriceOracleAPIProbeBody), &body) - if err != nil { - return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"content\": \"RmFjaWxpcyBvZmZpY2lpcy4=\"\n }'") - } - if body.Content == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("content", "body")) - } - if err != nil { - return nil, err - } - } - var key *string - { - if injectivePriceOracleAPIProbeKey != "" { - key = &injectivePriceOracleAPIProbeKey - } - } - v := &injectivepriceoracleapi.ProbePayload{ - Content: body.Content, - } - v.Key = key - - return v, nil -} diff --git a/api/gen/http/injective_price_oracle_api/client/client.go b/api/gen/http/injective_price_oracle_api/client/client.go deleted file mode 100644 index cae8deb..0000000 --- a/api/gen/http/injective_price_oracle_api/client/client.go +++ /dev/null @@ -1,85 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API client HTTP transport -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "context" - "mime/multipart" - "net/http" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" -) - -// Client lists the Injective Price Oracle API service endpoint HTTP clients. -type Client struct { - // Probe Doer is the HTTP client used to make requests to the probe endpoint. - ProbeDoer goahttp.Doer - - // CORS Doer is the HTTP client used to make requests to the endpoint. - CORSDoer goahttp.Doer - - // RestoreResponseBody controls whether the response bodies are reset after - // decoding so they can be read again. - RestoreResponseBody bool - - scheme string - host string - encoder func(*http.Request) goahttp.Encoder - decoder func(*http.Response) goahttp.Decoder -} - -// InjectivePriceOracleAPIProbeEncoderFunc is the type to encode multipart -// request for the "Injective Price Oracle API" service "probe" endpoint. -type InjectivePriceOracleAPIProbeEncoderFunc func(*multipart.Writer, *injectivepriceoracleapi.ProbePayload) error - -// NewClient instantiates HTTP clients for all the Injective Price Oracle API -// service servers. -func NewClient( - scheme string, - host string, - doer goahttp.Doer, - enc func(*http.Request) goahttp.Encoder, - dec func(*http.Response) goahttp.Decoder, - restoreBody bool, -) *Client { - return &Client{ - ProbeDoer: doer, - CORSDoer: doer, - RestoreResponseBody: restoreBody, - scheme: scheme, - host: host, - decoder: dec, - encoder: enc, - } -} - -// Probe returns an endpoint that makes HTTP requests to the Injective Price -// Oracle API service probe server. -func (c *Client) Probe(injectivePriceOracleAPIProbeEncoderFn InjectivePriceOracleAPIProbeEncoderFunc) goa.Endpoint { - var ( - encodeRequest = EncodeProbeRequest(NewInjectivePriceOracleAPIProbeEncoder(injectivePriceOracleAPIProbeEncoderFn)) - decodeResponse = DecodeProbeResponse(c.decoder, c.RestoreResponseBody) - ) - return func(ctx context.Context, v interface{}) (interface{}, error) { - req, err := c.BuildProbeRequest(ctx, v) - if err != nil { - return nil, err - } - err = encodeRequest(req, v) - if err != nil { - return nil, err - } - resp, err := c.ProbeDoer.Do(req) - if err != nil { - return nil, goahttp.ErrRequestError("Injective Price Oracle API", "probe", err) - } - return decodeResponse(resp) - } -} diff --git a/api/gen/http/injective_price_oracle_api/client/encode_decode.go b/api/gen/http/injective_price_oracle_api/client/encode_decode.go deleted file mode 100644 index 8fd03c5..0000000 --- a/api/gen/http/injective_price_oracle_api/client/encode_decode.go +++ /dev/null @@ -1,160 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP client encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "bytes" - "context" - "io/ioutil" - "mime/multipart" - "net/http" - "net/url" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goahttp "goa.design/goa/v3/http" -) - -// BuildProbeRequest instantiates a HTTP request object with method and path -// set to call the "Injective Price Oracle API" service "probe" endpoint -func (c *Client) BuildProbeRequest(ctx context.Context, v interface{}) (*http.Request, error) { - u := &url.URL{Scheme: c.scheme, Host: c.host, Path: ProbeInjectivePriceOracleAPIPath()} - req, err := http.NewRequest("POST", u.String(), nil) - if err != nil { - return nil, goahttp.ErrInvalidURL("Injective Price Oracle API", "probe", u.String(), err) - } - if ctx != nil { - req = req.WithContext(ctx) - } - - return req, nil -} - -// EncodeProbeRequest returns an encoder for requests sent to the Injective -// Price Oracle API probe server. -func EncodeProbeRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error { - return func(req *http.Request, v interface{}) error { - p, ok := v.(*injectivepriceoracleapi.ProbePayload) - if !ok { - return goahttp.ErrInvalidType("Injective Price Oracle API", "probe", "*injectivepriceoracleapi.ProbePayload", v) - } - if p.Key != nil { - head := *p.Key - req.Header.Set("X-Api-Key", head) - } - if err := encoder(req).Encode(p); err != nil { - return goahttp.ErrEncodingError("Injective Price Oracle API", "probe", err) - } - return nil - } -} - -// NewInjectivePriceOracleAPIProbeEncoder returns an encoder to encode the -// multipart request for the "Injective Price Oracle API" service "probe" -// endpoint. -func NewInjectivePriceOracleAPIProbeEncoder(encoderFn InjectivePriceOracleAPIProbeEncoderFunc) func(r *http.Request) goahttp.Encoder { - return func(r *http.Request) goahttp.Encoder { - body := &bytes.Buffer{} - mw := multipart.NewWriter(body) - return goahttp.EncodingFunc(func(v interface{}) error { - p := v.(*injectivepriceoracleapi.ProbePayload) - if err := encoderFn(mw, p); err != nil { - return err - } - r.Body = ioutil.NopCloser(body) - r.Header.Set("Content-Type", mw.FormDataContentType()) - return mw.Close() - }) - } -} - -// DecodeProbeResponse returns a decoder for responses returned by the -// Injective Price Oracle API probe endpoint. restoreBody controls whether the -// response body should be restored after having been read. -// DecodeProbeResponse may return the following errors: -// - "invalid_arg" (type *goa.ServiceError): http.StatusBadRequest -// - "internal" (type *goa.ServiceError): http.StatusInternalServerError -// - "unauthorized" (type *goa.ServiceError): http.StatusUnauthorized -// - error: internal error -func DecodeProbeResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { - return func(resp *http.Response) (interface{}, error) { - if restoreBody { - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - defer func() { - resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) - }() - } else { - defer resp.Body.Close() - } - switch resp.StatusCode { - case http.StatusOK: - var ( - body ProbeResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("Injective Price Oracle API", "probe", err) - } - err = ValidateProbeResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("Injective Price Oracle API", "probe", err) - } - res := NewProbeResponseOK(&body) - return res, nil - case http.StatusBadRequest: - var ( - body ProbeInvalidArgResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("Injective Price Oracle API", "probe", err) - } - err = ValidateProbeInvalidArgResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("Injective Price Oracle API", "probe", err) - } - return nil, NewProbeInvalidArg(&body) - case http.StatusInternalServerError: - var ( - body ProbeInternalResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("Injective Price Oracle API", "probe", err) - } - err = ValidateProbeInternalResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("Injective Price Oracle API", "probe", err) - } - return nil, NewProbeInternal(&body) - case http.StatusUnauthorized: - var ( - body ProbeUnauthorizedResponseBody - err error - ) - err = decoder(resp).Decode(&body) - if err != nil { - return nil, goahttp.ErrDecodingError("Injective Price Oracle API", "probe", err) - } - err = ValidateProbeUnauthorizedResponseBody(&body) - if err != nil { - return nil, goahttp.ErrValidationError("Injective Price Oracle API", "probe", err) - } - return nil, NewProbeUnauthorized(&body) - default: - body, _ := ioutil.ReadAll(resp.Body) - return nil, goahttp.ErrInvalidResponse("Injective Price Oracle API", "probe", resp.StatusCode, string(body)) - } - } -} diff --git a/api/gen/http/injective_price_oracle_api/client/paths.go b/api/gen/http/injective_price_oracle_api/client/paths.go deleted file mode 100644 index 305c060..0000000 --- a/api/gen/http/injective_price_oracle_api/client/paths.go +++ /dev/null @@ -1,13 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the Injective Price Oracle API service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -// ProbeInjectivePriceOracleAPIPath returns the URL path to the Injective Price Oracle API service probe HTTP endpoint. -func ProbeInjectivePriceOracleAPIPath() string { - return "/api/price-oracle/v1/probe" -} diff --git a/api/gen/http/injective_price_oracle_api/client/types.go b/api/gen/http/injective_price_oracle_api/client/types.go deleted file mode 100644 index bd3f0c0..0000000 --- a/api/gen/http/injective_price_oracle_api/client/types.go +++ /dev/null @@ -1,226 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP client types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goa "goa.design/goa/v3/pkg" -) - -// ProbeRequestBody is the type of the "Injective Price Oracle API" service -// "probe" endpoint HTTP request body. -type ProbeRequestBody struct { - // TOML file contents - Content []byte `form:"content" json:"content" xml:"content"` -} - -// ProbeResponseBody is the type of the "Injective Price Oracle API" service -// "probe" endpoint HTTP response body. -type ProbeResponseBody struct { - // Result of the probe - Result *string `form:"result,omitempty" json:"result,omitempty" xml:"result,omitempty"` -} - -// ProbeInvalidArgResponseBody is the type of the "Injective Price Oracle API" -// service "probe" endpoint HTTP response body for the "invalid_arg" error. -type ProbeInvalidArgResponseBody struct { - // Name is the name of this class of errors. - Name *string `form:"name,omitempty" json:"name,omitempty" xml:"name,omitempty"` - // ID is a unique identifier for this particular occurrence of the problem. - ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message *string `form:"message,omitempty" json:"message,omitempty" xml:"message,omitempty"` - // Is the error temporary? - Temporary *bool `form:"temporary,omitempty" json:"temporary,omitempty" xml:"temporary,omitempty"` - // Is the error a timeout? - Timeout *bool `form:"timeout,omitempty" json:"timeout,omitempty" xml:"timeout,omitempty"` - // Is the error a server-side fault? - Fault *bool `form:"fault,omitempty" json:"fault,omitempty" xml:"fault,omitempty"` -} - -// ProbeInternalResponseBody is the type of the "Injective Price Oracle API" -// service "probe" endpoint HTTP response body for the "internal" error. -type ProbeInternalResponseBody struct { - // Name is the name of this class of errors. - Name *string `form:"name,omitempty" json:"name,omitempty" xml:"name,omitempty"` - // ID is a unique identifier for this particular occurrence of the problem. - ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message *string `form:"message,omitempty" json:"message,omitempty" xml:"message,omitempty"` - // Is the error temporary? - Temporary *bool `form:"temporary,omitempty" json:"temporary,omitempty" xml:"temporary,omitempty"` - // Is the error a timeout? - Timeout *bool `form:"timeout,omitempty" json:"timeout,omitempty" xml:"timeout,omitempty"` - // Is the error a server-side fault? - Fault *bool `form:"fault,omitempty" json:"fault,omitempty" xml:"fault,omitempty"` -} - -// ProbeUnauthorizedResponseBody is the type of the "Injective Price Oracle -// API" service "probe" endpoint HTTP response body for the "unauthorized" -// error. -type ProbeUnauthorizedResponseBody struct { - // Name is the name of this class of errors. - Name *string `form:"name,omitempty" json:"name,omitempty" xml:"name,omitempty"` - // ID is a unique identifier for this particular occurrence of the problem. - ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message *string `form:"message,omitempty" json:"message,omitempty" xml:"message,omitempty"` - // Is the error temporary? - Temporary *bool `form:"temporary,omitempty" json:"temporary,omitempty" xml:"temporary,omitempty"` - // Is the error a timeout? - Timeout *bool `form:"timeout,omitempty" json:"timeout,omitempty" xml:"timeout,omitempty"` - // Is the error a server-side fault? - Fault *bool `form:"fault,omitempty" json:"fault,omitempty" xml:"fault,omitempty"` -} - -// NewProbeRequestBody builds the HTTP request body from the payload of the -// "probe" endpoint of the "Injective Price Oracle API" service. -func NewProbeRequestBody(p *injectivepriceoracleapi.ProbePayload) *ProbeRequestBody { - body := &ProbeRequestBody{ - Content: p.Content, - } - return body -} - -// NewProbeResponseOK builds a "Injective Price Oracle API" service "probe" -// endpoint result from a HTTP "OK" response. -func NewProbeResponseOK(body *ProbeResponseBody) *injectivepriceoracleapi.ProbeResponse { - v := &injectivepriceoracleapi.ProbeResponse{ - Result: *body.Result, - } - - return v -} - -// NewProbeInvalidArg builds a Injective Price Oracle API service probe -// endpoint invalid_arg error. -func NewProbeInvalidArg(body *ProbeInvalidArgResponseBody) *goa.ServiceError { - v := &goa.ServiceError{ - Name: *body.Name, - ID: *body.ID, - Message: *body.Message, - Temporary: *body.Temporary, - Timeout: *body.Timeout, - Fault: *body.Fault, - } - - return v -} - -// NewProbeInternal builds a Injective Price Oracle API service probe endpoint -// internal error. -func NewProbeInternal(body *ProbeInternalResponseBody) *goa.ServiceError { - v := &goa.ServiceError{ - Name: *body.Name, - ID: *body.ID, - Message: *body.Message, - Temporary: *body.Temporary, - Timeout: *body.Timeout, - Fault: *body.Fault, - } - - return v -} - -// NewProbeUnauthorized builds a Injective Price Oracle API service probe -// endpoint unauthorized error. -func NewProbeUnauthorized(body *ProbeUnauthorizedResponseBody) *goa.ServiceError { - v := &goa.ServiceError{ - Name: *body.Name, - ID: *body.ID, - Message: *body.Message, - Temporary: *body.Temporary, - Timeout: *body.Timeout, - Fault: *body.Fault, - } - - return v -} - -// ValidateProbeResponseBody runs the validations defined on ProbeResponseBody -func ValidateProbeResponseBody(body *ProbeResponseBody) (err error) { - if body.Result == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("result", "body")) - } - return -} - -// ValidateProbeInvalidArgResponseBody runs the validations defined on -// probe_invalid_arg_response_body -func ValidateProbeInvalidArgResponseBody(body *ProbeInvalidArgResponseBody) (err error) { - if body.Name == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("name", "body")) - } - if body.ID == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) - } - if body.Message == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("message", "body")) - } - if body.Temporary == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("temporary", "body")) - } - if body.Timeout == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("timeout", "body")) - } - if body.Fault == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("fault", "body")) - } - return -} - -// ValidateProbeInternalResponseBody runs the validations defined on -// probe_internal_response_body -func ValidateProbeInternalResponseBody(body *ProbeInternalResponseBody) (err error) { - if body.Name == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("name", "body")) - } - if body.ID == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) - } - if body.Message == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("message", "body")) - } - if body.Temporary == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("temporary", "body")) - } - if body.Timeout == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("timeout", "body")) - } - if body.Fault == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("fault", "body")) - } - return -} - -// ValidateProbeUnauthorizedResponseBody runs the validations defined on -// probe_unauthorized_response_body -func ValidateProbeUnauthorizedResponseBody(body *ProbeUnauthorizedResponseBody) (err error) { - if body.Name == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("name", "body")) - } - if body.ID == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) - } - if body.Message == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("message", "body")) - } - if body.Temporary == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("temporary", "body")) - } - if body.Timeout == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("timeout", "body")) - } - if body.Fault == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("fault", "body")) - } - return -} diff --git a/api/gen/http/injective_price_oracle_api/server/encode_decode.go b/api/gen/http/injective_price_oracle_api/server/encode_decode.go deleted file mode 100644 index 5e28a5d..0000000 --- a/api/gen/http/injective_price_oracle_api/server/encode_decode.go +++ /dev/null @@ -1,134 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP server encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "errors" - "net/http" - "strings" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" -) - -// EncodeProbeResponse returns an encoder for responses returned by the -// Injective Price Oracle API probe endpoint. -func EncodeProbeResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { - return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { - res, _ := v.(*injectivepriceoracleapi.ProbeResponse) - enc := encoder(ctx, w) - body := NewProbeResponseBody(res) - w.WriteHeader(http.StatusOK) - return enc.Encode(body) - } -} - -// DecodeProbeRequest returns a decoder for requests sent to the Injective -// Price Oracle API probe endpoint. -func DecodeProbeRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { - return func(r *http.Request) (interface{}, error) { - var payload *injectivepriceoracleapi.ProbePayload - if err := decoder(r).Decode(&payload); err != nil { - return nil, goa.DecodePayloadError(err.Error()) - } - if payload.Key != nil { - if strings.Contains(*payload.Key, " ") { - // Remove authorization scheme prefix (e.g. "Bearer") - cred := strings.SplitN(*payload.Key, " ", 2)[1] - payload.Key = &cred - } - } - - return payload, nil - } -} - -// NewInjectivePriceOracleAPIProbeDecoder returns a decoder to decode the -// multipart request for the "Injective Price Oracle API" service "probe" -// endpoint. -func NewInjectivePriceOracleAPIProbeDecoder(mux goahttp.Muxer, injectivePriceOracleAPIProbeDecoderFn InjectivePriceOracleAPIProbeDecoderFunc) func(r *http.Request) goahttp.Decoder { - return func(r *http.Request) goahttp.Decoder { - return goahttp.EncodingFunc(func(v interface{}) error { - mr, merr := r.MultipartReader() - if merr != nil { - return merr - } - p := v.(**injectivepriceoracleapi.ProbePayload) - if err := injectivePriceOracleAPIProbeDecoderFn(mr, p); err != nil { - return err - } - - var ( - key *string - ) - keyRaw := r.Header.Get("X-Api-Key") - if keyRaw != "" { - key = &keyRaw - } - (*p).Key = key - return nil - }) - } -} - -// EncodeProbeError returns an encoder for errors returned by the probe -// Injective Price Oracle API endpoint. -func EncodeProbeError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error { - encodeError := goahttp.ErrorEncoder(encoder, formatter) - return func(ctx context.Context, w http.ResponseWriter, v error) error { - var en ErrorNamer - if !errors.As(v, &en) { - return encodeError(ctx, w, v) - } - switch en.ErrorName() { - case "invalid_arg": - var res *goa.ServiceError - errors.As(v, &res) - enc := encoder(ctx, w) - var body interface{} - if formatter != nil { - body = formatter(res) - } else { - body = NewProbeInvalidArgResponseBody(res) - } - w.Header().Set("goa-error", res.ErrorName()) - w.WriteHeader(http.StatusBadRequest) - return enc.Encode(body) - case "internal": - var res *goa.ServiceError - errors.As(v, &res) - enc := encoder(ctx, w) - var body interface{} - if formatter != nil { - body = formatter(res) - } else { - body = NewProbeInternalResponseBody(res) - } - w.Header().Set("goa-error", res.ErrorName()) - w.WriteHeader(http.StatusInternalServerError) - return enc.Encode(body) - case "unauthorized": - var res *goa.ServiceError - errors.As(v, &res) - enc := encoder(ctx, w) - var body interface{} - if formatter != nil { - body = formatter(res) - } else { - body = NewProbeUnauthorizedResponseBody(res) - } - w.Header().Set("goa-error", res.ErrorName()) - w.WriteHeader(http.StatusUnauthorized) - return enc.Encode(body) - default: - return encodeError(ctx, w, v) - } - } -} diff --git a/api/gen/http/injective_price_oracle_api/server/paths.go b/api/gen/http/injective_price_oracle_api/server/paths.go deleted file mode 100644 index c6cfff3..0000000 --- a/api/gen/http/injective_price_oracle_api/server/paths.go +++ /dev/null @@ -1,13 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the Injective Price Oracle API service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -// ProbeInjectivePriceOracleAPIPath returns the URL path to the Injective Price Oracle API service probe HTTP endpoint. -func ProbeInjectivePriceOracleAPIPath() string { - return "/api/price-oracle/v1/probe" -} diff --git a/api/gen/http/injective_price_oracle_api/server/server.go b/api/gen/http/injective_price_oracle_api/server/server.go deleted file mode 100644 index fc6f002..0000000 --- a/api/gen/http/injective_price_oracle_api/server/server.go +++ /dev/null @@ -1,183 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP server -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "mime/multipart" - "net/http" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goahttp "goa.design/goa/v3/http" - goa "goa.design/goa/v3/pkg" - "goa.design/plugins/v3/cors" -) - -// Server lists the Injective Price Oracle API service endpoint HTTP handlers. -type Server struct { - Mounts []*MountPoint - Probe http.Handler - CORS http.Handler -} - -// ErrorNamer is an interface implemented by generated error structs that -// exposes the name of the error as defined in the design. -type ErrorNamer interface { - ErrorName() string -} - -// MountPoint holds information about the mounted endpoints. -type MountPoint struct { - // Method is the name of the service method served by the mounted HTTP handler. - Method string - // Verb is the HTTP method used to match requests to the mounted handler. - Verb string - // Pattern is the HTTP request path pattern used to match requests to the - // mounted handler. - Pattern string -} - -// InjectivePriceOracleAPIProbeDecoderFunc is the type to decode multipart -// request for the "Injective Price Oracle API" service "probe" endpoint. -type InjectivePriceOracleAPIProbeDecoderFunc func(*multipart.Reader, **injectivepriceoracleapi.ProbePayload) error - -// New instantiates HTTP handlers for all the Injective Price Oracle API -// service endpoints using the provided encoder and decoder. The handlers are -// mounted on the given mux using the HTTP verb and path defined in the design. -// errhandler is called whenever a response fails to be encoded. formatter is -// used to format errors returned by the service methods prior to encoding. -// Both errhandler and formatter are optional and can be nil. -func New( - e *injectivepriceoracleapi.Endpoints, - mux goahttp.Muxer, - decoder func(*http.Request) goahttp.Decoder, - encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, - errhandler func(context.Context, http.ResponseWriter, error), - formatter func(err error) goahttp.Statuser, - injectivePriceOracleAPIProbeDecoderFn InjectivePriceOracleAPIProbeDecoderFunc, -) *Server { - return &Server{ - Mounts: []*MountPoint{ - {"Probe", "POST", "/api/price-oracle/v1/probe"}, - {"CORS", "OPTIONS", "/api/price-oracle/v1/probe"}, - }, - Probe: NewProbeHandler(e.Probe, mux, NewInjectivePriceOracleAPIProbeDecoder(mux, injectivePriceOracleAPIProbeDecoderFn), encoder, errhandler, formatter), - CORS: NewCORSHandler(), - } -} - -// Service returns the name of the service served. -func (s *Server) Service() string { return "Injective Price Oracle API" } - -// Use wraps the server handlers with the given middleware. -func (s *Server) Use(m func(http.Handler) http.Handler) { - s.Probe = m(s.Probe) - s.CORS = m(s.CORS) -} - -// Mount configures the mux to serve the Injective Price Oracle API endpoints. -func Mount(mux goahttp.Muxer, h *Server) { - MountProbeHandler(mux, h.Probe) - MountCORSHandler(mux, h.CORS) -} - -// Mount configures the mux to serve the Injective Price Oracle API endpoints. -func (s *Server) Mount(mux goahttp.Muxer) { - Mount(mux, s) -} - -// MountProbeHandler configures the mux to serve the "Injective Price Oracle -// API" service "probe" endpoint. -func MountProbeHandler(mux goahttp.Muxer, h http.Handler) { - f, ok := HandleInjectivePriceOracleAPIOrigin(h).(http.HandlerFunc) - if !ok { - f = func(w http.ResponseWriter, r *http.Request) { - h.ServeHTTP(w, r) - } - } - mux.Handle("POST", "/api/price-oracle/v1/probe", f) -} - -// NewProbeHandler creates a HTTP handler which loads the HTTP request and -// calls the "Injective Price Oracle API" service "probe" endpoint. -func NewProbeHandler( - endpoint goa.Endpoint, - mux goahttp.Muxer, - decoder func(*http.Request) goahttp.Decoder, - encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, - errhandler func(context.Context, http.ResponseWriter, error), - formatter func(err error) goahttp.Statuser, -) http.Handler { - var ( - decodeRequest = DecodeProbeRequest(mux, decoder) - encodeResponse = EncodeProbeResponse(encoder) - encodeError = EncodeProbeError(encoder, formatter) - ) - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) - ctx = context.WithValue(ctx, goa.MethodKey, "probe") - ctx = context.WithValue(ctx, goa.ServiceKey, "Injective Price Oracle API") - payload, err := decodeRequest(r) - if err != nil { - if err := encodeError(ctx, w, err); err != nil { - errhandler(ctx, w, err) - } - return - } - res, err := endpoint(ctx, payload) - if err != nil { - if err := encodeError(ctx, w, err); err != nil { - errhandler(ctx, w, err) - } - return - } - if err := encodeResponse(ctx, w, res); err != nil { - errhandler(ctx, w, err) - } - }) -} - -// MountCORSHandler configures the mux to serve the CORS endpoints for the -// service Injective Price Oracle API. -func MountCORSHandler(mux goahttp.Muxer, h http.Handler) { - h = HandleInjectivePriceOracleAPIOrigin(h) - mux.Handle("OPTIONS", "/api/price-oracle/v1/probe", h.ServeHTTP) -} - -// NewCORSHandler creates a HTTP handler which returns a simple 200 response. -func NewCORSHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - }) -} - -// HandleInjectivePriceOracleAPIOrigin applies the CORS response headers -// corresponding to the origin for the service Injective Price Oracle API. -func HandleInjectivePriceOracleAPIOrigin(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - origin := r.Header.Get("Origin") - if origin == "" { - // Not a CORS request - h.ServeHTTP(w, r) - return - } - if cors.MatchOrigin(origin, "*") { - w.Header().Set("Access-Control-Allow-Origin", origin) - w.Header().Set("Vary", "Origin") - if acrm := r.Header.Get("Access-Control-Request-Method"); acrm != "" { - // We are handling a preflight request - w.Header().Set("Access-Control-Allow-Methods", "POST") - w.Header().Set("Access-Control-Allow-Headers", "Content-Type, X-Api-Key") - } - h.ServeHTTP(w, r) - return - } - h.ServeHTTP(w, r) - return - }) -} diff --git a/api/gen/http/injective_price_oracle_api/server/types.go b/api/gen/http/injective_price_oracle_api/server/types.go deleted file mode 100644 index 78c821b..0000000 --- a/api/gen/http/injective_price_oracle_api/server/types.go +++ /dev/null @@ -1,152 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API HTTP server types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - goa "goa.design/goa/v3/pkg" -) - -// ProbeRequestBody is the type of the "Injective Price Oracle API" service -// "probe" endpoint HTTP request body. -type ProbeRequestBody struct { - // TOML file contents - Content []byte `form:"content,omitempty" json:"content,omitempty" xml:"content,omitempty"` -} - -// ProbeResponseBody is the type of the "Injective Price Oracle API" service -// "probe" endpoint HTTP response body. -type ProbeResponseBody struct { - // Result of the probe - Result string `form:"result" json:"result" xml:"result"` -} - -// ProbeInvalidArgResponseBody is the type of the "Injective Price Oracle API" -// service "probe" endpoint HTTP response body for the "invalid_arg" error. -type ProbeInvalidArgResponseBody struct { - // Name is the name of this class of errors. - Name string `form:"name" json:"name" xml:"name"` - // ID is a unique identifier for this particular occurrence of the problem. - ID string `form:"id" json:"id" xml:"id"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message string `form:"message" json:"message" xml:"message"` - // Is the error temporary? - Temporary bool `form:"temporary" json:"temporary" xml:"temporary"` - // Is the error a timeout? - Timeout bool `form:"timeout" json:"timeout" xml:"timeout"` - // Is the error a server-side fault? - Fault bool `form:"fault" json:"fault" xml:"fault"` -} - -// ProbeInternalResponseBody is the type of the "Injective Price Oracle API" -// service "probe" endpoint HTTP response body for the "internal" error. -type ProbeInternalResponseBody struct { - // Name is the name of this class of errors. - Name string `form:"name" json:"name" xml:"name"` - // ID is a unique identifier for this particular occurrence of the problem. - ID string `form:"id" json:"id" xml:"id"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message string `form:"message" json:"message" xml:"message"` - // Is the error temporary? - Temporary bool `form:"temporary" json:"temporary" xml:"temporary"` - // Is the error a timeout? - Timeout bool `form:"timeout" json:"timeout" xml:"timeout"` - // Is the error a server-side fault? - Fault bool `form:"fault" json:"fault" xml:"fault"` -} - -// ProbeUnauthorizedResponseBody is the type of the "Injective Price Oracle -// API" service "probe" endpoint HTTP response body for the "unauthorized" -// error. -type ProbeUnauthorizedResponseBody struct { - // Name is the name of this class of errors. - Name string `form:"name" json:"name" xml:"name"` - // ID is a unique identifier for this particular occurrence of the problem. - ID string `form:"id" json:"id" xml:"id"` - // Message is a human-readable explanation specific to this occurrence of the - // problem. - Message string `form:"message" json:"message" xml:"message"` - // Is the error temporary? - Temporary bool `form:"temporary" json:"temporary" xml:"temporary"` - // Is the error a timeout? - Timeout bool `form:"timeout" json:"timeout" xml:"timeout"` - // Is the error a server-side fault? - Fault bool `form:"fault" json:"fault" xml:"fault"` -} - -// NewProbeResponseBody builds the HTTP response body from the result of the -// "probe" endpoint of the "Injective Price Oracle API" service. -func NewProbeResponseBody(res *injectivepriceoracleapi.ProbeResponse) *ProbeResponseBody { - body := &ProbeResponseBody{ - Result: res.Result, - } - return body -} - -// NewProbeInvalidArgResponseBody builds the HTTP response body from the result -// of the "probe" endpoint of the "Injective Price Oracle API" service. -func NewProbeInvalidArgResponseBody(res *goa.ServiceError) *ProbeInvalidArgResponseBody { - body := &ProbeInvalidArgResponseBody{ - Name: res.Name, - ID: res.ID, - Message: res.Message, - Temporary: res.Temporary, - Timeout: res.Timeout, - Fault: res.Fault, - } - return body -} - -// NewProbeInternalResponseBody builds the HTTP response body from the result -// of the "probe" endpoint of the "Injective Price Oracle API" service. -func NewProbeInternalResponseBody(res *goa.ServiceError) *ProbeInternalResponseBody { - body := &ProbeInternalResponseBody{ - Name: res.Name, - ID: res.ID, - Message: res.Message, - Temporary: res.Temporary, - Timeout: res.Timeout, - Fault: res.Fault, - } - return body -} - -// NewProbeUnauthorizedResponseBody builds the HTTP response body from the -// result of the "probe" endpoint of the "Injective Price Oracle API" service. -func NewProbeUnauthorizedResponseBody(res *goa.ServiceError) *ProbeUnauthorizedResponseBody { - body := &ProbeUnauthorizedResponseBody{ - Name: res.Name, - ID: res.ID, - Message: res.Message, - Temporary: res.Temporary, - Timeout: res.Timeout, - Fault: res.Fault, - } - return body -} - -// NewProbePayload builds a Injective Price Oracle API service probe endpoint -// payload. -func NewProbePayload(body *ProbeRequestBody, key *string) *injectivepriceoracleapi.ProbePayload { - v := &injectivepriceoracleapi.ProbePayload{ - Content: body.Content, - } - v.Key = key - - return v -} - -// ValidateProbeRequestBody runs the validations defined on ProbeRequestBody -func ValidateProbeRequestBody(body *ProbeRequestBody) (err error) { - if body.Content == nil { - err = goa.MergeErrors(err, goa.MissingFieldError("content", "body")) - } - return -} diff --git a/api/gen/http/openapi.json b/api/gen/http/openapi.json deleted file mode 100644 index bd58d1c..0000000 --- a/api/gen/http/openapi.json +++ /dev/null @@ -1 +0,0 @@ -{"swagger":"2.0","info":{"title":"PriceOracle Service","description":"HTTP server for the Price Oracle API","version":""},"host":"k8s.mainnet.eu.price-oracle.injective.network","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/api/health/v1/status":{"get":{"tags":["health"],"summary":"GetStatus health","description":"Get current backend health status","operationId":"health#GetStatus","responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/HealthGetStatusResponseBody","required":["s","status"]}},"500":{"description":"Internal Server Error response.","schema":{"$ref":"#/definitions/HealthGetStatusInternalResponseBody"}}},"schemes":["https"]}},"/api/price-oracle/v1/probe":{"post":{"tags":["Injective Price Oracle API"],"summary":"probe Injective Price Oracle API","description":"Validate TOML file","operationId":"Injective Price Oracle API#probe","consumes":["multipart/form-data"],"parameters":[{"name":"X-Api-Key","in":"header","description":"API key for authentication","required":false,"type":"string"},{"name":"ProbeRequestBody","in":"formData","required":true,"schema":{"$ref":"#/definitions/InjectivePriceOracleAPIProbeRequestBody","required":["content"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/InjectivePriceOracleAPIProbeResponseBody","required":["result"]}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/InjectivePriceOracleAPIProbeInvalidArgResponseBody"}},"401":{"description":"Unauthorized response.","schema":{"$ref":"#/definitions/InjectivePriceOracleAPIProbeUnauthorizedResponseBody"}},"500":{"description":"Internal Server Error response.","schema":{"$ref":"#/definitions/InjectivePriceOracleAPIProbeInternalResponseBody"}}},"schemes":["https"],"security":[{"api_key_header_X-Api-Key":[]}]}},"/swagger/index.html":{"get":{"tags":["Swagger"],"summary":"Download ./swagger/index.html","description":"Provide Swagger-UI html document","operationId":"Swagger#/swagger/index.html","responses":{"200":{"description":"File downloaded","schema":{"type":"file"}}},"schemes":["https"]}},"/swagger/{path}":{"get":{"tags":["Swagger"],"summary":"Download ./swagger/","description":"Serve static content.","operationId":"Swagger#/swagger/{*path}","parameters":[{"name":"path","in":"path","description":"Relative file path","required":true,"type":"string"}],"responses":{"200":{"description":"File downloaded","schema":{"type":"file"}},"404":{"description":"File not found","schema":{"$ref":"#/definitions/Error"}}},"schemes":["https"]}}},"definitions":{"Error":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Error response result type (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"HealthGetStatusInternalResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Internal Server Error (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"HealthGetStatusResponseBody":{"title":"HealthGetStatusResponseBody","type":"object","properties":{"data":{"$ref":"#/definitions/HealthStatusResponseBody"},"errmsg":{"type":"string","description":"Error message.","example":"Something has failed"},"s":{"type":"string","description":"Status of the response.","example":"error","enum":["ok","error","no_data"]},"status":{"type":"string","example":"Est ut consequatur."}},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Non dolor rerum."},"required":["s","status"]},"HealthStatusResponseBody":{"title":"HealthStatusResponseBody","type":"object","description":"Status defines the structure for health information","example":{}},"InjectivePriceOracleAPIProbeInternalResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Internal Server Error (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"InjectivePriceOracleAPIProbeInvalidArgResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Invalid argument (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"InjectivePriceOracleAPIProbeRequestBody":{"title":"InjectivePriceOracleAPIProbeRequestBody","type":"object","properties":{"content":{"type":"string","description":"TOML file contents","example":"TW9sZXN0aWFzIHV0IHByYWVzZW50aXVtIHBvcnJvIG5vbiBzaW50IG5lc2NpdW50Lg==","format":"byte"}},"example":{"content":"RG9sb3JlbXF1ZSBxdWlhIHNlZCBlb3Mu"},"required":["content"]},"InjectivePriceOracleAPIProbeResponseBody":{"title":"InjectivePriceOracleAPIProbeResponseBody","type":"object","properties":{"result":{"type":"string","description":"Result of the probe","example":"Ea corrupti."}},"example":{"result":"Inventore non explicabo cumque possimus molestiae enim."},"required":["result"]},"InjectivePriceOracleAPIProbeUnauthorizedResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"Unauthorized (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]}},"securityDefinitions":{"api_key_header_X-Api-Key":{"type":"apiKey","description":"\n**Security Scopes**:\n * `api:read`: Read-only access","name":"X-Api-Key","in":"header"}}} \ No newline at end of file diff --git a/api/gen/http/openapi.yaml b/api/gen/http/openapi.yaml deleted file mode 100644 index 44a7395..0000000 --- a/api/gen/http/openapi.yaml +++ /dev/null @@ -1,486 +0,0 @@ -swagger: "2.0" -info: - title: PriceOracle Service - description: HTTP server for the Price Oracle API - version: "" -host: k8s.mainnet.eu.price-oracle.injective.network -consumes: -- application/json -- application/xml -- application/gob -produces: -- application/json -- application/xml -- application/gob -paths: - /api/health/v1/status: - get: - tags: - - health - summary: GetStatus health - description: Get current backend health status - operationId: health#GetStatus - responses: - "200": - description: OK response. - schema: - $ref: '#/definitions/HealthGetStatusResponseBody' - required: - - s - - status - "500": - description: Internal Server Error response. - schema: - $ref: '#/definitions/HealthGetStatusInternalResponseBody' - schemes: - - https - /api/price-oracle/v1/probe: - post: - tags: - - Injective Price Oracle API - summary: probe Injective Price Oracle API - description: Validate TOML file - operationId: Injective Price Oracle API#probe - consumes: - - multipart/form-data - parameters: - - name: X-Api-Key - in: header - description: API key for authentication - required: false - type: string - - name: ProbeRequestBody - in: formData - required: true - schema: - $ref: '#/definitions/InjectivePriceOracleAPIProbeRequestBody' - required: - - content - responses: - "200": - description: OK response. - schema: - $ref: '#/definitions/InjectivePriceOracleAPIProbeResponseBody' - required: - - result - "400": - description: Bad Request response. - schema: - $ref: '#/definitions/InjectivePriceOracleAPIProbeInvalidArgResponseBody' - "401": - description: Unauthorized response. - schema: - $ref: '#/definitions/InjectivePriceOracleAPIProbeUnauthorizedResponseBody' - "500": - description: Internal Server Error response. - schema: - $ref: '#/definitions/InjectivePriceOracleAPIProbeInternalResponseBody' - schemes: - - https - security: - - api_key_header_X-Api-Key: [] - /swagger/{path}: - get: - tags: - - Swagger - summary: Download ./swagger/ - description: Serve static content. - operationId: Swagger#/swagger/{*path} - parameters: - - name: path - in: path - description: Relative file path - required: true - type: string - responses: - "200": - description: File downloaded - schema: - type: file - "404": - description: File not found - schema: - $ref: '#/definitions/Error' - schemes: - - https - /swagger/index.html: - get: - tags: - - Swagger - summary: Download ./swagger/index.html - description: Provide Swagger-UI html document - operationId: Swagger#/swagger/index.html - responses: - "200": - description: File downloaded - schema: - type: file - schemes: - - https -definitions: - Error: - title: 'Mediatype identifier: application/vnd.goa.error; view=default' - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: false - id: - type: string - description: ID is a unique identifier for this particular occurrence of the - problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: true - timeout: - type: boolean - description: Is the error a timeout? - example: true - description: Error response result type (default view) - example: - fault: true - id: 123abc - message: parameter 'p' must be an integer - name: bad_request - temporary: true - timeout: true - required: - - name - - id - - message - - temporary - - timeout - - fault - HealthGetStatusInternalResponseBody: - title: 'Mediatype identifier: application/vnd.goa.error; view=default' - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: true - id: - type: string - description: ID is a unique identifier for this particular occurrence of the - problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: false - timeout: - type: boolean - description: Is the error a timeout? - example: true - description: Internal Server Error (default view) - example: - fault: false - id: 123abc - message: parameter 'p' must be an integer - name: bad_request - temporary: true - timeout: false - required: - - name - - id - - message - - temporary - - timeout - - fault - HealthGetStatusResponseBody: - title: HealthGetStatusResponseBody - type: object - properties: - data: - $ref: '#/definitions/HealthStatusResponseBody' - errmsg: - type: string - description: Error message. - example: Something has failed - s: - type: string - description: Status of the response. - example: error - enum: - - ok - - error - - no_data - status: - type: string - example: Est ut consequatur. - example: - data: {} - errmsg: Something has failed - s: error - status: Non dolor rerum. - required: - - s - - status - HealthStatusResponseBody: - title: HealthStatusResponseBody - type: object - description: Status defines the structure for health information - example: {} - InjectivePriceOracleAPIProbeInternalResponseBody: - title: 'Mediatype identifier: application/vnd.goa.error; view=default' - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: false - id: - type: string - description: ID is a unique identifier for this particular occurrence of the - problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: true - timeout: - type: boolean - description: Is the error a timeout? - example: true - description: Internal Server Error (default view) - example: - fault: true - id: 123abc - message: parameter 'p' must be an integer - name: bad_request - temporary: true - timeout: false - required: - - name - - id - - message - - temporary - - timeout - - fault - InjectivePriceOracleAPIProbeInvalidArgResponseBody: - title: 'Mediatype identifier: application/vnd.goa.error; view=default' - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: true - id: - type: string - description: ID is a unique identifier for this particular occurrence of the - problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: true - timeout: - type: boolean - description: Is the error a timeout? - example: true - description: Invalid argument (default view) - example: - fault: true - id: 123abc - message: parameter 'p' must be an integer - name: bad_request - temporary: false - timeout: true - required: - - name - - id - - message - - temporary - - timeout - - fault - InjectivePriceOracleAPIProbeRequestBody: - title: InjectivePriceOracleAPIProbeRequestBody - type: object - properties: - content: - type: string - description: TOML file contents - example: - - 77 - - 111 - - 108 - - 101 - - 115 - - 116 - - 105 - - 97 - - 115 - - 32 - - 117 - - 116 - - 32 - - 112 - - 114 - - 97 - - 101 - - 115 - - 101 - - 110 - - 116 - - 105 - - 117 - - 109 - - 32 - - 112 - - 111 - - 114 - - 114 - - 111 - - 32 - - 110 - - 111 - - 110 - - 32 - - 115 - - 105 - - 110 - - 116 - - 32 - - 110 - - 101 - - 115 - - 99 - - 105 - - 117 - - 110 - - 116 - - 46 - format: byte - example: - content: - - 68 - - 111 - - 108 - - 111 - - 114 - - 101 - - 109 - - 113 - - 117 - - 101 - - 32 - - 113 - - 117 - - 105 - - 97 - - 32 - - 115 - - 101 - - 100 - - 32 - - 101 - - 111 - - 115 - - 46 - required: - - content - InjectivePriceOracleAPIProbeResponseBody: - title: InjectivePriceOracleAPIProbeResponseBody - type: object - properties: - result: - type: string - description: Result of the probe - example: Ea corrupti. - example: - result: Inventore non explicabo cumque possimus molestiae enim. - required: - - result - InjectivePriceOracleAPIProbeUnauthorizedResponseBody: - title: 'Mediatype identifier: application/vnd.goa.error; view=default' - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: true - id: - type: string - description: ID is a unique identifier for this particular occurrence of the - problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: false - timeout: - type: boolean - description: Is the error a timeout? - example: false - description: Unauthorized (default view) - example: - fault: true - id: 123abc - message: parameter 'p' must be an integer - name: bad_request - temporary: false - timeout: true - required: - - name - - id - - message - - temporary - - timeout - - fault -securityDefinitions: - api_key_header_X-Api-Key: - type: apiKey - description: |2- - - **Security Scopes**: - * `api:read`: Read-only access - name: X-Api-Key - in: header diff --git a/api/gen/http/openapi3.json b/api/gen/http/openapi3.json deleted file mode 100644 index 801e9d4..0000000 --- a/api/gen/http/openapi3.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.0.3","info":{"title":"PriceOracle Service","description":"HTTP server for the Price Oracle API","version":"1.0"},"servers":[{"url":"https://k8s.mainnet.eu.price-oracle.injective.network"},{"url":"https://k8s.testnet.price-oracle.injective.network"},{"url":"https://k8s.mainnet.staging.price-oracle.injective.network"}],"paths":{"/api/health/v1/status":{"get":{"tags":["health"],"summary":"GetStatus health","description":"Get current backend health status","operationId":"health#GetStatus","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatusResponse"},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Maiores ut et quaerat ad dignissimos nostrum."}}}},"500":{"description":"Internal Server Error response.","content":{"application/vnd.goa.error":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"id":"3F1FKVRR","message":"Value of ID must be an integer","name":"bad_request"}}}}}}},"/api/price-oracle/v1/probe":{"post":{"tags":["Injective Price Oracle API"],"summary":"probe Injective Price Oracle API","description":"Validate TOML file","operationId":"Injective Price Oracle API#probe","parameters":[{"name":"X-Api-Key","in":"header","description":"API key for authentication","allowEmptyValue":true,"schema":{"type":"string","description":"API key for authentication","example":"Neque alias nisi."},"example":"Dolorem nesciunt eum commodi similique placeat ratione."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/ProbeRequestBody"},"example":{"content":"RmFjaWxpcyBvZmZpY2lpcy4="}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProbeResponse"},"example":{"result":"Expedita est quo eos amet dolores consequatur."}}}},"400":{"description":"Bad Request response.","content":{"application/vnd.goa.error":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"id":"3F1FKVRR","message":"Value of ID must be an integer","name":"bad_request"}}}},"401":{"description":"Unauthorized response.","content":{"application/vnd.goa.error":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"id":"3F1FKVRR","message":"Value of ID must be an integer","name":"bad_request"}}}},"500":{"description":"Internal Server Error response.","content":{"application/vnd.goa.error":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"id":"3F1FKVRR","message":"Value of ID must be an integer","name":"bad_request"}}}}},"security":[{"api_key_header_X-Api-Key":[]}]}},"/swagger/index.html":{"get":{"tags":["Swagger"],"summary":"Download ./swagger/index.html","description":"Provide Swagger-UI html document","operationId":"Swagger#/swagger/index.html","responses":{"200":{"description":"File downloaded"}}}},"/swagger/{*path}":{"get":{"tags":["Swagger"],"summary":"Download ./swagger/","description":"Serve static content.","operationId":"Swagger#/swagger/{*path}","parameters":[{"name":"path","in":"path","description":"Relative file path","required":true}],"responses":{"200":{"description":"File not found"},"404":{"description":"File not found"}}}}},"components":{"schemas":{"Error":{"type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"Invalid argument","example":{"id":"3F1FKVRR","message":"Value of ID must be an integer","name":"bad_request"},"required":["name","id","message","temporary","timeout","fault"]},"HealthStatus":{"type":"object","description":"Status defines the structure for health information","example":{}},"HealthStatusResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/HealthStatus"},"errmsg":{"type":"string","description":"Error message.","example":"Something has failed"},"s":{"type":"string","description":"Status of the response.","example":"error","enum":["ok","error","no_data"]},"status":{"type":"string","example":"Voluptatibus animi quia sed dolor."}},"example":{"data":{},"errmsg":"Something has failed","s":"error","status":"Consequuntur totam maiores."},"required":["s","status"]},"ProbeRequestBody":{"type":"object","properties":{"content":{"type":"string","description":"TOML file contents","example":"UmVwdWRpYW5kYWUgZXJyb3IgcGFyaWF0dXIu","format":"binary"}},"example":{"content":"UmF0aW9uZSBlc3NlIGJlYXRhZSBlYXF1ZS4="},"required":["content"]},"ProbeResponse":{"type":"object","properties":{"result":{"type":"string","description":"Result of the probe","example":"Quidem laborum ut."}},"example":{"result":"Et atque labore veniam voluptate."},"required":["result"]}},"securitySchemes":{"api_key_header_X-Api-Key":{"type":"apiKey","name":"X-Api-Key","in":"header"}}},"tags":[{"name":"Injective Price Oracle API","description":"Injective-Price-Oracle services API doc"},{"name":"Swagger","description":"The API Swagger specification"},{"name":"health","description":"HealthAPI allows to check if backend data is up-to-date and reliable or not."}]} \ No newline at end of file diff --git a/api/gen/http/openapi3.yaml b/api/gen/http/openapi3.yaml deleted file mode 100644 index f08f8b5..0000000 --- a/api/gen/http/openapi3.yaml +++ /dev/null @@ -1,313 +0,0 @@ -openapi: 3.0.3 -info: - title: PriceOracle Service - description: HTTP server for the Price Oracle API - version: "1.0" -servers: -- url: https://k8s.mainnet.eu.price-oracle.injective.network -- url: https://k8s.testnet.price-oracle.injective.network -- url: https://k8s.mainnet.staging.price-oracle.injective.network -paths: - /api/health/v1/status: - get: - tags: - - health - summary: GetStatus health - description: Get current backend health status - operationId: health#GetStatus - responses: - "200": - description: OK response. - content: - application/json: - schema: - $ref: '#/components/schemas/HealthStatusResponse' - example: - data: {} - errmsg: Something has failed - s: error - status: Maiores ut et quaerat ad dignissimos nostrum. - "500": - description: Internal Server Error response. - content: - application/vnd.goa.error: - schema: - $ref: '#/components/schemas/Error' - example: - id: 3F1FKVRR - message: Value of ID must be an integer - name: bad_request - /api/price-oracle/v1/probe: - post: - tags: - - Injective Price Oracle API - summary: probe Injective Price Oracle API - description: Validate TOML file - operationId: Injective Price Oracle API#probe - parameters: - - name: X-Api-Key - in: header - description: API key for authentication - allowEmptyValue: true - schema: - type: string - description: API key for authentication - example: Neque alias nisi. - example: Dolorem nesciunt eum commodi similique placeat ratione. - requestBody: - required: true - content: - multipart/form-data: - schema: - $ref: '#/components/schemas/ProbeRequestBody' - example: - content: - - 70 - - 97 - - 99 - - 105 - - 108 - - 105 - - 115 - - 32 - - 111 - - 102 - - 102 - - 105 - - 99 - - 105 - - 105 - - 115 - - 46 - responses: - "200": - description: OK response. - content: - application/json: - schema: - $ref: '#/components/schemas/ProbeResponse' - example: - result: Expedita est quo eos amet dolores consequatur. - "400": - description: Bad Request response. - content: - application/vnd.goa.error: - schema: - $ref: '#/components/schemas/Error' - example: - id: 3F1FKVRR - message: Value of ID must be an integer - name: bad_request - "401": - description: Unauthorized response. - content: - application/vnd.goa.error: - schema: - $ref: '#/components/schemas/Error' - example: - id: 3F1FKVRR - message: Value of ID must be an integer - name: bad_request - "500": - description: Internal Server Error response. - content: - application/vnd.goa.error: - schema: - $ref: '#/components/schemas/Error' - example: - id: 3F1FKVRR - message: Value of ID must be an integer - name: bad_request - security: - - api_key_header_X-Api-Key: [] - /swagger/{*path}: - get: - tags: - - Swagger - summary: Download ./swagger/ - description: Serve static content. - operationId: Swagger#/swagger/{*path} - parameters: - - name: path - in: path - description: Relative file path - required: true - responses: - "200": - description: File not found - "404": - description: File not found - /swagger/index.html: - get: - tags: - - Swagger - summary: Download ./swagger/index.html - description: Provide Swagger-UI html document - operationId: Swagger#/swagger/index.html - responses: - "200": - description: File downloaded -components: - schemas: - Error: - type: object - properties: - fault: - type: boolean - description: Is the error a server-side fault? - example: false - id: - type: string - description: ID is a unique identifier for this particular occurrence of - the problem. - example: 123abc - message: - type: string - description: Message is a human-readable explanation specific to this occurrence - of the problem. - example: parameter 'p' must be an integer - name: - type: string - description: Name is the name of this class of errors. - example: bad_request - temporary: - type: boolean - description: Is the error temporary? - example: true - timeout: - type: boolean - description: Is the error a timeout? - example: true - description: Invalid argument - example: - id: 3F1FKVRR - message: Value of ID must be an integer - name: bad_request - required: - - name - - id - - message - - temporary - - timeout - - fault - HealthStatus: - type: object - description: Status defines the structure for health information - example: {} - HealthStatusResponse: - type: object - properties: - data: - $ref: '#/components/schemas/HealthStatus' - errmsg: - type: string - description: Error message. - example: Something has failed - s: - type: string - description: Status of the response. - example: error - enum: - - ok - - error - - no_data - status: - type: string - example: Voluptatibus animi quia sed dolor. - example: - data: {} - errmsg: Something has failed - s: error - status: Consequuntur totam maiores. - required: - - s - - status - ProbeRequestBody: - type: object - properties: - content: - type: string - description: TOML file contents - example: - - 82 - - 101 - - 112 - - 117 - - 100 - - 105 - - 97 - - 110 - - 100 - - 97 - - 101 - - 32 - - 101 - - 114 - - 114 - - 111 - - 114 - - 32 - - 112 - - 97 - - 114 - - 105 - - 97 - - 116 - - 117 - - 114 - - 46 - format: binary - example: - content: - - 82 - - 97 - - 116 - - 105 - - 111 - - 110 - - 101 - - 32 - - 101 - - 115 - - 115 - - 101 - - 32 - - 98 - - 101 - - 97 - - 116 - - 97 - - 101 - - 32 - - 101 - - 97 - - 113 - - 117 - - 101 - - 46 - required: - - content - ProbeResponse: - type: object - properties: - result: - type: string - description: Result of the probe - example: Quidem laborum ut. - example: - result: Et atque labore veniam voluptate. - required: - - result - securitySchemes: - api_key_header_X-Api-Key: - type: apiKey - name: X-Api-Key - in: header -tags: -- name: Injective Price Oracle API - description: Injective-Price-Oracle services API doc -- name: Swagger - description: The API Swagger specification -- name: health - description: HealthAPI allows to check if backend data is up-to-date and reliable - or not. diff --git a/api/gen/http/swagger/client/client.go b/api/gen/http/swagger/client/client.go deleted file mode 100644 index a0bd9b6..0000000 --- a/api/gen/http/swagger/client/client.go +++ /dev/null @@ -1,48 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger client HTTP transport -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client - -import ( - "net/http" - - goahttp "goa.design/goa/v3/http" -) - -// Client lists the Swagger service endpoint HTTP clients. -type Client struct { - // CORS Doer is the HTTP client used to make requests to the endpoint. - CORSDoer goahttp.Doer - - // RestoreResponseBody controls whether the response bodies are reset after - // decoding so they can be read again. - RestoreResponseBody bool - - scheme string - host string - encoder func(*http.Request) goahttp.Encoder - decoder func(*http.Response) goahttp.Decoder -} - -// NewClient instantiates HTTP clients for all the Swagger service servers. -func NewClient( - scheme string, - host string, - doer goahttp.Doer, - enc func(*http.Request) goahttp.Encoder, - dec func(*http.Response) goahttp.Decoder, - restoreBody bool, -) *Client { - return &Client{ - CORSDoer: doer, - RestoreResponseBody: restoreBody, - scheme: scheme, - host: host, - decoder: dec, - encoder: enc, - } -} diff --git a/api/gen/http/swagger/client/encode_decode.go b/api/gen/http/swagger/client/encode_decode.go deleted file mode 100644 index 7a58d70..0000000 --- a/api/gen/http/swagger/client/encode_decode.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger HTTP client encoders and decoders -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client diff --git a/api/gen/http/swagger/client/paths.go b/api/gen/http/swagger/client/paths.go deleted file mode 100644 index 576585b..0000000 --- a/api/gen/http/swagger/client/paths.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the Swagger service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client diff --git a/api/gen/http/swagger/client/types.go b/api/gen/http/swagger/client/types.go deleted file mode 100644 index 11c459f..0000000 --- a/api/gen/http/swagger/client/types.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger HTTP client types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package client diff --git a/api/gen/http/swagger/server/paths.go b/api/gen/http/swagger/server/paths.go deleted file mode 100644 index 72533bf..0000000 --- a/api/gen/http/swagger/server/paths.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// HTTP request path constructors for the Swagger service. -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server diff --git a/api/gen/http/swagger/server/server.go b/api/gen/http/swagger/server/server.go deleted file mode 100644 index 0db0cd3..0000000 --- a/api/gen/http/swagger/server/server.go +++ /dev/null @@ -1,138 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger HTTP server -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server - -import ( - "context" - "net/http" - - swagger "github.com/InjectiveLabs/injective-price-oracle/api/gen/swagger" - goahttp "goa.design/goa/v3/http" -) - -// Server lists the Swagger service endpoint HTTP handlers. -type Server struct { - Mounts []*MountPoint - CORS http.Handler - SwaggerIndexHTML http.Handler - Swagger http.Handler -} - -// ErrorNamer is an interface implemented by generated error structs that -// exposes the name of the error as defined in the design. -type ErrorNamer interface { - ErrorName() string -} - -// MountPoint holds information about the mounted endpoints. -type MountPoint struct { - // Method is the name of the service method served by the mounted HTTP handler. - Method string - // Verb is the HTTP method used to match requests to the mounted handler. - Verb string - // Pattern is the HTTP request path pattern used to match requests to the - // mounted handler. - Pattern string -} - -// New instantiates HTTP handlers for all the Swagger service endpoints using -// the provided encoder and decoder. The handlers are mounted on the given mux -// using the HTTP verb and path defined in the design. errhandler is called -// whenever a response fails to be encoded. formatter is used to format errors -// returned by the service methods prior to encoding. Both errhandler and -// formatter are optional and can be nil. -func New( - e *swagger.Endpoints, - mux goahttp.Muxer, - decoder func(*http.Request) goahttp.Decoder, - encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, - errhandler func(context.Context, http.ResponseWriter, error), - formatter func(err error) goahttp.Statuser, - fileSystemSwaggerIndexHTML http.FileSystem, - fileSystemSwagger http.FileSystem, -) *Server { - if fileSystemSwaggerIndexHTML == nil { - fileSystemSwaggerIndexHTML = http.Dir(".") - } - if fileSystemSwagger == nil { - fileSystemSwagger = http.Dir(".") - } - return &Server{ - Mounts: []*MountPoint{ - {"CORS", "OPTIONS", "/swagger/index.html"}, - {"CORS", "OPTIONS", "/swagger/{*path}"}, - {"./swagger/index.html", "GET", "/swagger/index.html"}, - {"./swagger/", "GET", "/swagger"}, - }, - CORS: NewCORSHandler(), - SwaggerIndexHTML: http.FileServer(fileSystemSwaggerIndexHTML), - Swagger: http.FileServer(fileSystemSwagger), - } -} - -// Service returns the name of the service served. -func (s *Server) Service() string { return "Swagger" } - -// Use wraps the server handlers with the given middleware. -func (s *Server) Use(m func(http.Handler) http.Handler) { - s.CORS = m(s.CORS) -} - -// Mount configures the mux to serve the Swagger endpoints. -func Mount(mux goahttp.Muxer, h *Server) { - MountCORSHandler(mux, h.CORS) - MountSwaggerIndexHTML(mux, goahttp.Replace("", "/./swagger/", h.SwaggerIndexHTML)) - MountSwagger(mux, goahttp.Replace("/swagger", "/./swagger/", h.Swagger)) -} - -// Mount configures the mux to serve the Swagger endpoints. -func (s *Server) Mount(mux goahttp.Muxer) { - Mount(mux, s) -} - -// MountSwaggerIndexHTML configures the mux to serve GET request made to -// "/swagger/index.html". -func MountSwaggerIndexHTML(mux goahttp.Muxer, h http.Handler) { - mux.Handle("GET", "/swagger/index.html", HandleSwaggerOrigin(h).ServeHTTP) -} - -// MountSwagger configures the mux to serve GET request made to "/swagger". -func MountSwagger(mux goahttp.Muxer, h http.Handler) { - mux.Handle("GET", "/swagger/", HandleSwaggerOrigin(h).ServeHTTP) - mux.Handle("GET", "/swagger/*path", HandleSwaggerOrigin(h).ServeHTTP) -} - -// MountCORSHandler configures the mux to serve the CORS endpoints for the -// service Swagger. -func MountCORSHandler(mux goahttp.Muxer, h http.Handler) { - h = HandleSwaggerOrigin(h) - mux.Handle("OPTIONS", "/swagger/index.html", h.ServeHTTP) - mux.Handle("OPTIONS", "/swagger/{*path}", h.ServeHTTP) -} - -// NewCORSHandler creates a HTTP handler which returns a simple 200 response. -func NewCORSHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(200) - }) -} - -// HandleSwaggerOrigin applies the CORS response headers corresponding to the -// origin for the service Swagger. -func HandleSwaggerOrigin(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - origin := r.Header.Get("Origin") - if origin == "" { - // Not a CORS request - h.ServeHTTP(w, r) - return - } - h.ServeHTTP(w, r) - return - }) -} diff --git a/api/gen/http/swagger/server/types.go b/api/gen/http/swagger/server/types.go deleted file mode 100644 index 9184f8e..0000000 --- a/api/gen/http/swagger/server/types.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger HTTP server types -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package server diff --git a/api/gen/injective_price_oracle_api/client.go b/api/gen/injective_price_oracle_api/client.go deleted file mode 100644 index 517b8ef..0000000 --- a/api/gen/injective_price_oracle_api/client.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API client -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package injectivepriceoracleapi - -import ( - "context" - - goa "goa.design/goa/v3/pkg" -) - -// Client is the "Injective Price Oracle API" service client. -type Client struct { - ProbeEndpoint goa.Endpoint -} - -// NewClient initializes a "Injective Price Oracle API" service client given -// the endpoints. -func NewClient(probe goa.Endpoint) *Client { - return &Client{ - ProbeEndpoint: probe, - } -} - -// Probe calls the "probe" endpoint of the "Injective Price Oracle API" service. -func (c *Client) Probe(ctx context.Context, p *ProbePayload) (res *ProbeResponse, err error) { - var ires interface{} - ires, err = c.ProbeEndpoint(ctx, p) - if err != nil { - return - } - return ires.(*ProbeResponse), nil -} diff --git a/api/gen/injective_price_oracle_api/endpoints.go b/api/gen/injective_price_oracle_api/endpoints.go deleted file mode 100644 index 7d3a0bf..0000000 --- a/api/gen/injective_price_oracle_api/endpoints.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API endpoints -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package injectivepriceoracleapi - -import ( - "context" - - goa "goa.design/goa/v3/pkg" - "goa.design/goa/v3/security" -) - -// Endpoints wraps the "Injective Price Oracle API" service endpoints. -type Endpoints struct { - Probe goa.Endpoint -} - -// NewEndpoints wraps the methods of the "Injective Price Oracle API" service -// with endpoints. -func NewEndpoints(s Service) *Endpoints { - // Casting service to Auther interface - a := s.(Auther) - return &Endpoints{ - Probe: NewProbeEndpoint(s, a.APIKeyAuth), - } -} - -// Use applies the given middleware to all the "Injective Price Oracle API" -// service endpoints. -func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { - e.Probe = m(e.Probe) -} - -// NewProbeEndpoint returns an endpoint function that calls the method "probe" -// of service "Injective Price Oracle API". -func NewProbeEndpoint(s Service, authAPIKeyFn security.AuthAPIKeyFunc) goa.Endpoint { - return func(ctx context.Context, req interface{}) (interface{}, error) { - p := req.(*ProbePayload) - var err error - sc := security.APIKeyScheme{ - Name: "api_key", - Scopes: []string{"api:read"}, - RequiredScopes: []string{}, - } - var key string - if p.Key != nil { - key = *p.Key - } - ctx, err = authAPIKeyFn(ctx, key, &sc) - if err != nil { - return nil, err - } - return s.Probe(ctx, p) - } -} diff --git a/api/gen/injective_price_oracle_api/service.go b/api/gen/injective_price_oracle_api/service.go deleted file mode 100644 index 3545ba0..0000000 --- a/api/gen/injective_price_oracle_api/service.go +++ /dev/null @@ -1,89 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Injective Price Oracle API service -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package injectivepriceoracleapi - -import ( - "context" - - goa "goa.design/goa/v3/pkg" - "goa.design/goa/v3/security" -) - -// Injective-Price-Oracle services API doc -type Service interface { - // Validate TOML file - Probe(context.Context, *ProbePayload) (res *ProbeResponse, err error) -} - -// Auther defines the authorization functions to be implemented by the service. -type Auther interface { - // APIKeyAuth implements the authorization logic for the APIKey security scheme. - APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error) -} - -// ServiceName is the name of the service as defined in the design. This is the -// same value that is set in the endpoint request contexts under the ServiceKey -// key. -const ServiceName = "Injective Price Oracle API" - -// MethodNames lists the service method names as defined in the design. These -// are the same values that are set in the endpoint request contexts under the -// MethodKey key. -var MethodNames = [1]string{"probe"} - -// ProbePayload is the payload type of the Injective Price Oracle API service -// probe method. -type ProbePayload struct { - // API key for authentication - Key *string - // TOML file contents - Content []byte -} - -// ProbeResponse is the result type of the Injective Price Oracle API service -// probe method. -type ProbeResponse struct { - // Result of the probe - Result string -} - -// MakeInvalidArg builds a goa.ServiceError from an error. -func MakeInvalidArg(err error) *goa.ServiceError { - return &goa.ServiceError{ - Name: "invalid_arg", - ID: goa.NewErrorID(), - Message: err.Error(), - } -} - -// MakeNotFound builds a goa.ServiceError from an error. -func MakeNotFound(err error) *goa.ServiceError { - return &goa.ServiceError{ - Name: "not_found", - ID: goa.NewErrorID(), - Message: err.Error(), - } -} - -// MakeInternal builds a goa.ServiceError from an error. -func MakeInternal(err error) *goa.ServiceError { - return &goa.ServiceError{ - Name: "internal", - ID: goa.NewErrorID(), - Message: err.Error(), - } -} - -// MakeUnauthorized builds a goa.ServiceError from an error. -func MakeUnauthorized(err error) *goa.ServiceError { - return &goa.ServiceError{ - Name: "unauthorized", - ID: goa.NewErrorID(), - Message: err.Error(), - } -} diff --git a/api/gen/swagger/client.go b/api/gen/swagger/client.go deleted file mode 100644 index 3bbb226..0000000 --- a/api/gen/swagger/client.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger client -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package swagger - -import ( - goa "goa.design/goa/v3/pkg" -) - -// Client is the "Swagger" service client. -type Client struct { -} - -// NewClient initializes a "Swagger" service client given the endpoints. -func NewClient(goa.Endpoint) *Client { - return &Client{} -} diff --git a/api/gen/swagger/endpoints.go b/api/gen/swagger/endpoints.go deleted file mode 100644 index 8fc29cd..0000000 --- a/api/gen/swagger/endpoints.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger endpoints -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package swagger - -import ( - goa "goa.design/goa/v3/pkg" -) - -// Endpoints wraps the "Swagger" service endpoints. -type Endpoints struct { -} - -// NewEndpoints wraps the methods of the "Swagger" service with endpoints. -func NewEndpoints(s Service) *Endpoints { - return &Endpoints{} -} - -// Use applies the given middleware to all the "Swagger" service endpoints. -func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { -} diff --git a/api/gen/swagger/service.go b/api/gen/swagger/service.go deleted file mode 100644 index 6bbcb58..0000000 --- a/api/gen/swagger/service.go +++ /dev/null @@ -1,22 +0,0 @@ -// Code generated by goa v3.7.0, DO NOT EDIT. -// -// Swagger service -// -// Command: -// $ goa gen github.com/InjectiveLabs/injective-price-oracle/api/design -o ../ - -package swagger - -// The API Swagger specification -type Service interface { -} - -// ServiceName is the name of the service as defined in the design. This is the -// same value that is set in the endpoint request contexts under the ServiceKey -// key. -const ServiceName = "Swagger" - -// MethodNames lists the service method names as defined in the design. These -// are the same values that are set in the endpoint request contexts under the -// MethodKey key. -var MethodNames = [0]string{} diff --git a/cmd/injective-price-oracle/api.go b/cmd/injective-price-oracle/api.go deleted file mode 100644 index 2539f0b..0000000 --- a/cmd/injective-price-oracle/api.go +++ /dev/null @@ -1,276 +0,0 @@ -package main - -import ( - "context" - "fmt" - "io" - "mime/multipart" - "net/http" - "os/signal" - "syscall" - "time" - - "github.com/InjectiveLabs/metrics" - - api_health_rpc "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/pb" - api_health "github.com/InjectiveLabs/injective-price-oracle/api/gen/grpc/health/server" - api_health_service "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" - api_health_http_server "github.com/InjectiveLabs/injective-price-oracle/api/gen/http/health/server" - api_http_server "github.com/InjectiveLabs/injective-price-oracle/api/gen/http/injective_price_oracle_api/server" - swaggerHTTPServer "github.com/InjectiveLabs/injective-price-oracle/api/gen/http/swagger/server" - api_server_service "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" - swaggerEndpoints "github.com/InjectiveLabs/injective-price-oracle/api/gen/swagger" - "github.com/InjectiveLabs/injective-price-oracle/internal/service/health" - "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle" - "github.com/InjectiveLabs/injective-price-oracle/internal/service/swagger" - - log "github.com/InjectiveLabs/suplog" - "github.com/improbable-eng/grpc-web/go/grpcweb" - cli "github.com/jawher/mow.cli" - "github.com/pkg/errors" - "github.com/rs/cors" - goahttp "goa.design/goa/v3/http" - goaMiddleware "goa.design/goa/v3/middleware" - "google.golang.org/grpc" -) - -// apiCmd action runs the service -// -// $ injective-price-oracle api -func apiCmd(cmd *cli.Cmd) { - var ( - // Metrics - statsdPrefix *string - statsdAddr *string - statsdAgent *string - statsdStuckDur *string - statsdMocking *string - statsdDisabled *string - - grpcWebListenAddress *string - grpcWebRequestTimeout *string - apiKey *string - ) - - initStatsdOptions( - cmd, - &statsdPrefix, - &statsdAddr, - &statsdAgent, - &statsdStuckDur, - &statsdMocking, - &statsdDisabled, - ) - - iniAPIOptions( - cmd, - &grpcWebListenAddress, - &grpcWebRequestTimeout, - &apiKey, - ) - - cmd.Action = func() { - ctx := context.Background() - ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) - defer cancel() - - startMetricsGathering( - statsdPrefix, - statsdAddr, - statsdAgent, - statsdStuckDur, - statsdMocking, - statsdDisabled, - ) - - grpcWebMux := goahttp.NewMuxer() - - requestTimeout, err := time.ParseDuration(*grpcWebRequestTimeout) - panicIf(err) - grpcServer := grpc.NewServer(grpc.ChainUnaryInterceptor(TimeoutInterceptor(requestTimeout))) - - apiSvc := oracle.NewAPIService(*apiKey) - - // Initialize and register Health Service - healthSvc := health.NewHealthService(log.DefaultLogger, metrics.Tags{ - "svc": "health", - }) - log.Infof("created API service") - - grpcHealthRouter := api_health.New( - api_health_service.NewEndpoints(healthSvc), - nil, - ) - - api_health_rpc.RegisterHealthServer(grpcServer, grpcHealthRouter) - - // http health api - healthHTTPRouter := api_health_http_server.New( - api_health_service.NewEndpoints(healthSvc), - grpcWebMux, - goahttp.RequestDecoder, - goahttp.ResponseEncoder, - newErrorHandler(log.DefaultLogger), - nil, - ) - - api_health_http_server.Mount(grpcWebMux, healthHTTPRouter) - - // http api - apiRouter := api_http_server.New( - api_server_service.NewEndpoints(apiSvc), - grpcWebMux, - goahttp.RequestDecoder, - goahttp.ResponseEncoder, - newErrorHandler(log.DefaultLogger), - nil, - DecodeInjectivePriceOracleAPIProbeRequest, - ) - - api_http_server.Mount(grpcWebMux, apiRouter) - - swaggerSvc := swagger.NewSwaggerService() - - swaggerRouter := swaggerHTTPServer.New( - swaggerEndpoints.NewEndpoints(swaggerSvc), - grpcWebMux, - goahttp.RequestDecoder, - goahttp.ResponseEncoder, - newErrorHandler(log.DefaultLogger), - nil, - nil, - nil, - ) - swaggerHTTPServer.Mount(grpcWebMux, swaggerRouter) - - // only need to serve Grpc-Web - handlerWithCors := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{ - http.MethodHead, - http.MethodGet, - http.MethodPost, - http.MethodPut, - http.MethodPatch, - http.MethodDelete, - }, - AllowedHeaders: []string{"*"}, - AllowCredentials: false, - OptionsPassthrough: false, - }) - - grpcWeb := grpcweb.WrapServer(grpcServer) - mountGRPCWebServices(grpcWebMux, grpcWeb, grpcweb.ListGRPCResources(grpcServer), 10*time.Second) - - httpSrv := &http.Server{ - Addr: *grpcWebListenAddress, - Handler: handlerWithCors.Handler(grpcWebMux), - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - IdleTimeout: 10 * time.Second, - } - - // Start server in goroutine - go func() { - log.Infof("injective price oracle api starts listening on %s", *grpcWebListenAddress) - if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed { - log.WithError(err).Fatalln("failed to start HTTP server") - } - }() - - <-ctx.Done() - - shutdownCtx, cancelShutdown := context.WithTimeout(context.Background(), 5*time.Second) - defer cancelShutdown() - - grpcServer.GracefulStop() - - if err = httpSrv.Shutdown(shutdownCtx); err != nil { - log.WithError(err).Error("HTTP server graceful shutdown failed") - } - - log.Info("Shutdown complete") - } - -} - -func DecodeInjectivePriceOracleAPIProbeRequest(mr *multipart.Reader, payload **api_server_service.ProbePayload) error { - var ( - part *multipart.Part - err error - p = &api_server_service.ProbePayload{} - ) - - for { - part, err = mr.NextPart() - if err == io.EOF { - break - } - if part.FormName() == "content" { - data, err := io.ReadAll(part) - if err != nil { - return err - } - p.Content = data - } - } - - *payload = p - return nil -} - -func mountGRPCWebServices( - mux goahttp.Muxer, - grpcWeb *grpcweb.WrappedGrpcServer, - grpcResources []string, - requestTimeout time.Duration, -) { - for _, res := range grpcResources { - currentResource := res - - log.Infof("[GRPC Web] HTTP POST mounted on %s", currentResource) - - mux.Handle("POST", currentResource, func(resp http.ResponseWriter, req *http.Request) { - if !grpcWeb.IsGrpcWebRequest(req) { - resp.WriteHeader(400) - resp.Write([]byte(fmt.Sprintf("not a GRPC web request on %s", currentResource))) - return - } - - ctx, cancel := context.WithTimeout(req.Context(), requestTimeout) - defer cancel() - - grpcWeb.HandleGrpcWebRequest(resp, req.WithContext(ctx)) - }) - } -} - -func newErrorHandler(logger log.Logger) func(context.Context, http.ResponseWriter, error) { - type stackTracer interface { - StackTrace() errors.StackTrace - } - - return func(ctx context.Context, w http.ResponseWriter, err error) { - id, ok := ctx.Value(goaMiddleware.RequestIDKey).(string) - if !ok { - return - } - logFields := log.Fields{ - "request_id": id, - } - if errWithStack, ok := err.(stackTracer); ok { - logFields["stack_frames"] = len(errWithStack.StackTrace()) - } - logger.WithFields(logFields).Warningln(err) - fmt.Fprintf(w, "request (%s) processing internal error: %v", id, err) - } -} - -func TimeoutInterceptor(timeout time.Duration) grpc.UnaryServerInterceptor { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - ctx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - return handler(ctx, req) - } -} diff --git a/cmd/injective-price-oracle/main.go b/cmd/injective-price-oracle/main.go index 96b78c0..a59cddd 100644 --- a/cmd/injective-price-oracle/main.go +++ b/cmd/injective-price-oracle/main.go @@ -38,8 +38,6 @@ func main() { } app.Command("start", "Starts the oracle main loop.", oracleCmd) - app.Command("api", "Starts the oracle API server.", apiCmd) - app.Command("probe", "Validates target TOML file spec and runs it once, printing the result.", probeCmd) app.Command("version", "Print the version information and exit.", versionCmd) _ = app.Run(os.Args) diff --git a/cmd/injective-price-oracle/options.go b/cmd/injective-price-oracle/options.go index 7ef4931..abff222 100644 --- a/cmd/injective-price-oracle/options.go +++ b/cmd/injective-price-oracle/options.go @@ -251,29 +251,26 @@ func initStorkOracleWebSocketOptions( }) } -func iniAPIOptions( +func initChainlinkDataStreamsOptions( cmd *cli.Cmd, - grpcWebListenAddress **string, - grpcWebRequestTimeout **string, - apiKey **string, + chainlinkWsURL **string, + chainlinkAPIKey **string, + chainlinkAPISecret **string, ) { - *grpcWebListenAddress = cmd.String(cli.StringOpt{ - Name: "grpc-web-listen-address", - Desc: "GRPC_WEB_LISTEN_ADDRESS,", - EnvVar: "GRPC_WEB_LISTEN_ADDRESS", - Value: "0.0.0.0:9924", - }) - *grpcWebRequestTimeout = cmd.String(cli.StringOpt{ - Name: "grpc-web-request-timeout", - Desc: "GRPC web request timeout duration", - EnvVar: "GRPC_WEB_REQUEST_TIMEOUT", - Value: "10s", - }) - *apiKey = cmd.String(cli.StringOpt{ - Name: "api-key", - Desc: "API key for authenticating requests to the price oracle API", - EnvVar: "API_KEY", - Value: "", + *chainlinkWsURL = cmd.String(cli.StringOpt{ + Name: "chainlink-ws-url", + Desc: "Chainlink Data Streams WebSocket URL", + EnvVar: "CHAINLINK_WS_URL", + Value: "wss://ws.testnet-dataengine.chain.link", + }) + *chainlinkAPIKey = cmd.String(cli.StringOpt{ + Name: "chainlink-api-key", + Desc: "Chainlink Data Streams API Key", + EnvVar: "CHAINLINK_API_KEY", + }) + *chainlinkAPISecret = cmd.String(cli.StringOpt{ + Name: "chainlink-api-secret", + Desc: "Chainlink Data Streams API Secret", + EnvVar: "CHAINLINK_API_SECRET", }) - } diff --git a/cmd/injective-price-oracle/oracle.go b/cmd/injective-price-oracle/oracle.go index 2fc0423..d63b598 100644 --- a/cmd/injective-price-oracle/oracle.go +++ b/cmd/injective-price-oracle/oracle.go @@ -16,11 +16,16 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" cosmtypes "github.com/cosmos/cosmos-sdk/types" cli "github.com/jawher/mow.cli" + "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" + streams "github.com/smartcontractkit/data-streams-sdk/go" "github.com/xlab/closer" svcoracle "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle" - "github.com/InjectiveLabs/injective-price-oracle/pipeline" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/chainlink" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/stork" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/utils" ) type CosmosConfig struct { @@ -72,6 +77,11 @@ func oracleCmd(cmd *cli.Cmd) { websocketUrl *string websocketHeader *string websocketSubscribeMessage *string + + // Chainlink Data Streams params + chainlinkWsURL *string + chainlinkAPIKey *string + chainlinkAPISecret *string ) initCosmosOptions( @@ -120,6 +130,13 @@ func oracleCmd(cmd *cli.Cmd) { &websocketSubscribeMessage, ) + initChainlinkDataStreamsOptions( + cmd, + &chainlinkWsURL, + &chainlinkAPIKey, + &chainlinkAPISecret, + ) + cmd.Action = func() { ctx := context.Background() // ensure a clean exit @@ -192,8 +209,12 @@ func oracleCmd(cmd *cli.Cmd) { var storkEnabled bool storkMap := make(map[string]struct{}) + chainlinkMap := make(map[string]struct{}) + + var chainlinkEnabled bool + + feedConfigs := make(map[string]*types.FeedConfig) - feedConfigs := make(map[string]*svcoracle.FeedConfig) if len(*feedsDir) > 0 { err := filepath.WalkDir(*feedsDir, func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -206,25 +227,50 @@ func oracleCmd(cmd *cli.Cmd) { cfgBody, err := os.ReadFile(path) if err != nil { - err = errors.Wrapf(err, "failed to read dynamic feed config") + err = errors.Wrapf(err, "failed to read feed config") return err } - feedCfg, err := svcoracle.ParseDynamicFeedConfig(cfgBody) - if err != nil { + // First try to determine provider type by parsing as generic FeedConfig + var genericCfg types.FeedConfig + if err := toml.Unmarshal(cfgBody, &genericCfg); err != nil { log.WithError(err).WithFields(log.Fields{ "filename": d.Name(), - }).Errorln("failed to parse dynamic feed config") + }).Errorln("failed to parse feed config") return nil } - if feedCfg.ProviderName == svcoracle.FeedProviderStork.String() { + if genericCfg.ProviderName == types.FeedProviderStork.String() { storkEnabled = true + feedCfg, err := stork.ParseStorkFeedConfig(cfgBody) + if err != nil { + log.WithError(err).WithFields(log.Fields{ + "filename": d.Name(), + }).Errorln("failed to parse stork feed config") + return nil + } storkMap[feedCfg.Ticker] = struct{}{} + feedConfigs[filepath.Base(path)] = feedCfg + } else if genericCfg.ProviderName == types.FeedProviderChainlink.String() { + chainlinkEnabled = true + // Parse Chainlink specific config to extract feed IDs + feedCfg, err := chainlink.ParseChainlinkFeedConfig(cfgBody) + if err != nil { + log.WithError(err).WithFields(log.Fields{ + "filename": d.Name(), + }).Errorln("failed to parse stork feed config") + return nil + } + chainlinkMap[feedCfg.FeedID] = struct{}{} + feedConfigs[filepath.Base(path)] = feedCfg + } else { + // Unsupported provider + log.WithFields(log.Fields{ + "filename": d.Name(), + "provider": genericCfg.ProviderName, + }).Warningln("unsupported feed provider, skipping") } - feedConfigs[filepath.Base(path)] = feedCfg - return nil }) @@ -237,7 +283,7 @@ func oracleCmd(cmd *cli.Cmd) { log.Infof("found %d dynamic feed configs", len(feedConfigs)) } - var storkFetcher svcoracle.StorkFetcher + var storkFetcher stork.StorkFetcher if storkEnabled { var storkTickers []string @@ -245,7 +291,40 @@ func oracleCmd(cmd *cli.Cmd) { storkTickers = append(storkTickers, ticker) } - storkFetcher = svcoracle.NewStorkFetcher(*websocketSubscribeMessage, storkTickers) + storkFetcher = stork.NewFetcher(*websocketSubscribeMessage, storkTickers) + } + + var chainlinkFetcher chainlink.ChainLinkFetcher + + if chainlinkEnabled { + var feeds []string + for feedID := range chainlinkMap { + feeds = append(feeds, feedID) + } + + // Set up the SDK client configuration + cfg := streams.Config{ + ApiKey: *chainlinkAPIKey, + ApiSecret: *chainlinkAPISecret, + WsURL: *chainlinkWsURL, + Logger: streams.LogPrintf, + } + + log.Infoln("creating Chainlink Data Streams client") + log.Infoln("Chainlink Data Streams WS URL:", cfg.WsURL) + log.Infoln("Chainlink Data Streams Feeds:", feeds) + + client, err := streams.New(cfg) + if err != nil { + log.WithError(err).Fatalln("failed to create Chainlink Data Streams client") + return + } + + fetcher, err := chainlink.NewFetcher(client, feeds) + if err != nil { + log.WithError(err).Fatalln("failed to create Chainlink fetcher") + } + chainlinkFetcher = fetcher } svc, err := svcoracle.NewService( @@ -253,6 +332,7 @@ func oracleCmd(cmd *cli.Cmd) { cosmosClients, feedConfigs, storkFetcher, + chainlinkFetcher, ) if err != nil { log.Fatalln(err) @@ -275,7 +355,7 @@ func oracleCmd(cmd *cli.Cmd) { } connectIn = 5 * time.Second - conn, err := pipeline.ConnectWebSocket(ctx, *websocketUrl, *websocketHeader, svcoracle.MaxRetriesReConnectWebSocket) + conn, err := utils.ConnectWebSocket(ctx, *websocketUrl, *websocketHeader, svcoracle.MaxRetriesReConnectWebSocket) if err != nil { log.WithError(err).Errorln("failed to connect to WebSocket") continue @@ -288,6 +368,27 @@ func oracleCmd(cmd *cli.Cmd) { } }() + go func() { + if chainlinkFetcher == nil { + return // no chainlink feeds + } + + for { + select { + case <-ctx.Done(): + return + default: + } + + err := chainlinkFetcher.Start(ctx) + if err != nil { + log.WithError(err).Errorln("chainlink fetcher failed, retrying in 5 seconds") + time.Sleep(5 * time.Second) + continue + } + } + }() + go func() { if err := svc.Start(ctx); err != nil { log.Errorln(err) diff --git a/cmd/injective-price-oracle/probe.go b/cmd/injective-price-oracle/probe.go deleted file mode 100644 index 79e111a..0000000 --- a/cmd/injective-price-oracle/probe.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "context" - "io/ioutil" - - log "github.com/InjectiveLabs/suplog" - cli "github.com/jawher/mow.cli" - "github.com/xlab/closer" - - "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle" -) - -// probeCmd action validates target TOML file spec and runs it once, printing the result. -// -// $ injective-price-oracle probe -func probeCmd(cmd *cli.Cmd) { - tomlSource := cmd.StringArg("FILE", "", "Path to target TOML file with pipeline spec") - - cmd.Action = func() { - // ensure a clean exit - defer closer.Close() - - cfgBody, err := ioutil.ReadFile(*tomlSource) - if err != nil { - log.WithField("file", *tomlSource).WithError(err).Fatalln("failed to read dynamic feed config") - return - } - - feedCfg, err := oracle.ParseDynamicFeedConfig(cfgBody) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "file": *tomlSource, - }).Errorln("failed to parse dynamic feed config") - return - } - - pricePuller, err := oracle.NewDynamicPriceFeed(feedCfg) - if err != nil { - log.WithError(err).Fatalln("failed to init new dynamic price feed") - return - } - - pullerLogger := log.WithFields(log.Fields{ - "provider_name": pricePuller.ProviderName(), - "symbol": pricePuller.Symbol(), - "oracle_type": pricePuller.OracleType().String(), - }) - - answer, err := pricePuller.PullPrice(context.Background()) - if err != nil { - pullerLogger.WithError(err).Errorln("failed to pull price") - return - } - - log.Infof("Answer: %s", answer.Price) - } -} diff --git a/examples/mainnet_chainlink_btc_usd.toml b/examples/mainnet_chainlink_btc_usd.toml new file mode 100644 index 0000000..f6b4d4b --- /dev/null +++ b/examples/mainnet_chainlink_btc_usd.toml @@ -0,0 +1,5 @@ +provider = "chainlink" +feedId = "0x00081e842c78eee5a521e7c876e749715e980f07349f9edf868fe1078403d6b1" +ticker = "BTC/USD" +pullInterval = "1s" +oracleType = "Chainlink" \ No newline at end of file diff --git a/examples/mainnet_chainlink_googl_usd.toml b/examples/mainnet_chainlink_googl_usd.toml new file mode 100644 index 0000000..d925f72 --- /dev/null +++ b/examples/mainnet_chainlink_googl_usd.toml @@ -0,0 +1,5 @@ +provider = "chainlink" +feedId = "0x00039d9e45394f473ab1f050a1b963e6b05351e52d71e507509ada0c95ed75b8" +ticker = "GOOGL/USD" +pullInterval = "1s" +oracleType = "Chainlink" \ No newline at end of file diff --git a/examples/testnet_chainlink_btc_usd.toml b/examples/testnet_chainlink_btc_usd.toml new file mode 100644 index 0000000..a2e5951 --- /dev/null +++ b/examples/testnet_chainlink_btc_usd.toml @@ -0,0 +1,5 @@ +provider = "chainlink" +feedId = "0x00037da06d56d083fe599397a4769a042d63aa73dc4ef57709d31e9971a5b439" +ticker = "BTC/USD" +pullInterval = "1s" +oracleType = "Chainlink" diff --git a/examples/testnet_chainlink_tsla_usd.toml b/examples/testnet_chainlink_tsla_usd.toml new file mode 100644 index 0000000..c297234 --- /dev/null +++ b/examples/testnet_chainlink_tsla_usd.toml @@ -0,0 +1,5 @@ +provider = "chainlink" +feedId = "0x000890039996f52efbfa66e193d077fd4aa6fa12009688f7f6606a64cc0c25ad" +ticker = "TSLA/USD" +pullInterval = "1s" +oracleType = "Chainlink" diff --git a/gen/Dockerfile b/gen/Dockerfile deleted file mode 100644 index 0f87f67..0000000 --- a/gen/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM golang:1.24.0-alpine - -RUN apk add --no-cache git make protoc nodejs npm libc6-compat - -RUN go install goa.design/goa/v3/cmd/goa@v3.7.0 \ - && go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.30.0 \ - && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0 \ - && go install github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc@v1.5.1 \ - && go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.15.0 \ - && go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.16.0 \ - && go install go.uber.org/mock/mockgen@v0.5.0 - -RUN npm install -g ts-protoc-gen protoc-gen-js - -ARG GH_USER -ARG GH_TOKEN - -RUN echo "machine github.com login $GH_USER password $GH_TOKEN" > /root/.netrc \ No newline at end of file diff --git a/gen/gen-goa.sh b/gen/gen-goa.sh deleted file mode 100755 index 0864b79..0000000 --- a/gen/gen-goa.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail - -echo "start generating goagen code" -rm -rf ./api/gen -go env -w GOFLAGS=-buildvcs=false -go generate ./api/... -cp -rf ./api/gen/http/openapi3.json ./swagger/swagger.json \ No newline at end of file diff --git a/go.mod b/go.mod index 753e156..ba5c6d0 100644 --- a/go.mod +++ b/go.mod @@ -5,29 +5,19 @@ go 1.24.0 require ( cosmossdk.io/math v1.4.0 github.com/InjectiveLabs/metrics v0.0.21 - github.com/InjectiveLabs/sdk-go v1.58.0 + github.com/InjectiveLabs/sdk-go v1.60.0-rc1 github.com/InjectiveLabs/suplog v1.3.4 github.com/cometbft/cometbft v1.0.1 - github.com/cosmos/cosmos-sdk v0.50.9 + github.com/cosmos/cosmos-sdk v0.50.12 github.com/ethereum/go-ethereum v1.15.7 github.com/gorilla/websocket v1.5.3 - github.com/improbable-eng/grpc-web v0.15.0 github.com/jawher/mow.cli v1.2.0 - github.com/jpillora/backoff v1.0.0 - github.com/mitchellh/mapstructure v1.5.0 github.com/pelletier/go-toml/v2 v2.2.3 github.com/pkg/errors v0.9.1 - github.com/rs/cors v1.11.1 - github.com/satori/go.uuid v1.2.0 github.com/shopspring/decimal v1.2.0 + github.com/smartcontractkit/data-streams-sdk/go v1.2.0 github.com/xlab/closer v0.0.0-20190328110542-03326addb7c2 - go.uber.org/multierr v1.11.0 - goa.design/goa/v3 v3.7.0 - goa.design/plugins/v3 v3.5.5 - gonum.org/v1/gonum v0.16.0 google.golang.org/grpc v1.75.1 - google.golang.org/protobuf v1.36.9 - gopkg.in/guregu/null.v4 v4.0.0 ) require ( @@ -64,6 +54,7 @@ require ( github.com/alexcesaro/statsd v2.0.0+incompatible // indirect github.com/aws/aws-sdk-go v1.44.327 // indirect github.com/bandprotocol/bandchain-packet v0.0.4 // indirect + github.com/bcp-innovations/hyperlane-cosmos v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.22.0 // indirect @@ -79,20 +70,19 @@ require ( github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect - github.com/cockroachdb/pebble v1.1.4 // indirect + github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v1.0.4 // indirect github.com/cometbft/cometbft/api v1.0.0 // indirect - github.com/consensys/bavard v0.1.30 // indirect - github.com/consensys/gnark-crypto v0.17.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.1.1 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 // indirect - github.com/cosmos/iavl v1.2.2 // indirect + github.com/cosmos/iavl v1.2.6 // indirect github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect github.com/cosmos/ibc-go/v8 v8.6.1 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect @@ -106,8 +96,6 @@ require ( github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v4 v4.6.0 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect - github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 // indirect - github.com/dimfeld/httptreemux/v5 v5.5.0 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -155,6 +143,7 @@ require ( github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect + github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -165,13 +154,12 @@ require ( github.com/linxGnu/grocksdb v1.9.8 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect - github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mixpanel/mixpanel-go v1.2.1 // indirect - github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect @@ -191,12 +179,12 @@ require ( github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.33.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shamaton/msgpack/v2 v2.2.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -218,7 +206,6 @@ require ( github.com/tklauser/numcpus v0.10.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.4.0 // indirect @@ -227,28 +214,27 @@ require ( go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.42.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/mod v0.28.0 // indirect golang.org/x/net v0.44.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.36.0 // indirect golang.org/x/term v0.35.0 // indirect golang.org/x/text v0.29.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.36.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect - nhooyr.io/websocket v1.8.6 // indirect + nhooyr.io/websocket v1.8.11 // indirect pgregory.net/rapid v1.1.0 // indirect - rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 82a5b14..bdcf8d6 100644 --- a/go.sum +++ b/go.sum @@ -1508,12 +1508,11 @@ github.com/InjectiveLabs/go-ethereum v1.15.11-inj h1:ErgCmRgz/U4rBP4oKmvT/RXLhxR github.com/InjectiveLabs/go-ethereum v1.15.11-inj/go.mod h1:LEmqeZSAb2/+Kvx/rH+OocHJqpsYF4rMJ2BSZW4C8jM= github.com/InjectiveLabs/ibc-go/v8 v8.7.0-evm-comet1-inj h1:yuSodqSSgIwSQyLUJ45j+jCCUtuYNdo8Vj5YOkKjLx8= github.com/InjectiveLabs/ibc-go/v8 v8.7.0-evm-comet1-inj/go.mod h1:JnZjgZ9KyhXp3HFjtGXkM2ByyPfJWjAnz2KMCmFK3po= -github.com/InjectiveLabs/metrics v0.0.10 h1:BoOwXnCtRRIPmq06jcI20pXZYE758eusaCI5jDOoN4U= github.com/InjectiveLabs/metrics v0.0.10/go.mod h1:eYu++0DVUjk/jjV9WgvCo8gQU+16Yoyhp1iu+ghKNME= github.com/InjectiveLabs/metrics v0.0.21 h1:/oEOJryuY+34+6pIYO+EvJVn7MV267OD1v9MkyM2Cpw= github.com/InjectiveLabs/metrics v0.0.21/go.mod h1:oDwGiKYrI9EplQDJzzBwvKsdCNyvGeTonxb91HauZmk= -github.com/InjectiveLabs/sdk-go v1.58.0 h1:n5bPcZMYP1o4uJbvtqsknqvhu8Ff0l8f72D1jdA99ig= -github.com/InjectiveLabs/sdk-go v1.58.0/go.mod h1:/LNZhVsHMpb3YUnWcLu7+p3fUUz9XLxhEzFfebFR9Mg= +github.com/InjectiveLabs/sdk-go v1.60.0-rc1 h1:NFRnFv0oib3pdkUgSfp08hFjzdZ+5kehEvYjNSyesbY= +github.com/InjectiveLabs/sdk-go v1.60.0-rc1/go.mod h1:WpShs1DknsncOOFQ/WvMcNaPTKiG3/Bu2Ji8K23PvFg= github.com/InjectiveLabs/suplog v1.3.4 h1:Ex3qj19FkKjlJVOpqEzLnPFlFtuV3FV4zR5w9JnG2/0= github.com/InjectiveLabs/suplog v1.3.4/go.mod h1:+I9WRgUhzmo1V/n7IkW24kFBFB9ZTPAiXXXCogWxmTM= github.com/InjectiveLabs/wasmd v0.53.2-evm-comet1-inj h1:UgdJzfF6OC7Bz8d9WooRKHCLAwlghuqL3pnZcbr6aS4= @@ -1697,6 +1696,8 @@ github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/bcp-innovations/hyperlane-cosmos v1.0.1 h1:gT8OqyJ866Q6AHOlIXKxSdLjd0p8crKG9XXERIWoh4c= +github.com/bcp-innovations/hyperlane-cosmos v1.0.1/go.mod h1:3yfa0io5Ii6GmhHWsWl2LEAOEHsqWuMgw2R02+LPogw= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -1776,7 +1777,6 @@ github.com/bytecodealliance/wasmtime-go v0.36.0/go.mod h1:q320gUxqyI8yB+ZqRuaJOE github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -1806,9 +1806,7 @@ github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAc github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= @@ -1889,8 +1887,9 @@ github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= -github.com/cockroachdb/pebble v1.1.4 h1:5II1uEP4MyHLDnsrbv/EZ36arcb9Mxg3n+owhZ3GrG8= github.com/cockroachdb/pebble v1.1.4/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= @@ -1907,10 +1906,8 @@ github.com/cometbft/cometbft-db v1.0.4/go.mod h1:M+BtHAGU2XLrpUxo3Nn1nOCcnVCiLM9 github.com/cometbft/cometbft-load-test v0.3.0/go.mod h1:zKrQpRm3Ay5+RfeRTNWoLniFJNIPnw9JPEM1wuWS3TA= github.com/confluentinc/confluent-kafka-go v1.9.2/go.mod h1:ptXNqsuDfYbAE/LBW6pnwWZElUoWxHoV8E43DCrliyo= github.com/confluentinc/confluent-kafka-go/v2 v2.2.0/go.mod h1:mfGzHbxQ6LRc25qqaLotDHkhdYmeZQ3ctcKNlPUjDW4= -github.com/consensys/bavard v0.1.30 h1:wwAj9lSnMLFXjEclKwyhf7Oslg8EoaFz9u1QGgt0bsk= -github.com/consensys/bavard v0.1.30/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.17.0 h1:vKDhZMOrySbpZDCvGMOELrHFv/A9mJ7+9I8HEfRZSkI= -github.com/consensys/gnark-crypto v0.17.0/go.mod h1:A2URlMHUT81ifJ0UlLzSlm7TmnE3t7VxEThApdMukJw= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/container-orchestrated-devices/container-device-interface v0.5.4/go.mod h1:DjE95rfPiiSmG7uVXtg0z6MnPm/Lx4wxKCIts0ZE0vg= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= @@ -2074,8 +2071,9 @@ github.com/cosmos/gogoproto v1.5.0/go.mod h1:iUM31aofn3ymidYG6bUR5ZFrk+Om8p5s754 github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= -github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= +github.com/cosmos/iavl v1.2.6 h1:Hs3LndJbkIB+rEvToKJFXZvKo6Vy0Ex1SJ54hhtioIs= +github.com/cosmos/iavl v1.2.6/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= @@ -2157,10 +2155,6 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 h1:MGKhKyiYrvMDZsmLR/+RGffQSXwEkXgfLSA08qDn9AI= -github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598/go.mod h1:0FpDmbrt36utu8jEmeU05dPC9AB5tsLYVVi+ZHfyuwI= -github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= -github.com/dimfeld/httptreemux/v5 v5.5.0 h1:p8jkiMrCuZ0CmhwYLcbNbl7DDo21fozhKHQ2PccwOFQ= github.com/dimfeld/httptreemux/v5 v5.5.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= github.com/distribution/distribution/v3 v3.0.0-20220526142353-ffbd94cbe269/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= @@ -2331,15 +2325,11 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getkin/kin-openapi v0.88.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getkin/kin-openapi v0.92.0 h1:lR1imqtGufk9Iv5dQoGwWbBP2SMcwI2ndIydSqwUyBI= -github.com/getkin/kin-openapi v0.92.0/go.mod h1:LWZfzOd7PRy8GJ1dJ6mCU6tNdSfOwRac1BUPam4aw6Q= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/getsentry/sentry-go v0.21.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= @@ -2349,15 +2339,12 @@ github.com/getsentry/sentry-go v0.31.1 h1:ELVc0h7gwyhnXHDouXkhqTFSO5oslsRDk0++ey github.com/getsentry/sentry-go v0.31.1/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -2440,7 +2427,6 @@ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= @@ -2452,8 +2438,6 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= @@ -2465,18 +2449,15 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= @@ -2489,7 +2470,9 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= @@ -2500,22 +2483,17 @@ github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22/go.mod h github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= -github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= github.com/goccmack/goutil v1.2.3/go.mod h1:dPBoKv07AeI2DGYE3ECrSLOLpGaBIBGCUCGKHclOPyU= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= -github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/gocql/gocql v0.0.0-20220224095938-0eacd3183625/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= @@ -2668,8 +2646,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4 h1:OL2d27ueTKnlQJoqLW2fc9pWYulFnJYLWzomGV7HqZo= -github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -2708,7 +2684,6 @@ github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -2759,7 +2734,6 @@ github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= @@ -2985,6 +2959,8 @@ github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0 github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= +github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jawher/mow.cli v1.2.0 h1:e6ViPPy+82A/NFF/cfbq3Lr6q4JHKT9tyHwTCcUQgQw= github.com/jawher/mow.cli v1.2.0/go.mod h1:y+pcA3jBAdo/GIZx/0rFjw/K2bVEODP9rfZOfaiq8Ko= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= @@ -3029,9 +3005,7 @@ github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Cc github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -3040,11 +3014,9 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= @@ -3110,13 +3082,11 @@ github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -3150,7 +3120,6 @@ github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= @@ -3202,14 +3171,9 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= -github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d h1:Zj+PHjnhRYWBK6RqCDBcAhLXoi3TzC27Zad/Vn+gnVQ= -github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d/go.mod h1:WZy8Q5coAB1zhY9AOBJP0O6J4BuDfbupUDavKY+I3+s= -github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b h1:3E44bLeN8uKYdfQqVQycPnaVviZdBLbizFhU49mtbe4= -github.com/manveru/gobdd v0.0.0-20131210092515-f1a17fdd710b/go.mod h1:Bj8LjjP0ReT1eKt5QlKjwgi5AFm5mI6O1A2G4ChI0Ag= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= @@ -3311,9 +3275,6 @@ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mixpanel/mixpanel-go v1.2.1 h1:iykbHKomTJjVoWU95Vt1sjZy4HLt8UOYacMEEEMFBok= github.com/mixpanel/mixpanel-go v1.2.1/go.mod h1:mPGaNhBoZMJuLu8k7Y1KhU5n8Vw13rxQZZjHj+b9RLk= -github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= -github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= -github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= @@ -3336,11 +3297,9 @@ github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6U github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= @@ -3442,6 +3401,7 @@ github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7 github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -3756,7 +3716,6 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.2.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= @@ -3772,7 +3731,6 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= @@ -3798,14 +3756,14 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/smartcontractkit/data-streams-sdk/go v1.2.0 h1:wA5p2VdiITjfnVfmSVNi6R4cL+mGewXXssPE+Jzhd1k= +github.com/smartcontractkit/data-streams-sdk/go v1.2.0/go.mod h1:/fFD/9Fbpicp5XdzWyc8Kkw4JLBm3lEBVmpMGh4PVT4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -3956,18 +3914,15 @@ github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GH github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -4047,8 +4002,6 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI= -github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea/go.mod h1:eNr558nEUjP8acGw8FFjTeWvSgU1stO7FAO6eknhHe4= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= @@ -4260,16 +4213,9 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -goa.design/goa/v3 v3.5.5/go.mod h1:fKBXWhT+vF6pqXQc9bb81D48WAQ38lm72iRN4VlPE0Y= -goa.design/goa/v3 v3.7.0 h1:yQfWNvee4tpR4YyZq5mz+gWhVyN0SDhne+sbS0y9WRE= -goa.design/goa/v3 v3.7.0/go.mod h1:ZTtOqLweXERJmfOfdKsUscAWWph+e3aS9WGAOmpxl1k= -goa.design/plugins/v3 v3.5.5 h1:hv9RsmccionWAHOYuxiUKxVWa1WAA9LpLshelboDpwo= -goa.design/plugins/v3 v3.5.5/go.mod h1:TFf5+NzL5zeQoXsZmbUemDFhZ8xA42ciEU69ASVSOjA= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -4459,8 +4405,6 @@ golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -5267,7 +5211,6 @@ google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220204002441-d6cc3cc0770e/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= @@ -5607,8 +5550,6 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= -gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/httprequest.v1 v1.2.1/go.mod h1:x2Otw96yda5+8+6ZeWwHIJTFkEHWP/qP8pJOzqEtWPM= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -5807,8 +5748,9 @@ modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= +nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= @@ -5818,8 +5760,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= -rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= diff --git a/internal/service/health/health.go b/internal/service/health/health.go deleted file mode 100644 index 066ce8a..0000000 --- a/internal/service/health/health.go +++ /dev/null @@ -1,34 +0,0 @@ -package health - -import ( - "context" - - "github.com/InjectiveLabs/metrics" - log "github.com/InjectiveLabs/suplog" - - injectivehealthapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/health" -) - -type Service struct { - logger log.Logger - svcTags metrics.Tags -} - -func NewHealthService(logger log.Logger, svcTags metrics.Tags) *Service { - return &Service{ - logger: logger, - svcTags: svcTags, - } -} - -// GetStatus Get the latest block. -func (s *Service) GetStatus(_ context.Context) (res *injectivehealthapi.HealthStatusResponse, err error) { - defer metrics.ReportFuncCallAndTimingWithErr(s.svcTags)(&err) - - return &injectivehealthapi.HealthStatusResponse{ - Errmsg: nil, - Data: &injectivehealthapi.HealthStatus{}, - S: "ok", - Status: "ok", - }, nil -} diff --git a/internal/service/oracle/api.go b/internal/service/oracle/api.go deleted file mode 100644 index b394555..0000000 --- a/internal/service/oracle/api.go +++ /dev/null @@ -1,105 +0,0 @@ -package oracle - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - "goa.design/goa/v3/security" - - log "github.com/InjectiveLabs/suplog" - - injectivepriceoracleapi "github.com/InjectiveLabs/injective-price-oracle/api/gen/injective_price_oracle_api" -) - -type apiSvc struct { - APIKey string -} - -type APIService interface { - APIKeyAuth(ctx context.Context, key string, schema *security.APIKeyScheme) (context.Context, error) - Probe(ctx context.Context, payload *injectivepriceoracleapi.ProbePayload) (res *injectivepriceoracleapi.ProbeResponse, err error) -} - -func NewAPIService(APIKey string) APIService { - return &apiSvc{ - APIKey: APIKey, - } -} - -// APIKeyAuth verifies the API key sent by the client -func (s *apiSvc) APIKeyAuth(ctx context.Context, key string, _ *security.APIKeyScheme) (context.Context, error) { - if s.APIKey != key { - return nil, injectivepriceoracleapi.MakeUnauthorized(fmt.Errorf("invalid API key")) - } - - return ctx, nil -} - -// Probe validates the dynamic feed config and attempts to pull price once -func (s *apiSvc) Probe(ctx context.Context, payload *injectivepriceoracleapi.ProbePayload) (res *injectivepriceoracleapi.ProbeResponse, err error) { - feedCfg, err := ParseDynamicFeedConfig(payload.Content) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "payload": len(payload.Content), - }).Errorln("failed to parse dynamic feed config") - return nil, injectivepriceoracleapi.MakeInternal(fmt.Errorf("failed to parse dynamic feed config: %w", err)) - } - - if err = validateFeedConfig(feedCfg); err != nil { - log.WithError(err).WithFields(log.Fields{ - "feed_config": feedCfg, - }).Errorln("invalid feed config") - return nil, injectivepriceoracleapi.MakeInternal(fmt.Errorf("invalid feed config: %w", err)) - } - - pricePuller, err := NewDynamicPriceFeed(feedCfg) - if err != nil { - log.WithError(err).Errorln("failed to init new dynamic price feed") - return nil, injectivepriceoracleapi.MakeInternal(fmt.Errorf("failed to init new dynamic price feed: %w", err)) - } - - pullerLogger := log.WithFields(log.Fields{ - "provider_name": pricePuller.ProviderName(), - "symbol": pricePuller.Symbol(), - "oracle_type": pricePuller.OracleType().String(), - }) - - answer, err := pricePuller.PullPrice(ctx) - if err != nil { - pullerLogger.WithError(err).Errorln("failed to pull price") - return nil, injectivepriceoracleapi.MakeInternal(fmt.Errorf("failed to pull price: %w", err)) - } - - if answer == nil { - return nil, injectivepriceoracleapi.MakeInternal(fmt.Errorf("pull price returned empty result")) - } - - return &injectivepriceoracleapi.ProbeResponse{ - Result: answer.Price.String(), - }, nil -} - -func validateFeedConfig(feedCfg *FeedConfig) error { - if feedCfg == nil { - return errors.New("feed config is nil") - } - - if feedCfg.ProviderName == "" { - return errors.New("provider name is empty in feed config") - } - - if feedCfg.Ticker == "" { - return errors.New("ticker is empty in feed config") - } - - if feedCfg.ObservationSource == "" { - return errors.New("observation source is empty in feed config") - } - - if feedCfg.PullInterval == "" { - return errors.New("pull interval is empty in feed config") - } - - return nil -} diff --git a/internal/service/oracle/chainlink/chainlink_fetcher.go b/internal/service/oracle/chainlink/chainlink_fetcher.go new file mode 100644 index 0000000..fd0eb6d --- /dev/null +++ b/internal/service/oracle/chainlink/chainlink_fetcher.go @@ -0,0 +1,150 @@ +package chainlink + +import ( + "context" + "sync" + + "github.com/InjectiveLabs/metrics" + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + log "github.com/InjectiveLabs/suplog" + "github.com/pkg/errors" + streams "github.com/smartcontractkit/data-streams-sdk/go" + "github.com/smartcontractkit/data-streams-sdk/go/feed" +) + +type ChainLinkFetcher interface { + Start(ctx context.Context) error + ChainlinkReport(feedID string) *oracletypes.ChainlinkReport +} + +type chainlinkFetcher struct { + client streams.Client + stream streams.Stream + latestPrices map[string]*oracletypes.ChainlinkReport + feedIDs []string + mu sync.RWMutex + + logger log.Logger + svcTags metrics.Tags +} + +// NewFetcher returns a new Fetcher instance. +func NewFetcher(client streams.Client, feedIds []string) (*chainlinkFetcher, error) { + fetcher := &chainlinkFetcher{ + latestPrices: make(map[string]*oracletypes.ChainlinkReport), + logger: log.WithFields(log.Fields{ + "svc": "oracle", + "dynamic": true, + "provider": "chainlinkFetcher", + }), + client: client, + feedIDs: feedIds, + + svcTags: metrics.Tags{ + "provider": "chainlinkFetcher", + }, + } + + return fetcher, nil +} + +func (f *chainlinkFetcher) logPrintf(format string, args ...interface{}) { + f.logger.Infof(format, args...) +} + +func (f *chainlinkFetcher) ChainlinkReport(feedID string) *oracletypes.ChainlinkReport { + f.mu.RLock() + defer f.mu.RUnlock() + + return f.latestPrices[feedID] +} + +func (f *chainlinkFetcher) Start(ctx context.Context) error { + if len(f.feedIDs) == 0 { + return errors.New("no feed IDs to subscribe to") + } + + // Parse the feed IDs + var ids []feed.ID + for _, feedIDStr := range f.feedIDs { + var fid feed.ID + if err := fid.FromString(feedIDStr); err != nil { + return errors.Wrapf(err, "invalid stream ID %s", feedIDStr) + } + + ids = append(ids, fid) + } + + f.logger.Infof("subscribing to %d Chainlink feed IDs: %v", len(ids), f.feedIDs) + + // Subscribe to the feeds + stream, err := f.client.Stream(ctx, ids) + if err != nil { + return errors.Wrap(err, "failed to subscribe to Chainlink streams") + } + + f.stream = stream + f.logger.Infoln("successfully subscribed to Chainlink Data Streams") + + return f.startReadingReports(ctx) +} + +func (f *chainlinkFetcher) startReadingReports(ctx context.Context) error { + for { + select { + case <-ctx.Done(): + f.logger.Infoln("context cancelled, stopping Chainlink fetcher") + return ctx.Err() + default: + } + + reportResponse, err := f.stream.Read(ctx) + if err != nil { + metrics.CustomReport(func(s metrics.Statter, tagSpec []string) { + s.Count("feed_provider.chainlink.read_error.count", 1, tagSpec, 1) + }, f.svcTags) + f.logger.WithError(err).Warningln("error reading from Chainlink stream") + continue + } + + feedIDStr := reportResponse.FeedID.String() + + metrics.CustomReport(func(s metrics.Statter, tagSpec []string) { + s.Count("feed_provider.chainlink.price_receive.count", 1, tagSpec, 1) + }, f.svcTags) + + // Log the decoded report + f.logger.WithFields(log.Fields{ + "feedID": feedIDStr, + }).Debugln("received Chainlink report") + + priceData := &oracletypes.ChainlinkReport{ + FeedId: reportResponse.FeedID[:], + FullReport: reportResponse.FullReport, + ValidFromTimestamp: reportResponse.ValidFromTimestamp, + ObservationsTimestamp: reportResponse.ObservationsTimestamp, + } + + // Update the latest prices + f.mu.Lock() + f.latestPrices[feedIDStr] = priceData + f.mu.Unlock() + + metrics.CustomReport(func(s metrics.Statter, tagSpec []string) { + s.Count("feed_provider.chainlink.latest_pairs_update.count", 1, tagSpec, 1) + }, f.svcTags) + } +} + +func (f *chainlinkFetcher) Close() error { + if f.stream != nil { + return f.stream.Close() + } + + f.mu.Lock() + f.latestPrices = make(map[string]*oracletypes.ChainlinkReport) + f.mu.Unlock() + f.logger.Infoln("Chainlink fetcher closed") + + return nil +} diff --git a/internal/service/oracle/chainlink/feed_chainlink.go b/internal/service/oracle/chainlink/feed_chainlink.go new file mode 100644 index 0000000..069b699 --- /dev/null +++ b/internal/service/oracle/chainlink/feed_chainlink.go @@ -0,0 +1,129 @@ +package chainlink + +import ( + "context" + "fmt" + "time" + + "github.com/InjectiveLabs/metrics" + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + log "github.com/InjectiveLabs/suplog" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" +) + +type chainlinkPriceFeed struct { + chainlinkFetcher ChainLinkFetcher + providerName string + ticker string + feedID string + interval time.Duration + logger log.Logger + svcTags metrics.Tags + oracleType oracletypes.OracleType +} + +func ParseChainlinkFeedConfig(body []byte) (*types.FeedConfig, error) { + var config types.FeedConfig + if err := toml.Unmarshal(body, &config); err != nil { + err = errors.Wrap(err, "failed to unmarshal TOML config") + return nil, err + } + return &config, nil +} + +// NewChainlinkPriceFeed returns price puller for Chainlink Data Streams +func NewChainlinkPriceFeed(chainlinkFetcher ChainLinkFetcher, cfg *types.FeedConfig) (types.PricePuller, error) { + pullInterval := 1 * time.Minute + if len(cfg.PullInterval) > 0 { + interval, err := time.ParseDuration(cfg.PullInterval) + if err != nil { + err = errors.Wrapf(err, "failed to parse pull interval: %s (expected format: 60s)", cfg.PullInterval) + return nil, err + } + + if interval < 1*time.Second { + err = errors.Wrapf(err, "failed to parse pull interval: %s (minimum interval = 1s)", cfg.PullInterval) + return nil, err + } + + pullInterval = interval + } + var oracleType oracletypes.OracleType + if cfg.OracleType == "" { + oracleType = oracletypes.OracleType_ChainlinkDataStreams + } else { + tmpType, exist := oracletypes.OracleType_value[cfg.OracleType] + if !exist { + return nil, fmt.Errorf("oracle type does not exist: %s", cfg.OracleType) + } + + oracleType = oracletypes.OracleType(tmpType) + } + feed := &chainlinkPriceFeed{ + chainlinkFetcher: chainlinkFetcher, + ticker: cfg.Ticker, + providerName: cfg.ProviderName, + feedID: cfg.FeedID, + interval: pullInterval, + oracleType: oracleType, + logger: log.WithFields(log.Fields{ + "svc": "oracle", + "dynamic": true, + "provider": cfg.ProviderName, + }), + svcTags: metrics.Tags{ + "provider": cfg.ProviderName, + }, + } + return feed, nil +} +func (f *chainlinkPriceFeed) Provider() types.FeedProvider { + return FeedProviderChainlink +} +func (f *chainlinkPriceFeed) ProviderName() string { + return f.providerName +} +func (f *chainlinkPriceFeed) Symbol() string { + return f.ticker +} +func (f *chainlinkPriceFeed) Interval() time.Duration { + return f.interval +} +func (f *chainlinkPriceFeed) OracleType() oracletypes.OracleType { + return oracletypes.OracleType_ChainlinkDataStreams +} +func (f *chainlinkPriceFeed) GetAssetPair() *oracletypes.AssetPair { + return nil +} + +func (f *chainlinkPriceFeed) PullPrice(_ context.Context) ( + priceData types.PriceData, + err error, +) { + metrics.ReportFuncCallAndTimingWithErr(f.svcTags)(&err) + + ts := time.Now() + + chainlinkRepot := f.chainlinkFetcher.ChainlinkReport(f.feedID) + if chainlinkRepot == nil { + return nil, nil + } + + chainlinkData := &ChainlinkPriceData{ + Ticker: f.ticker, + ProviderName: f.providerName, + Symbol: f.ticker, + Timestamp: ts, + OracleType: f.OracleType(), + ChainlinkReport: chainlinkRepot, + } + + return chainlinkData, nil +} + +func (f *chainlinkPriceFeed) GetFeedID() string { + return f.feedID +} diff --git a/internal/service/oracle/chainlink/models.go b/internal/service/oracle/chainlink/models.go new file mode 100644 index 0000000..334e673 --- /dev/null +++ b/internal/service/oracle/chainlink/models.go @@ -0,0 +1,52 @@ +package chainlink + +import ( + "time" + + "github.com/shopspring/decimal" + + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" +) + +const FeedProviderChainlink types.FeedProvider = "chainlink" + +// PriceData stores price data for Chainlink Oracle +type ChainlinkPriceData struct { + Ticker string + ProviderName string + Symbol string + Price decimal.Decimal + ChainlinkReport *oracletypes.ChainlinkReport + Timestamp time.Time + OracleType oracletypes.OracleType +} + +func (c *ChainlinkPriceData) GetTicker() string { return c.Ticker } +func (c *ChainlinkPriceData) GetProviderName() string { return c.ProviderName } +func (c *ChainlinkPriceData) GetSymbol() string { return c.Symbol } +func (c *ChainlinkPriceData) GetPrice() decimal.Decimal { return c.Price } +func (c *ChainlinkPriceData) GetTimestamp() time.Time { return c.Timestamp } +func (c *ChainlinkPriceData) GetOracleType() oracletypes.OracleType { return c.OracleType } + +// ReportVersion represents the version of a Chainlink Data Streams report +type ReportVersion string + +const ( + // ReportVersionV3 is used for crypto assets (BTC/USD, ETH/USD, etc.) + ReportVersionV3 ReportVersion = "v3" + + // ReportVersionV8 is used for Real World Assets (RWA) + ReportVersionV8 ReportVersion = "v8" +) + +// String returns the string representation of the report version +func (v ReportVersion) String() string { + return string(v) +} + +// IsValid checks if the report version is supported +func (v ReportVersion) IsValid() bool { + return v == ReportVersionV3 || v == ReportVersionV8 +} diff --git a/internal/service/oracle/chainlink/types.go b/internal/service/oracle/chainlink/types.go new file mode 100644 index 0000000..f2f7fba --- /dev/null +++ b/internal/service/oracle/chainlink/types.go @@ -0,0 +1,19 @@ +package chainlink + +import ( + "context" + + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" +) + +type Fetcher interface { + Start(ctx context.Context) error + ChainlinkReport(feedID string) *oracletypes.ChainlinkReport +} + +type Config struct { + WsURL string + APIKey string + APISecret string + FeedIDs []string +} diff --git a/internal/service/oracle/feed_dynamic.go b/internal/service/oracle/feed_dynamic.go deleted file mode 100644 index 3fc11e3..0000000 --- a/internal/service/oracle/feed_dynamic.go +++ /dev/null @@ -1,225 +0,0 @@ -package oracle - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "sync/atomic" - "time" - - "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" - "github.com/shopspring/decimal" - - "github.com/InjectiveLabs/metrics" - oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" - log "github.com/InjectiveLabs/suplog" - - "github.com/InjectiveLabs/injective-price-oracle/pipeline" -) - -func ParseDynamicFeedConfig(body []byte) (*FeedConfig, error) { - var config FeedConfig - if err := toml.Unmarshal(body, &config); err != nil { - err = errors.Wrap(err, "failed to unmarshal TOML config") - return nil, err - } - - // validate the observation source graph - _, err := pipeline.Parse(config.ObservationSource) - if err != nil { - err = errors.Wrap(err, "observation source pipeline parse error") - return nil, err - } - - return &config, nil -} - -func (c *FeedConfig) Hash() string { - h := sha256.New() - - _, _ = h.Write([]byte(c.ProviderName)) - _, _ = h.Write([]byte(c.Ticker)) - _, _ = h.Write([]byte(c.ObservationSource)) - - return hex.EncodeToString(h.Sum(nil)) -} - -// NewDynamicPriceFeed returns price puller that is implemented by Chainlink's job spec -// runner that accepts dotDag graphs as a definition of the observation source. -func NewDynamicPriceFeed(cfg *FeedConfig) (PricePuller, error) { - pullInterval := 1 * time.Minute - if len(cfg.PullInterval) > 0 { - interval, err := time.ParseDuration(cfg.PullInterval) - if err != nil { - err = errors.Wrapf(err, "failed to parse pull interval: %s (expected format: 60s)", cfg.PullInterval) - return nil, err - } - - if interval < 1*time.Second { - err = errors.Wrapf(err, "failed to parse pull interval: %s (minimum interval = 1s)", cfg.PullInterval) - return nil, err - } - - pullInterval = interval - } - - var oracleType oracletypes.OracleType - if cfg.OracleType == "" { - oracleType = oracletypes.OracleType_PriceFeed - } else { - tmpType, exist := oracletypes.OracleType_value[cfg.OracleType] - if !exist { - return nil, fmt.Errorf("oracle type does not exist: %s", cfg.OracleType) - } - - oracleType = oracletypes.OracleType(tmpType) - } - - feed := &dynamicPriceFeed{ - ticker: cfg.Ticker, - providerName: cfg.ProviderName, - interval: pullInterval, - dotDagSource: cfg.ObservationSource, - oracleType: oracleType, - - logger: log.WithFields(log.Fields{ - "svc": "oracle", - "dynamic": true, - "provider": cfg.ProviderName, - }), - - svcTags: metrics.Tags{ - "provider": cfg.ProviderName, - }, - } - - return feed, nil -} - -type dynamicPriceFeed struct { - ticker string - providerName string - interval time.Duration - dotDagSource string - - runNonce int32 - - logger log.Logger - svcTags metrics.Tags - - oracleType oracletypes.OracleType -} - -func (f *dynamicPriceFeed) Interval() time.Duration { - return f.interval -} - -func (f *dynamicPriceFeed) Symbol() string { - // dynamic price feeds don't expose symbol name outside observation source graph, - // so we just report its associated ticker here. - return f.ticker -} - -func (f *dynamicPriceFeed) Provider() FeedProvider { - return FeedProviderDynamic -} - -func (f *dynamicPriceFeed) ProviderName() string { - return f.providerName -} - -func (f *dynamicPriceFeed) OracleType() oracletypes.OracleType { - if f.oracleType == oracletypes.OracleType_Unspecified { - return oracletypes.OracleType_PriceFeed - } - return f.oracleType -} - -func (f *dynamicPriceFeed) PullPrice(ctx context.Context) ( - priceData *PriceData, - err error, -) { - metrics.ReportFuncCall(f.svcTags) - doneFn := metrics.ReportFuncTiming(f.svcTags) - defer doneFn() - - ts := time.Now() - - runner := pipeline.NewRunner(f.logger) - runLogger := f.logger.WithFields(log.Fields{ - "ticker": f.ticker, - }) - - jobID := atomic.AddInt32(&f.runNonce, 1) - spec := pipeline.Spec{ - ID: jobID, - DotDagSource: f.dotDagSource, - CreatedAt: time.Now().UTC(), - - JobID: jobID, - JobName: fmt.Sprintf("%s_%s", f.providerName, f.ticker), - } - - runVars := pipeline.NewVarsFrom(map[string]interface{}{}) - run, trrs, err := runner.ExecuteRun(ctx, spec, runVars, runLogger) - if err != nil { - err = errors.Wrap(err, "failed to execute pipeline run") - return nil, err - } else if run.State != pipeline.RunStatusCompleted { - if run.HasErrors() { - runLogger.Warningf("final run result has non-critical errors: %s", run.AllErrors.ToError()) - } - - if run.HasFatalErrors() { - err = errors.Errorf("final run result has fatal errors: %s", run.FatalErrors.ToError()) - return nil, err - } - - err = errors.Errorf("expected run to be completed, yet got %v", run.State) - return nil, err - } - - finalResult := trrs.FinalResult(runLogger) - - if finalResult.HasErrors() { - runLogger.Warningf("final run result has non-critical errors: %v", finalResult.AllErrors) - } - - if finalResult.HasFatalErrors() { - return nil, errors.Errorf("final run result has fatal errors: %v", finalResult.FatalErrors) - } - - res, err := finalResult.SingularResult() - if err != nil { - return nil, errors.Wrap(err, "failed to get single result of pipeline run") - } - - price, ok := res.Value.(decimal.Decimal) - if !ok { - if floatPrice, ok := res.Value.(float64); ok { - price = decimal.NewFromFloat(floatPrice) - } else if someString, ok := res.Value.(string); ok { - price, err = decimal.NewFromString(someString) - } else { - err = errors.New("value is neither decimals, float64 nor string") - } - - if err != nil { - err = fmt.Errorf("expected pipeline result as string, decimal.Decimal or float64, but got %T, err: %w", res.Value, err) - return nil, err - } - } - - runLogger.Infoln("PullPrice (pipeline run) done in", time.Since(ts)) - - return &PriceData{ - Ticker: Ticker(f.ticker), - ProviderName: f.ProviderName(), - Symbol: f.Symbol(), - Price: price, - Timestamp: time.Now(), - OracleType: f.OracleType(), - }, nil -} diff --git a/internal/service/oracle/models.go b/internal/service/oracle/models.go deleted file mode 100644 index 009b934..0000000 --- a/internal/service/oracle/models.go +++ /dev/null @@ -1,43 +0,0 @@ -package oracle - -import ( - "strings" - "time" - - "github.com/shopspring/decimal" - - oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" -) - -// PriceData stores additional meta info for a price report. -type PriceData struct { - // Ticker is BASE/QUOTE pair name - Ticker Ticker - - // ProviderName is the name of the feed - ProviderName string - - // Symbol is provider-specific - Symbol string - - // Price is the reported price by feed integarion - Price decimal.Decimal - - // Asset pair - for Stork Oracle - AssetPair *oracletypes.AssetPair - - // Timestamp of the report - Timestamp time.Time - - OracleType oracletypes.OracleType -} - -type Ticker string - -func (t Ticker) Base() string { - return strings.Split(string(t), "/")[0] -} - -func (t Ticker) Quote() string { - return strings.Split(string(t), "/")[1] -} diff --git a/internal/service/oracle/service.go b/internal/service/oracle/service.go index ab1d8f0..f71b89e 100644 --- a/internal/service/oracle/service.go +++ b/internal/service/oracle/service.go @@ -7,17 +7,17 @@ import ( "strings" "time" - "cosmossdk.io/math" - - log "github.com/InjectiveLabs/suplog" - cosmtypes "github.com/cosmos/cosmos-sdk/types" - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "github.com/InjectiveLabs/metrics" exchangetypes "github.com/InjectiveLabs/sdk-go/chain/exchange/types/v2" oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" chainclient "github.com/InjectiveLabs/sdk-go/client/chain" + log "github.com/InjectiveLabs/suplog" + cosmtypes "github.com/cosmos/cosmos-sdk/types" + "github.com/pkg/errors" + + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/chainlink" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/stork" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" ) type Service interface { @@ -25,118 +25,36 @@ type Service interface { Close() } -type PricePuller interface { - Provider() FeedProvider - ProviderName() string - Symbol() string - Interval() time.Duration - - // PullPrice method must be implemented in order to get a price - // from external source, handled by PricePuller. - PullPrice(ctx context.Context) (priceData *PriceData, err error) - OracleType() oracletypes.OracleType -} - -type FeedConfig struct { - ProviderName string `toml:"provider"` - Ticker string `toml:"ticker"` - PullInterval string `toml:"pullInterval"` - ObservationSource string `toml:"observationSource"` - OracleType string `toml:"oracleType"` -} - type oracleSvc struct { - pricePullers map[string]PricePuller + pricePullers map[string]types.PricePuller supportedPriceFeeds map[string]PriceFeedConfig cosmosClients []chainclient.ChainClient exchangeQueryClient exchangetypes.QueryClient oracleQueryClient oracletypes.QueryClient - config *StorkConfig logger log.Logger svcTags metrics.Tags } const ( - maxRespTime = 3 * time.Second + maxRespTime = 15 * time.Second maxRetriesPerInterval = 3 MaxRetriesReConnectWebSocket = 5 ) -var ( - zeroPrice = decimal.Decimal{} -) - -type FeedProvider string - -func (f FeedProvider) String() string { - return string(f) -} - -const ( - FeedProviderDynamic FeedProvider = "_" - FeedProviderBinance FeedProvider = "binance" - FeedProviderStork FeedProvider = "stork" -) - type PriceFeedConfig struct { Symbol string - FeedProvider FeedProvider + FeedProvider types.FeedProvider PullInterval time.Duration - DynamicConfig *FeedConfig -} - -// getEnabledFeeds returns a mapping between ticker and price feeder config, this will query -// the chain to fetch only those configs where current Cosmos sender is authorized as a relayer. -func (s *oracleSvc) getEnabledFeeds(cosmosClient chainclient.ChainClient) map[string]PriceFeedConfig { - metrics.ReportFuncCall(s.svcTags) - doneFn := metrics.ReportFuncTiming(s.svcTags) - defer doneFn() - - ctx, cancelFn := context.WithTimeout(context.Background(), 1*time.Minute) - defer cancelFn() - - feeds := make(map[string]PriceFeedConfig) - - sender := strings.ToLower(cosmosClient.FromAddress().String()) - res, err := s.oracleQueryClient.PriceFeedPriceStates(ctx, &oracletypes.QueryPriceFeedPriceStatesRequest{}) - if err != nil { - metrics.ReportFuncError(s.svcTags) - return nil - } - - for _, priceFeedState := range res.PriceStates { - var found bool - for _, relayer := range priceFeedState.Relayers { - if strings.ToLower(relayer) == sender { - found = true - } - } - - if !found { - continue - } - - ticker := fmt.Sprintf("%s/%s", priceFeedState.Base, priceFeedState.Quote) - if feed, ok := s.supportedPriceFeeds[ticker]; ok { - feeds[ticker] = feed - } else { - s.logger.WithFields(log.Fields{ - "sender": sender, - }).Warningf("current sender is authorized in %s feed, but no corresponding feed config loaded", ticker) - } - } - - s.logger.Infof("got %d enabled price feeds", len(feeds)) - - return feeds + DynamicConfig *types.FeedConfig } func NewService( _ context.Context, cosmosClients []chainclient.ChainClient, - feedConfigs map[string]*FeedConfig, - storkFetcher StorkFetcher, + feedConfigs map[string]*types.FeedConfig, + storkFetcher stork.Fetcher, + chainlinkFetcher chainlink.Fetcher, ) (Service, error) { svc := &oracleSvc{ cosmosClients: cosmosClients, @@ -146,34 +64,28 @@ func NewService( }, } - // supportedPriceFeeds is a mapping between price ticker and its pricefeed config - svc.supportedPriceFeeds = map[string]PriceFeedConfig{} - for _, feedCfg := range feedConfigs { - svc.supportedPriceFeeds[feedCfg.Ticker] = PriceFeedConfig{ - FeedProvider: FeedProviderDynamic, - DynamicConfig: feedCfg, - } - } - - svc.pricePullers = map[string]PricePuller{} + svc.pricePullers = map[string]types.PricePuller{} for _, feedCfg := range feedConfigs { switch feedCfg.ProviderName { - case FeedProviderStork.String(): + case types.FeedProviderStork.String(): ticker := feedCfg.Ticker - pricePuller, err := NewStorkPriceFeed(storkFetcher, feedCfg) + pricePuller, err := stork.NewStorkPriceFeed(storkFetcher, feedCfg) if err != nil { err = errors.Wrapf(err, "failed to init stork price feed for ticker %s", ticker) return nil, err } svc.pricePullers[ticker] = pricePuller - default: // TODO this should be replaced with correct providers + case types.FeedProviderChainlink.String(): ticker := feedCfg.Ticker - pricePuller, err := NewDynamicPriceFeed(feedCfg) + pricePuller, err := chainlink.NewChainlinkPriceFeed(chainlinkFetcher, feedCfg) if err != nil { - err = errors.Wrapf(err, "failed to init dynamic price feed for ticker %s", ticker) + err = errors.Wrapf(err, "failed to init chainlink price feed for ticker %s", ticker) return nil, err } svc.pricePullers[ticker] = pricePuller + default: + // Unsupported provider + svc.logger.WithField("provider", feedCfg.ProviderName).Warningln("unsupported feed provider, skipping") } } @@ -187,11 +99,11 @@ func (s *oracleSvc) Start(ctx context.Context) (err error) { if len(s.pricePullers) > 0 { s.logger.Infoln("starting pullers for", len(s.pricePullers), "feeds") - dataC := make(chan *PriceData, len(s.pricePullers)) + dataC := make(chan types.PriceData, len(s.pricePullers)) for ticker, pricePuller := range s.pricePullers { switch pricePuller.Provider() { - case FeedProviderBinance, FeedProviderStork, FeedProviderDynamic: + case types.FeedProviderStork, types.FeedProviderChainlink: go s.processSetPriceFeed(ctx, ticker, pricePuller, dataC) default: s.logger.WithField("provider", pricePuller.Provider()).Warningln("unsupported price feed provider") @@ -204,7 +116,7 @@ func (s *oracleSvc) Start(ctx context.Context) (err error) { return } -func (s *oracleSvc) processSetPriceFeed(ctx context.Context, ticker string, pricePuller PricePuller, dataC chan<- *PriceData) { +func (s *oracleSvc) processSetPriceFeed(ctx context.Context, ticker string, pricePuller types.PricePuller, dataC chan<- types.PriceData) { feedLogger := s.logger.WithFields(log.Fields{ "ticker": ticker, "provider": pricePuller.ProviderName(), @@ -221,7 +133,7 @@ func (s *oracleSvc) processSetPriceFeed(ctx context.Context, ticker string, pric feedLogger.Infoln("context cancelled, stopping price feed") return case <-t.C: - var result *PriceData + var result types.PriceData var err error for i := 0; i < maxRetriesPerInterval; i++ { @@ -265,97 +177,73 @@ const ( var pullIntervalChain = 500 * time.Millisecond -func composePriceFeedMsgs(cosmosClient chainclient.ChainClient, priceBatch []*PriceData) (results []cosmtypes.Msg) { - msg := &oracletypes.MsgRelayPriceFeedPrice{ - Sender: cosmosClient.FromAddress().String(), - } - - for _, priceData := range priceBatch { - if priceData.OracleType != oracletypes.OracleType_PriceFeed { - continue - } - - msg.Base = append(msg.Base, priceData.Ticker.Base()) - msg.Quote = append(msg.Quote, priceData.Ticker.Quote()) - msg.Price = append(msg.Price, math.LegacyMustNewDecFromStr(priceData.Price.String())) - } - - if len(msg.Base) > 0 { - return []cosmtypes.Msg{msg} - } - - return nil -} - -func composeProviderFeedMsgs(cosmosClient chainclient.ChainClient, priceBatch []*PriceData) (result []cosmtypes.Msg) { +func composeStorkOracleMsgs(cosmosClient chainclient.ChainClient, priceBatch []types.PriceData) (result []cosmtypes.Msg) { if len(priceBatch) == 0 { return nil } - providerToMsg := make(map[string]*oracletypes.MsgRelayProviderPrices) - for _, priceData := range priceBatch { - if priceData.OracleType != oracletypes.OracleType_Provider { + assetPairs := make([]*oracletypes.AssetPair, 0) + for _, pData := range priceBatch { + if pData.GetOracleType() != oracletypes.OracleType_Stork { continue } - provider := strings.ToLower(priceData.ProviderName) - msg, exist := providerToMsg[provider] - if !exist { - msg = &oracletypes.MsgRelayProviderPrices{ - Sender: cosmosClient.FromAddress().String(), - Provider: priceData.ProviderName, - } - providerToMsg[provider] = msg + if chainlinkData, ok := pData.(*stork.StorkPriceData); ok { + assetPair := chainlinkData.AssetPair + assetPairs = append(assetPairs, assetPair) } - - msg.Symbols = append(msg.Symbols, priceData.Symbol) - msg.Prices = append(msg.Prices, math.LegacyMustNewDecFromStr(priceData.Price.String())) } - for _, msg := range providerToMsg { + if len(assetPairs) > 0 { + msg := &oracletypes.MsgRelayStorkPrices{ + Sender: cosmosClient.FromAddress().String(), + AssetPairs: assetPairs, + } + + log.Debugf("assetPairs: %v", assetPairs) result = append(result, msg) } + return result } -func composeStorkOracleMsgs(cosmosClient chainclient.ChainClient, priceBatch []*PriceData) (result []cosmtypes.Msg) { +func composeChainlinkOracleMsgs(cosmosClient chainclient.ChainClient, priceBatch []types.PriceData) (result []cosmtypes.Msg) { if len(priceBatch) == 0 { return nil } - assetPairs := make([]*oracletypes.AssetPair, 0) + reports := make([]*oracletypes.ChainlinkReport, 0) for _, pData := range priceBatch { - var priceData = pData - if priceData.OracleType != oracletypes.OracleType_Stork { + if pData.GetOracleType() != oracletypes.OracleType_ChainlinkDataStreams { continue } - if priceData.AssetPair != nil { - assetPairs = append(assetPairs, priceData.AssetPair) + if chainlinkData, ok := pData.(*chainlink.ChainlinkPriceData); ok { + report := chainlinkData.ChainlinkReport + reports = append(reports, report) } } - if len(assetPairs) > 0 { - msg := &oracletypes.MsgRelayStorkPrices{ - Sender: cosmosClient.FromAddress().String(), - AssetPairs: assetPairs, + if len(reports) > 0 { + msg := &oracletypes.MsgRelayChainlinkPrices{ + Sender: cosmosClient.FromAddress().String(), + Reports: reports, } - log.Debugf("assetPairs: %v", assetPairs) + log.Debugf("chainlink reports: %d reports", len(reports)) result = append(result, msg) } return result } -func composeMsgs(cosmoClient chainclient.ChainClient, priceBatch []*PriceData) (result []cosmtypes.Msg) { - result = append(result, composePriceFeedMsgs(cosmoClient, priceBatch)...) - result = append(result, composeProviderFeedMsgs(cosmoClient, priceBatch)...) +func composeMsgs(cosmoClient chainclient.ChainClient, priceBatch []types.PriceData) (result []cosmtypes.Msg) { result = append(result, composeStorkOracleMsgs(cosmoClient, priceBatch)...) + result = append(result, composeChainlinkOracleMsgs(cosmoClient, priceBatch)...) return result } -func (s *oracleSvc) commitSetPrices(ctx context.Context, dataC <-chan *PriceData) { +func (s *oracleSvc) commitSetPrices(ctx context.Context, dataC <-chan types.PriceData) { metrics.ReportFuncCall(s.svcTags) doneFn := metrics.ReportFuncTiming(s.svcTags) defer doneFn() @@ -363,20 +251,20 @@ func (s *oracleSvc) commitSetPrices(ctx context.Context, dataC <-chan *PriceData expirationTimer := time.NewTimer(commitPriceBatchTimeLimit) defer expirationTimer.Stop() - pricesBatch := make(map[string]*PriceData) + pricesBatch := make(map[string]types.PriceData) pricesMeta := make(map[string]int) - resetBatch := func() (map[string]*PriceData, map[string]int) { + resetBatch := func() (map[string]types.PriceData, map[string]int) { expirationTimer.Reset(commitPriceBatchTimeLimit) prev := pricesBatch prevMeta := pricesMeta - pricesBatch = make(map[string]*PriceData) + pricesBatch = make(map[string]types.PriceData) pricesMeta = make(map[string]int) return prev, prevMeta } - submitBatch := func(currentBatch map[string]*PriceData, currentMeta map[string]int, timeout bool) { + submitBatch := func(currentBatch map[string]types.PriceData, currentMeta map[string]int, timeout bool) { if len(currentBatch) == 0 { return } @@ -386,7 +274,7 @@ func (s *oracleSvc) commitSetPrices(ctx context.Context, dataC <-chan *PriceData "timeout": timeout, }) - var priceBatch []*PriceData + var priceBatch []types.PriceData for _, msg := range currentBatch { priceBatch = append(priceBatch, msg) } @@ -422,25 +310,41 @@ func (s *oracleSvc) commitSetPrices(ctx context.Context, dataC <-chan *PriceData submitBatch(prevBatch, prevMeta, false) return } - if priceData.OracleType == oracletypes.OracleType_Stork { - if priceData.AssetPair == nil { - s.logger.WithFields(log.Fields{ - "ticker": priceData.Ticker, - "provider": priceData.ProviderName, - }).Debugln("got nil asset pair for stork oracle, skipping") - continue + + // Validate based on oracle type + if priceData.GetOracleType() == oracletypes.OracleType_Stork { + if storkData, ok := priceData.(*stork.StorkPriceData); ok { + if storkData.AssetPair == nil { + s.logger.WithFields(log.Fields{ + "ticker": priceData.GetTicker(), + "provider": priceData.GetProviderName(), + }).Debugln("got nil asset pair for stork oracle, skipping") + continue + } + } + } else if priceData.GetOracleType() == oracletypes.OracleType_ChainlinkDataStreams { + if chainlinkData, ok := priceData.(*chainlink.ChainlinkPriceData); ok { + if chainlinkData.ChainlinkReport.FeedId == nil || chainlinkData.ChainlinkReport == nil { + s.logger.WithFields(log.Fields{ + "ticker": priceData.GetTicker(), + "provider": priceData.GetProviderName(), + }).Debugln("got invalid chainlink report data, skipping") + continue + } } } else { - if priceData.Price.IsZero() || priceData.Price.IsNegative() { + // For other oracle types, validate price + if priceData.GetPrice().IsZero() || priceData.GetPrice().IsNegative() { s.logger.WithFields(log.Fields{ - "ticker": priceData.Ticker, - "provider": priceData.ProviderName, + "ticker": priceData.GetTicker(), + "provider": priceData.GetProviderName(), }).Debugln("got negative or zero price, skipping") continue } } - pricesMeta[priceData.OracleType.String()]++ - pricesBatch[priceData.OracleType.String()+":"+priceData.Symbol] = priceData + + pricesMeta[priceData.GetOracleType().String()]++ + pricesBatch[priceData.GetOracleType().String()+":"+priceData.GetSymbol()] = priceData if len(pricesBatch) >= commitPriceBatchSizeLimit { prevBatch, prevMeta := resetBatch() diff --git a/internal/service/oracle/feed_stork.go b/internal/service/oracle/stork/feed_stork.go similarity index 89% rename from internal/service/oracle/feed_stork.go rename to internal/service/oracle/stork/feed_stork.go index 4629fad..57ec20e 100644 --- a/internal/service/oracle/feed_stork.go +++ b/internal/service/oracle/stork/feed_stork.go @@ -1,4 +1,4 @@ -package oracle +package stork import ( "context" @@ -6,17 +6,16 @@ import ( "strings" "time" + "github.com/InjectiveLabs/metrics" + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + log "github.com/InjectiveLabs/suplog" "github.com/ethereum/go-ethereum/common" "github.com/pelletier/go-toml/v2" "github.com/pkg/errors" - "github.com/InjectiveLabs/metrics" - oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" - log "github.com/InjectiveLabs/suplog" + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" ) -var _ PricePuller = &storkPriceFeed{} - type storkPriceFeed struct { storkFetcher StorkFetcher providerName string @@ -30,8 +29,8 @@ type storkPriceFeed struct { oracleType oracletypes.OracleType } -func ParseStorkFeedConfig(body []byte) (*FeedConfig, error) { - var config FeedConfig +func ParseStorkFeedConfig(body []byte) (*types.FeedConfig, error) { + var config types.FeedConfig if err := toml.Unmarshal(body, &config); err != nil { err = errors.Wrap(err, "failed to unmarshal TOML config") return nil, err @@ -41,7 +40,7 @@ func ParseStorkFeedConfig(body []byte) (*FeedConfig, error) { } // NewStorkPriceFeed returns price puller -func NewStorkPriceFeed(storkFetcher StorkFetcher, cfg *FeedConfig) (PricePuller, error) { +func NewStorkPriceFeed(storkFetcher StorkFetcher, cfg *types.FeedConfig) (types.PricePuller, error) { pullInterval := 1 * time.Minute if len(cfg.PullInterval) > 0 { interval, err := time.ParseDuration(cfg.PullInterval) @@ -99,7 +98,7 @@ func (f *storkPriceFeed) Symbol() string { return f.ticker } -func (f *storkPriceFeed) Provider() FeedProvider { +func (f *storkPriceFeed) Provider() types.FeedProvider { return FeedProviderStork } @@ -111,12 +110,12 @@ func (f *storkPriceFeed) OracleType() oracletypes.OracleType { return oracletypes.OracleType_Stork } -func (f *storkPriceFeed) AssetPair() *oracletypes.AssetPair { +func (f *storkPriceFeed) GetAssetPair() *oracletypes.AssetPair { return f.storkFetcher.AssetPair(f.ticker) } func (f *storkPriceFeed) PullPrice(_ context.Context) ( - priceData *PriceData, + priceData types.PriceData, err error, ) { pair := f.storkFetcher.AssetPair(f.ticker) @@ -124,8 +123,8 @@ func (f *storkPriceFeed) PullPrice(_ context.Context) ( return nil, nil } - return &PriceData{ - Ticker: Ticker(f.ticker), + return &StorkPriceData{ + Ticker: types.Ticker(f.ticker).String(), ProviderName: f.ProviderName(), Symbol: f.Symbol(), AssetPair: pair, diff --git a/internal/service/oracle/feed_stork_test.go b/internal/service/oracle/stork/feed_stork_test.go similarity index 98% rename from internal/service/oracle/feed_stork_test.go rename to internal/service/oracle/stork/feed_stork_test.go index 73bf322..533bab0 100644 --- a/internal/service/oracle/feed_stork_test.go +++ b/internal/service/oracle/stork/feed_stork_test.go @@ -1,4 +1,4 @@ -package oracle +package stork import ( "testing" diff --git a/internal/service/oracle/stork/models.go b/internal/service/oracle/stork/models.go new file mode 100644 index 0000000..4ad0b51 --- /dev/null +++ b/internal/service/oracle/stork/models.go @@ -0,0 +1,32 @@ +package stork + +import ( + "time" + + "github.com/shopspring/decimal" + + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + + "github.com/InjectiveLabs/injective-price-oracle/internal/service/oracle/types" +) + +const FeedProviderStork types.FeedProvider = "stork" + +// PriceData stores price data for Stork Oracle +type StorkPriceData struct { + Ticker string + ProviderName string + Symbol string + Price decimal.Decimal + AssetPair *oracletypes.AssetPair + Timestamp time.Time + OracleType oracletypes.OracleType +} + +// Interface implementation methods +func (s *StorkPriceData) GetTicker() string { return s.Ticker } +func (s *StorkPriceData) GetProviderName() string { return s.ProviderName } +func (s *StorkPriceData) GetSymbol() string { return s.Symbol } +func (s *StorkPriceData) GetPrice() decimal.Decimal { return s.Price } +func (s *StorkPriceData) GetTimestamp() time.Time { return s.Timestamp } +func (s *StorkPriceData) GetOracleType() oracletypes.OracleType { return s.OracleType } diff --git a/internal/service/oracle/stork_fetcher.go b/internal/service/oracle/stork/stork_fetcher.go similarity index 96% rename from internal/service/oracle/stork_fetcher.go rename to internal/service/oracle/stork/stork_fetcher.go index b9b0898..ed1081e 100644 --- a/internal/service/oracle/stork_fetcher.go +++ b/internal/service/oracle/stork/stork_fetcher.go @@ -1,4 +1,4 @@ -package oracle +package stork import ( "context" @@ -35,12 +35,6 @@ func (m messageType) String() string { return string(m) } -type StorkConfig struct { - WebsocketUrl string - WebsocketHeader string - Message string -} - type storkFetcher struct { conn *websocket.Conn latestPairs map[string]*oracletypes.AssetPair @@ -52,8 +46,8 @@ type storkFetcher struct { svcTags metrics.Tags } -// NewStorkFetcher returns a new StorkFetcher instance. -func NewStorkFetcher(storkMessage string, storkTickers []string) *storkFetcher { +// NewFetcher returns a new StorkFetcher instance. +func NewFetcher(storkMessage string, storkTickers []string) *storkFetcher { feed := &storkFetcher{ message: storkMessage, tickers: storkTickers, diff --git a/internal/service/oracle/stork/types.go b/internal/service/oracle/stork/types.go new file mode 100644 index 0000000..03f14a9 --- /dev/null +++ b/internal/service/oracle/stork/types.go @@ -0,0 +1,13 @@ +package stork + +import ( + "context" + + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + "github.com/gorilla/websocket" +) + +type Fetcher interface { + Start(ctx context.Context, conn *websocket.Conn) error + AssetPair(ticker string) *oracletypes.AssetPair +} diff --git a/internal/service/oracle/types/types.go b/internal/service/oracle/types/types.go new file mode 100644 index 0000000..005800c --- /dev/null +++ b/internal/service/oracle/types/types.go @@ -0,0 +1,78 @@ +package types + +import ( + "context" + "strings" + "time" + + oracletypes "github.com/InjectiveLabs/sdk-go/chain/oracle/types" + "github.com/shopspring/decimal" +) + +// binance, kraken. coin +type Fetcher interface { + Start(ctx context.Context) error +} + +// PriceData is the common interface for all price data types +type PriceData interface { + GetTicker() string + GetProviderName() string + GetSymbol() string + GetPrice() decimal.Decimal + GetTimestamp() time.Time + GetOracleType() oracletypes.OracleType +} + +// PricePuller is the interface for pulling prices from external sources +type PricePuller interface { + Provider() FeedProvider + ProviderName() string + Symbol() string + Interval() time.Duration + PullPrice(ctx context.Context) (priceData PriceData, err error) + OracleType() oracletypes.OracleType +} + +// FeedProvider represents the type of price feed provider +type FeedProvider string + +func (f FeedProvider) String() string { + return string(f) +} + +const ( + FeedProviderStork FeedProvider = "stork" + FeedProviderChainlink FeedProvider = "chainlink" +) + +// Ticker represents a trading pair (e.g., "BTC/USDT") +type Ticker string + +func (t Ticker) Base() string { + return strings.Split(string(t), "/")[0] +} + +func (t Ticker) Quote() string { + return strings.Split(string(t), "/")[1] +} + +func (t Ticker) String() string { + return string(t) +} + +// FeedConfig represents a generic feed configuration +type FeedConfig struct { + ProviderName string `toml:"provider"` + FeedID string `toml:"feedId"` + Ticker string `toml:"ticker"` + PullInterval string `toml:"pullInterval"` + ObservationSource string `toml:"observationSource"` + OracleType string `toml:"oracleType"` +} + +type WsConfig struct { + WebsocketUrl string + WebsocketHeader string + Message string +} diff --git a/pipeline/ws.go b/internal/service/oracle/utils/ws.go similarity index 98% rename from pipeline/ws.go rename to internal/service/oracle/utils/ws.go index e62aae8..d111e62 100644 --- a/pipeline/ws.go +++ b/internal/service/oracle/utils/ws.go @@ -1,4 +1,4 @@ -package pipeline +package utils import ( "context" diff --git a/internal/service/swagger/swagger.go b/internal/service/swagger/swagger.go deleted file mode 100644 index 0a66ba6..0000000 --- a/internal/service/swagger/swagger.go +++ /dev/null @@ -1,20 +0,0 @@ -package swagger - -import ( - swaggerAPI "github.com/InjectiveLabs/injective-price-oracle/api/gen/swagger" - - log "github.com/InjectiveLabs/suplog" -) - -type SwaggerService = swaggerAPI.Service - -// swaggerService example implementation. -// The example methods log the requests and return zero values. -type swaggerService struct { - logger log.Logger -} - -// NewSwaggerService returns the swagger service implementation. -func NewSwaggerService() SwaggerService { - return &swaggerService{log.WithField("module", "swagger")} -} diff --git a/pipeline/LICENSE.txt b/pipeline/LICENSE.txt deleted file mode 100644 index e99dc9f..0000000 --- a/pipeline/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018-2022 SmartContract ChainLink, Ltd. -Copyright (c) 2022 Injective Labs - modifications to make the pipeline standalone - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/pipeline/common.go b/pipeline/common.go deleted file mode 100644 index ab9deab..0000000 --- a/pipeline/common.go +++ /dev/null @@ -1,421 +0,0 @@ -package pipeline - -import ( - "context" - "database/sql/driver" - "encoding/hex" - "encoding/json" - "reflect" - "sort" - "strconv" - "strings" - "time" - - log "github.com/InjectiveLabs/suplog" - "github.com/mitchellh/mapstructure" - "github.com/pkg/errors" - uuid "github.com/satori/go.uuid" - null "gopkg.in/guregu/null.v4" - - cnull "github.com/InjectiveLabs/injective-price-oracle/pipeline/null" -) - -type ( - Task interface { - Type() TaskType - ID() int - DotID() string - Run(ctx context.Context, lggr log.Logger, vars Vars, inputs []Result) (Result, RunInfo) - Base() *BaseTask - Outputs() []Task - Inputs() []TaskDependency - OutputIndex() int32 - TaskTimeout() (time.Duration, bool) - TaskRetries() uint32 - TaskMinBackoff() time.Duration - TaskMaxBackoff() time.Duration - } -) - -// Wraps the input Task for the given dependent task along with a bool variable PropagateResult, -// which Indicates whether result of InputTask should be propagated to its dependent task. -// If the edge between these tasks was an implicit edge, then results are not propagated. This is because -// some tasks cannot handle an input from an edge which wasn't specified in the spec. -type TaskDependency struct { - PropagateResult bool - InputTask Task -} - -var ( - ErrWrongInputCardinality = errors.New("wrong number of task inputs") - ErrBadInput = errors.New("bad input for task") - ErrInputTaskErrored = errors.New("input task errored") - ErrParameterEmpty = errors.New("parameter is empty") - ErrTooManyErrors = errors.New("too many errors") - ErrTimeout = errors.New("timeout") - ErrTaskRunFailed = errors.New("task run failed") - ErrCancelled = errors.New("task run cancelled (fail early)") -) - -const ( - InputTaskKey = "input" -) - -// RunInfo contains additional information about the finished TaskRun -type RunInfo struct { - IsRetryable bool - IsPending bool -} - -// retryableMeta should be returned if the error is non-deterministic; i.e. a -// repeated attempt sometime later _might_ succeed where the current attempt -// failed -func retryableRunInfo() RunInfo { - return RunInfo{IsRetryable: true} -} - -func pendingRunInfo() RunInfo { - return RunInfo{IsPending: true} -} - -func isRetryableHTTPError(statusCode int, err error) bool { - if statusCode >= 400 && statusCode < 500 { - // Client errors are not likely to succeed by resubmitting the exact same information again - return false - } else if statusCode >= 500 { - // Remote errors _might_ work on a retry - return true - } - return err != nil -} - -// Result is the result of a TaskRun -type Result struct { - Value interface{} - Error error -} - -// OutputDB dumps a single result output for a pipeline_run or pipeline_task_run -func (result Result) OutputDB() JSONSerializable { - return JSONSerializable{ - Val: result.Value, - Valid: !(result.Value == nil || (reflect.ValueOf(result.Value).Kind() == reflect.Ptr && reflect.ValueOf(result.Value).IsNil())), - } -} - -// ErrorDB dumps a single result error for a pipeline_task_run -func (result Result) ErrorDB() null.String { - var errString null.String - if result.Error != nil { - errString = null.StringFrom(result.Error.Error()) - } - return errString -} - -// FinalResult is the result of a Run -type FinalResult struct { - Values []interface{} - AllErrors []error - FatalErrors []error -} - -// HasFatalErrors returns true if the final result has any errors -func (result FinalResult) HasFatalErrors() bool { - for _, err := range result.FatalErrors { - if err != nil { - return true - } - } - return false -} - -// HasErrors returns true if the final result has any errors -func (result FinalResult) HasErrors() bool { - for _, err := range result.AllErrors { - if err != nil { - return true - } - } - return false -} - -// SingularResult returns a single result if the FinalResult only has one set of outputs/errors -func (result FinalResult) SingularResult() (Result, error) { - if len(result.FatalErrors) != 1 || len(result.Values) != 1 { - return Result{}, errors.Errorf("cannot cast FinalResult to singular result; it does not have exactly 1 error and exactly 1 output: %#v", result) - } - return Result{Error: result.FatalErrors[0], Value: result.Values[0]}, nil -} - -// TaskRunResult describes the result of a task run, suitable for database -// update or insert. -// ID might be zero if the TaskRun has not been inserted yet -// TaskSpecID will always be non-zero -type TaskRunResult struct { - ID uuid.UUID - Task Task - TaskRun TaskRun - Result Result - Attempts uint - CreatedAt time.Time - FinishedAt null.Time - // runInfo is never persisted - runInfo RunInfo -} - -func (result *TaskRunResult) IsPending() bool { - return !result.FinishedAt.Valid && result.Result == Result{} -} - -func (result *TaskRunResult) IsTerminal() bool { - return len(result.Task.Outputs()) == 0 -} - -// TaskRunResults represents a collection of results for all task runs for one pipeline run -type TaskRunResults []TaskRunResult - -// FinalResult pulls the FinalResult for the pipeline_run from the task runs -// It needs to respect the output index of each task -func (trrs TaskRunResults) FinalResult(l log.Logger) FinalResult { - var found bool - var fr FinalResult - sort.Slice(trrs, func(i, j int) bool { - return trrs[i].Task.OutputIndex() < trrs[j].Task.OutputIndex() - }) - for _, trr := range trrs { - fr.AllErrors = append(fr.AllErrors, trr.Result.Error) - if trr.IsTerminal() { - fr.Values = append(fr.Values, trr.Result.Value) - fr.FatalErrors = append(fr.FatalErrors, trr.Result.Error) - found = true - } - } - - if !found { - l.Panicln("Expected at least one task to be final", "tasks", trrs) - } - return fr -} - -type JSONSerializable struct { - Val interface{} - Valid bool -} - -// UnmarshalJSON implements custom unmarshaling logic -func (js *JSONSerializable) UnmarshalJSON(bs []byte) error { - if js == nil { - *js = JSONSerializable{} - } - str := string(bs) - if str == "" || str == "null" { - js.Valid = false - return nil - } - - err := json.Unmarshal(bs, &js.Val) - js.Valid = err == nil - return err -} - -// MarshalJSON implements custom marshaling logic -func (js JSONSerializable) MarshalJSON() ([]byte, error) { - if !js.Valid { - return []byte("null"), nil - } - switch x := js.Val.(type) { - case []byte: - // Don't need to HEX encode if it is a valid JSON string - if json.Valid(x) { - return json.Marshal(string(x)) - } - - // Don't need to HEX encode if it is already HEX encoded value - if isHexBytes(x) { - return json.Marshal(string(x)) - } - - return json.Marshal(hex.EncodeToString(x)) - default: - return json.Marshal(js.Val) - } -} - -// isHexBytes returns true if the given bytes array is basically HEX encoded value. -func isHexBytes(arr []byte) bool { - _, err := hex.DecodeString(strings.TrimPrefix(string(arr), "0x")) - return err == nil -} - -func (js *JSONSerializable) Scan(value interface{}) error { - if value == nil { - *js = JSONSerializable{} - return nil - } - bytes, ok := value.([]byte) - if !ok { - return errors.Errorf("JSONSerializable#Scan received a value of type %T", value) - } - if js == nil { - *js = JSONSerializable{} - } - return js.UnmarshalJSON(bytes) -} - -func (js JSONSerializable) Value() (driver.Value, error) { - if !js.Valid { - return nil, nil - } - return js.MarshalJSON() -} - -func (js *JSONSerializable) Empty() bool { - return js == nil || !js.Valid -} - -type TaskType string - -func (t TaskType) String() string { - return string(t) -} - -const ( - TaskTypeHTTP TaskType = "http" - TaskTypeMean TaskType = "mean" - TaskTypeMedian TaskType = "median" - TaskTypeMode TaskType = "mode" - TaskTypeSum TaskType = "sum" - TaskTypeMultiply TaskType = "multiply" - TaskTypeDivide TaskType = "divide" - TaskTypeJSONParse TaskType = "jsonparse" - TaskTypeAny TaskType = "any" - TaskTypeETHABIEncode TaskType = "ethabiencode" - TaskTypeETHABIEncode2 TaskType = "ethabiencode2" - TaskTypeETHABIDecode TaskType = "ethabidecode" - TaskTypeETHABIDecodeLog TaskType = "ethabidecodelog" - TaskTypeMerge TaskType = "merge" - TaskTypeLowercase TaskType = "lowercase" - TaskTypeUppercase TaskType = "uppercase" - - // Testing only. - TaskTypePanic TaskType = "panic" - TaskTypeMemo TaskType = "memo" - TaskTypeFail TaskType = "fail" -) - -var ( - stringType = reflect.TypeOf("") - bytesType = reflect.TypeOf([]byte(nil)) - bytes20Type = reflect.TypeOf([20]byte{}) - int32Type = reflect.TypeOf(int32(0)) - nullUint32Type = reflect.TypeOf(cnull.Uint32{}) -) - -func UnmarshalTaskFromMap(taskType TaskType, taskMap interface{}, ID int, dotID string) (_ Task, err error) { - defer func(err *error) { - if *err != nil { - *err = errors.Wrap(*err, "UnmarshalTaskFromMap") - } - }(&err) - - switch taskMap.(type) { - default: - return nil, errors.Errorf("UnmarshalTaskFromMap only accepts a map[string]interface{} or a map[string]string. Got %v (%#v) of type %T", taskMap, taskMap, taskMap) - case map[string]interface{}, map[string]string: - } - - taskType = TaskType(strings.ToLower(string(taskType))) - - var task Task - switch taskType { - case TaskTypePanic: - task = &PanicTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeHTTP: - task = &HTTPTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMean: - task = &MeanTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMedian: - task = &MedianTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMode: - task = &ModeTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeSum: - task = &SumTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeAny: - task = &AnyTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeJSONParse: - task = &JSONParseTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMemo: - task = &MemoTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMultiply: - task = &MultiplyTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeDivide: - task = &DivideTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeETHABIEncode: - task = ÐABIEncodeTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeETHABIEncode2: - task = ÐABIEncodeTask2{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeETHABIDecode: - task = ÐABIDecodeTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeETHABIDecodeLog: - task = ÐABIDecodeLogTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeFail: - task = &FailTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeMerge: - task = &MergeTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeLowercase: - task = &LowercaseTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - case TaskTypeUppercase: - task = &UppercaseTask{BaseTask: BaseTask{id: ID, dotID: dotID}} - default: - return nil, errors.Errorf(`unknown task type: "%v"`, taskType) - } - - decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - Result: task, - WeaklyTypedInput: true, - DecodeHook: mapstructure.ComposeDecodeHookFunc( - mapstructure.StringToTimeDurationHookFunc(), - func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { - if from != stringType { - return data, nil - } - switch to { - case nullUint32Type: - i, err2 := strconv.ParseUint(data.(string), 10, 32) - return cnull.Uint32From(uint32(i)), err2 - } - return data, nil - }, - ), - }) - if err != nil { - return nil, err - } - - err = decoder.Decode(taskMap) - if err != nil { - return nil, err - } - return task, nil -} - -func CheckInputs(inputs []Result, minLen, maxLen, maxErrors int) ([]interface{}, error) { - if minLen >= 0 && len(inputs) < minLen { - return nil, errors.Wrapf(ErrWrongInputCardinality, "min: %v max: %v (got %v)", minLen, maxLen, len(inputs)) - } else if maxLen >= 0 && len(inputs) > maxLen { - return nil, errors.Wrapf(ErrWrongInputCardinality, "min: %v max: %v (got %v)", minLen, maxLen, len(inputs)) - } - var vals []interface{} - var errs int - for _, input := range inputs { - if input.Error != nil { - errs++ - continue - } - vals = append(vals, input.Value) - } - if maxErrors >= 0 && errs > maxErrors { - return nil, ErrTooManyErrors - } - return vals, nil -} diff --git a/pipeline/common_eth.go b/pipeline/common_eth.go deleted file mode 100644 index 2006cd7..0000000 --- a/pipeline/common_eth.go +++ /dev/null @@ -1,334 +0,0 @@ -package pipeline - -import ( - "bytes" - "fmt" - "math/big" - "reflect" - "regexp" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" -) - -var ( - ethABIRegex = regexp.MustCompile(`\A\s*([a-zA-Z0-9_]+)?\s*\(\s*([a-zA-Z0-9\[\]_\s,]+\s*)?\)`) - indexedKeyword = []byte("indexed") - calldataKeyword = []byte("calldata") - memoryKeyword = []byte("memory") - storageKeyword = []byte("storage") - spaceDelim = []byte(" ") - commaDelim = []byte(",") -) - -func ParseETHABIArgsString(theABI []byte, isLog bool) (args abi.Arguments, indexedArgs abi.Arguments, _ error) { - var argStrs [][]byte - if len(bytes.TrimSpace(theABI)) > 0 { - argStrs = bytes.Split(theABI, commaDelim) - } - - for _, argStr := range argStrs { - argStr = bytes.ReplaceAll(argStr, calldataKeyword, nil) // Strip `calldata` modifiers - argStr = bytes.ReplaceAll(argStr, memoryKeyword, nil) // Strip `memory` modifiers - argStr = bytes.ReplaceAll(argStr, storageKeyword, nil) // Strip `storage` modifiers - argStr = bytes.TrimSpace(argStr) - parts := bytes.Split(argStr, spaceDelim) - - var ( - argParts [][]byte - typeStr []byte - argName []byte - indexed bool - ) - for i := range parts { - parts[i] = bytes.TrimSpace(parts[i]) - if len(parts[i]) > 0 { - argParts = append(argParts, parts[i]) - } - } - switch len(argParts) { - case 0: - return nil, nil, errors.Errorf("bad ABI specification, empty argument: %s", theABI) - - case 1: - return nil, nil, errors.Errorf("bad ABI specification, missing argument name: %s", theABI) - - case 2: - if isLog && bytes.Equal(argParts[1], indexedKeyword) { - return nil, nil, errors.Errorf("bad ABI specification, missing argument name: %s", theABI) - } - typeStr = argParts[0] - argName = argParts[1] - - case 3: - if !isLog { - return nil, nil, errors.Errorf("bad ABI specification, too many components in argument: %s", theABI) - } else if bytes.Equal(argParts[0], indexedKeyword) || bytes.Equal(argParts[2], indexedKeyword) { - return nil, nil, errors.Errorf("bad ABI specification, 'indexed' keyword must appear between argument type and name: %s", theABI) - } else if !bytes.Equal(argParts[1], indexedKeyword) { - return nil, nil, errors.Errorf("bad ABI specification, unknown keyword '%v' between argument type and name: %s", string(argParts[1]), theABI) - } - typeStr = argParts[0] - argName = argParts[2] - indexed = true - - default: - return nil, nil, errors.Errorf("bad ABI specification, too many components in argument: %s", theABI) - } - typ, err := abi.NewType(string(typeStr), "", nil) - if err != nil { - return nil, nil, errors.Errorf("bad ABI specification: %v", err.Error()) - } - args = append(args, abi.Argument{Type: typ, Name: string(argName), Indexed: indexed}) - if indexed { - indexedArgs = append(indexedArgs, abi.Argument{Type: typ, Name: string(argName), Indexed: indexed}) - } - } - return args, indexedArgs, nil -} - -func parseETHABIString(theABI []byte, isLog bool) (name string, args abi.Arguments, indexedArgs abi.Arguments, err error) { - matches := ethABIRegex.FindAllSubmatch(theABI, -1) - if len(matches) != 1 || len(matches[0]) != 3 { - return "", nil, nil, errors.Errorf("bad ABI specification: %s", theABI) - } - name = string(bytes.TrimSpace(matches[0][1])) - args, indexedArgs, err = ParseETHABIArgsString(matches[0][2], isLog) - return name, args, indexedArgs, err -} - -func convertToETHABIType(val interface{}, abiType abi.Type) (interface{}, error) { - srcVal := reflect.ValueOf(val) - - if abiType.GetType() == srcVal.Type() { - return val, nil - } - - switch abiType.T { - case abi.IntTy, abi.UintTy: - return convertToETHABIInteger(val, abiType) - - case abi.StringTy: - switch val := val.(type) { - case string: - return val, nil - case []byte: - return string(val), nil - } - - case abi.BytesTy: - switch val := val.(type) { - case string: - if strings.HasPrefix(val, "0x") { - return hexutil.Decode(val) - } - return []byte(val), nil - case []byte: - return val, nil - default: - return convertToETHABIBytes(abiType.GetType(), srcVal, srcVal.Len()) - } - - case abi.FixedBytesTy: - destType := abiType.GetType() - return convertToETHABIBytes(destType, srcVal, destType.Len()) - - case abi.AddressTy: - switch val := val.(type) { - case common.Address: - return val, nil - case [20]byte: - return common.Address(val), nil - default: - maybeBytes, err := convertToETHABIBytes(bytes20Type, srcVal, 20) - if err != nil { - return nil, err - } - bs, ok := maybeBytes.([20]byte) - if !ok { - panic("impossible") - } - return common.Address(bs), nil - } - - case abi.BoolTy: - switch val := val.(type) { - case bool: - return val, nil - case string: - return strconv.ParseBool(val) - } - - case abi.SliceTy: - dest := reflect.MakeSlice(abiType.GetType(), srcVal.Len(), srcVal.Len()) - for i := 0; i < dest.Len(); i++ { - elem, err := convertToETHABIType(srcVal.Index(i).Interface(), *abiType.Elem) - if err != nil { - return nil, err - } - dest.Index(i).Set(reflect.ValueOf(elem)) - } - return dest.Interface(), nil - - case abi.ArrayTy: - if srcVal.Kind() != reflect.Slice && srcVal.Kind() != reflect.Array { - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to %v", srcVal.Type(), abiType) - } else if srcVal.Len() != abiType.Size { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", abiType.Size, srcVal.Len()) - } - - dest := reflect.New(abiType.GetType()).Elem() - for i := 0; i < dest.Len(); i++ { - elem, err := convertToETHABIType(srcVal.Index(i).Interface(), *abiType.Elem) - if err != nil { - return nil, err - } - dest.Index(i).Set(reflect.ValueOf(elem)) - } - return dest.Interface(), nil - - case abi.TupleTy: - return convertToETHABITuple(abiType, srcVal) - - } - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to %v", srcVal.Type(), abiType) -} - -func convertToETHABITuple(abiType abi.Type, srcVal reflect.Value) (interface{}, error) { - size := len(abiType.TupleElems) - if srcVal.Len() != size { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", size, srcVal.Len()) - } - - dest := reflect.New(abiType.TupleType).Elem() - switch srcVal.Type().Kind() { - case reflect.Map: - for i, fieldName := range abiType.TupleRawNames { - src := srcVal.MapIndex(reflect.ValueOf(fieldName)) - elem, err := convertToETHABIType(src.Interface(), *abiType.TupleElems[i]) - if err != nil { - return nil, err - } - dest.FieldByIndex([]int{i}).Set(reflect.ValueOf(elem)) - } - - return dest.Interface(), nil - - case reflect.Slice, reflect.Array: - for i := range abiType.TupleRawNames { - src := srcVal.Index(i) - elem, err := convertToETHABIType(src.Interface(), *abiType.TupleElems[i]) - if err != nil { - return nil, err - } - dest.FieldByIndex([]int{i}).Set(reflect.ValueOf(elem)) - } - - return dest.Interface(), nil - - default: - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to tuple[%d]", srcVal.Type(), size) - } -} - -func convertToETHABIBytes(destType reflect.Type, srcVal reflect.Value, length int) (interface{}, error) { - switch srcVal.Type().Kind() { - case reflect.Slice: - if destType.Len() != length { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", length, destType.Len()) - } else if srcVal.Type().Elem().Kind() != reflect.Uint8 { - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to %v", srcVal.Type(), destType) - } - if destType.Kind() == reflect.Array { - destVal := reflect.New(destType).Elem() - reflect.Copy(destVal.Slice(0, length), srcVal.Slice(0, srcVal.Len())) - return destVal.Interface(), nil - } - destVal := reflect.MakeSlice(destType, length, length) - reflect.Copy(destVal.Slice(0, length), srcVal.Slice(0, srcVal.Len())) - return destVal.Interface(), nil - - case reflect.Array: - if destType.Kind() == reflect.Array && destType.Len() != length { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", length, destType.Len()) - } else if srcVal.Type().Elem().Kind() != reflect.Uint8 { - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to %v", srcVal.Type(), destType) - } - var destVal reflect.Value - if destType.Kind() == reflect.Array { - destVal = reflect.New(destType).Elem() - } else { - destVal = reflect.MakeSlice(destType, length, length) - } - reflect.Copy(destVal, srcVal) - return destVal.Interface(), nil - - case reflect.String: - s := srcVal.Convert(stringType).Interface().(string) - if strings.HasPrefix(s, "0x") { - if len(s) != (length*2)+2 { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", length, (len(s)-2)/2) - } - maybeBytes, err := hexutil.Decode(s) - if err != nil { - return nil, err - } - return convertToETHABIBytes(destType, reflect.ValueOf(maybeBytes), length) - } - - if destType.Len() != len(s) { - return nil, errors.Wrapf(ErrBadInput, "incorrect length: expected %v, got %v", length, len(s)) - } - return convertToETHABIBytes(destType, srcVal.Convert(bytesType), length) - - default: - return nil, errors.Wrapf(ErrBadInput, "cannot convert %v to %v", srcVal.Type(), destType) - } -} - -var ErrOverflow = errors.New("overflow") - -func convertToETHABIInteger(val interface{}, abiType abi.Type) (interface{}, error) { - d, err := ToDecimal(val) - if err != nil { - return nil, err - } - - i := d.BigInt() - - if abiType.Size > 64 { - return i, nil - } - - converted := reflect.New(abiType.GetType()).Elem() - // switch on signed/unsignedness of the abi type. - ty := abiType.GetType() - switch ty.Kind() { - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - if converted.OverflowUint(i.Uint64()) { - return nil, ErrOverflow - } - converted.SetUint(i.Uint64()) - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - if converted.OverflowInt(i.Int64()) { - return nil, ErrOverflow - } - converted.SetInt(i.Int64()) - default: - // go-ethereum handles in-betweener sizes, i.e 24, 40, 48, and 56 bit integers, - // as if they were big.Int, instead of the next largest native integer type that - // could hold it. Unsure of why this decision was taken. - // See https://github.com/ethereum/go-ethereum/blob/master/accounts/abi/reflect.go#L61 for - // the relevant code. - if ty == reflect.TypeOf(&big.Int{}) { - return i, nil - } - return nil, fmt.Errorf("unknown Go type %+v for abi type %+v", ty.String(), abiType) - } - - return converted.Interface(), nil -} diff --git a/pipeline/common_http.go b/pipeline/common_http.go deleted file mode 100644 index c695507..0000000 --- a/pipeline/common_http.go +++ /dev/null @@ -1,106 +0,0 @@ -package pipeline - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "strings" - "time" - - "github.com/pkg/errors" - - log "github.com/InjectiveLabs/suplog" -) - -func makeHTTPRequest( - ctx context.Context, - lggr log.Logger, - method StringParam, - url URLParam, - requestData MapParam, - headerMap MapParam, -) ([]byte, int, http.Header, time.Duration, error) { - - var bodyReader io.Reader - if requestData != nil { - bodyBytes, err := json.Marshal(requestData) - if err != nil { - return nil, 0, nil, 0, errors.Wrap(err, "failed to encode request body as JSON") - } - bodyReader = bytes.NewReader(bodyBytes) - } - - request, err := http.NewRequestWithContext(ctx, string(method), url.String(), bodyReader) - if err != nil { - return nil, 0, nil, 0, errors.Wrap(err, "failed to create http.Request") - } - request.Header.Set("Content-Type", "application/json") - - for key, value := range headerMap { - if strings.ToLower(key) == lowerContentTypeKey { - // skip Content-Type override attempts - continue - } - - request.Header.Set(key, value.(string)) - } - - httpRequest := HTTPRequest{ - Request: request, - Logger: lggr.WithFields(log.Fields{ - "svc": "pipeline", - "action": "HTTPRequest", - }), - } - - start := time.Now() - responseBytes, statusCode, headers, err := httpRequest.SendRequest() - if ctx.Err() != nil { - return nil, 0, nil, 0, errors.New("http request timed out or interrupted") - } - if err != nil { - return nil, 0, nil, 0, errors.Wrapf(err, "error making http request") - } - elapsed := time.Since(start) // TODO: return elapsed from utils/http - - if statusCode >= 400 { - maybeErr := bestEffortExtractError(responseBytes) - return nil, statusCode, headers, 0, errors.Errorf("got error from %s: (status code %v) %s", url.String(), statusCode, maybeErr) - } - return responseBytes, statusCode, headers, elapsed, nil -} - -var lowerContentTypeKey = strings.ToLower("Content-Type") - -type PossibleErrorResponses struct { - Error string `json:"error"` - ErrorMessage string `json:"errorMessage"` -} - -func bestEffortExtractError(responseBytes []byte) string { - var resp PossibleErrorResponses - err := json.Unmarshal(responseBytes, &resp) - if err != nil { - return "" - } - if resp.Error != "" { - return resp.Error - } else if resp.ErrorMessage != "" { - return resp.ErrorMessage - } - return string(responseBytes) -} - -func httpRequestCtx(ctx context.Context, t Task) (requestCtx context.Context, cancel context.CancelFunc) { - var defaultHTTPTimeout = 15 * time.Second - - if _, isSet := t.TaskTimeout(); !isSet && defaultHTTPTimeout > 0 { - requestCtx, cancel = context.WithTimeout(ctx, defaultHTTPTimeout) - } else { - requestCtx = ctx - cancel = func() {} - } - return -} diff --git a/pipeline/graph.go b/pipeline/graph.go deleted file mode 100644 index fd326e9..0000000 --- a/pipeline/graph.go +++ /dev/null @@ -1,250 +0,0 @@ -package pipeline - -import ( - "regexp" - "sort" - "strings" - "time" - - "github.com/pkg/errors" - "gonum.org/v1/gonum/graph" - "gonum.org/v1/gonum/graph/encoding" - "gonum.org/v1/gonum/graph/encoding/dot" - "gonum.org/v1/gonum/graph/simple" - "gonum.org/v1/gonum/graph/topo" -) - -// tree fulfills the graph.DirectedGraph interface, which makes it possible -// for us to `dot.Unmarshal(...)` a DOT string directly into it. -type Graph struct { - *simple.DirectedGraph -} - -func NewGraph() *Graph { - return &Graph{DirectedGraph: simple.NewDirectedGraph()} -} - -func (g *Graph) NewNode() graph.Node { - return &GraphNode{Node: g.DirectedGraph.NewNode()} -} - -func (g *Graph) NewEdge(from, to graph.Node) graph.Edge { - return &GraphEdge{Edge: g.DirectedGraph.NewEdge(from, to)} -} - -func (g *Graph) UnmarshalText(bs []byte) (err error) { - if g.DirectedGraph == nil { - g.DirectedGraph = simple.NewDirectedGraph() - } - bs = append([]byte("digraph {\n"), bs...) - bs = append(bs, []byte("\n}")...) - err = dot.Unmarshal(bs, g) - if err != nil { - return errors.Wrap(err, "could not unmarshal DOT into a pipeline.Graph") - } - g.AddImplicitDependenciesAsEdges() - return nil -} - -// Looks at node attributes and searches for implicit dependencies on other nodes -// expressed as attribute values. Adds those dependencies as implicit edges in the graph. -func (g *Graph) AddImplicitDependenciesAsEdges() { - for nodesIter := g.Nodes(); nodesIter.Next(); { - graphNode := nodesIter.Node().(*GraphNode) - - params := make(map[string]bool) - // Walk through all attributes and find all params which this node depends on - for _, attr := range graphNode.Attributes() { - for _, item := range variableRegexp.FindAll([]byte(attr.Value), -1) { - expr := strings.TrimSpace(string(item[2 : len(item)-1])) - param := strings.Split(expr, ".")[0] - params[param] = true - } - } - // Iterate through all nodes and add a new edge if node belongs to params set, and there already isn't an edge. - for nodesIter2 := g.Nodes(); nodesIter2.Next(); { - gn := nodesIter2.Node().(*GraphNode) - if params[gn.DOTID()] { - // If these are distinct nodes with no existing edge between them, then add an implicit edge. - if gn.ID() != graphNode.ID() && !g.HasEdgeFromTo(gn.ID(), graphNode.ID()) { - edge := g.NewEdge(gn, graphNode).(*GraphEdge) - // Setting isImplicit indicates that this edge wasn't specified via the TOML spec, - // but rather added automatically here. - // This distinction is needed, as we don't want to propagate results of a task to its dependent - // tasks along implicit edge, as some tasks can't handle unexpected inputs from implicit edges. - edge.SetIsImplicit(true) - g.SetEdge(edge) - } - } - } - } -} - -// Indicates whether there's an implicit edge from uid -> vid. -// Implicit edged are ones that weren't added via the TOML spec, but via the pipeline parsing code -func (g *Graph) IsImplicitEdge(uid, vid int64) bool { - edge := g.Edge(uid, vid).(*GraphEdge) - if edge == nil { - return false - } - return edge.IsImplicit() -} - -type GraphEdge struct { - graph.Edge - - // Indicates that this edge was implicitly added by the pipeline parser, and not via the TOML specs. - isImplicit bool -} - -func (e *GraphEdge) IsImplicit() bool { - return e.isImplicit -} - -func (e *GraphEdge) SetIsImplicit(isImplicit bool) { - e.isImplicit = isImplicit -} - -type GraphNode struct { - graph.Node - dotID string - attrs map[string]string -} - -func (n *GraphNode) DOTID() string { - return n.dotID -} - -func (n *GraphNode) SetDOTID(id string) { - n.dotID = id -} - -func (n *GraphNode) String() string { - return n.dotID -} - -var bracketQuotedAttrRegexp = regexp.MustCompile(`\A\s*<([^<>]+)>\s*\z`) - -func (n *GraphNode) SetAttribute(attr encoding.Attribute) error { - if n.attrs == nil { - n.attrs = make(map[string]string) - } - - // Strings quoted in angle brackets (supported natively by DOT) should - // have those brackets removed before decoding to task parameter types - sanitized := bracketQuotedAttrRegexp.ReplaceAllString(attr.Value, "$1") - - n.attrs[attr.Key] = sanitized - return nil -} - -func (n *GraphNode) Attributes() []encoding.Attribute { - var r []encoding.Attribute - for k, v := range n.attrs { - r = append(r, encoding.Attribute{Key: k, Value: v}) - } - // Ensure the slice returned is deterministic. - sort.Slice(r, func(i, j int) bool { - return r[i].Key < r[j].Key - }) - return r -} - -type Pipeline struct { - Tasks []Task - tree *Graph - Source string -} - -func (p *Pipeline) UnmarshalText(bs []byte) (err error) { - parsed, err := Parse(string(bs)) - if err != nil { - return err - } - *p = *parsed - return nil -} - -func (p *Pipeline) MinTimeout() (time.Duration, bool, error) { - var minTimeout time.Duration = 1<<63 - 1 - var aTimeoutSet bool - for _, t := range p.Tasks { - if timeout, set := t.TaskTimeout(); set && timeout < minTimeout { - minTimeout = timeout - aTimeoutSet = true - } - } - return minTimeout, aTimeoutSet, nil -} - -func (p *Pipeline) ByDotID(id string) Task { - for _, task := range p.Tasks { - if task.DotID() == id { - return task - } - } - return nil -} - -func Parse(text string) (*Pipeline, error) { - g := NewGraph() - err := g.UnmarshalText([]byte(text)) - - if err != nil { - return nil, err - } - - p := &Pipeline{ - tree: g, - Tasks: make([]Task, 0, g.Nodes().Len()), - Source: text, - } - - // toposort all the nodes: dependencies ordered before outputs. This also does cycle checking for us. - nodes, err := topo.SortStabilized(g, nil) - - if err != nil { - return nil, errors.Wrap(err, "Unable to topologically sort the graph, cycle detected") - } - - // we need a temporary mapping of graph.IDs to positional ids after toposort - ids := make(map[int64]int) - - // use the new ordering as the id so that we can easily reproduce the original toposort - for id, node := range nodes { - node, is := node.(*GraphNode) - if !is { - panic("unreachable") - } - - if node.dotID == InputTaskKey { - return nil, errors.Errorf("'%v' is a reserved keyword that cannot be used as a task's name", InputTaskKey) - } - - task, err := UnmarshalTaskFromMap(TaskType(node.attrs["type"]), node.attrs, id, node.dotID) - if err != nil { - return nil, err - } - - // re-link the edges - for inputs := g.To(node.ID()); inputs.Next(); { - isImplicitEdge := g.IsImplicitEdge(inputs.Node().ID(), node.ID()) - from := p.Tasks[ids[inputs.Node().ID()]] - - from.Base().outputs = append(from.Base().outputs, task) - task.Base().inputs = append(task.Base().inputs, TaskDependency{!isImplicitEdge, from}) - } - - // This is subtle: g.To doesn't return nodes in deterministic order, which would occasionally swap the order - // of inputs, therefore we manually sort. We don't need to sort outputs the same way because these appends happen - // in p.Task order, which is deterministic via topo.SortStable. - sort.Slice(task.Base().inputs, func(i, j int) bool { - return task.Base().inputs[i].InputTask.ID() < task.Base().inputs[j].InputTask.ID() - }) - - p.Tasks = append(p.Tasks, task) - ids[node.ID()] = id - } - - return p, nil -} diff --git a/pipeline/http.go b/pipeline/http.go deleted file mode 100644 index ae730e2..0000000 --- a/pipeline/http.go +++ /dev/null @@ -1,48 +0,0 @@ -package pipeline - -import ( - "fmt" - "io" - "net/http" - "time" - - log "github.com/InjectiveLabs/suplog" -) - -// HTTPRequest holds the request and config struct for a http request -type HTTPRequest struct { - Request *http.Request - Logger log.Logger -} - -// SendRequest sends a HTTPRequest, -// returns a body, status code, and error. -func (h *HTTPRequest) SendRequest() (responseBody []byte, statusCode int, headers http.Header, err error) { - var client *http.Client = &http.Client{} - start := time.Now() - - r, err := client.Do(h.Request) - if err != nil { - h.Logger.WithError(err).Warningln("http adapter got error") - return nil, 0, nil, err - } - - defer r.Body.Close() - - statusCode = r.StatusCode - elapsed := time.Since(start) - h.Logger.Debugln(fmt.Sprintf("http adapter got %v in %s", statusCode, elapsed), "statusCode", statusCode, "timeElapsedSeconds", elapsed) - - source := http.MaxBytesReader(nil, r.Body, 10*1024*1024) - bytes, err := io.ReadAll(source) - if err != nil { - h.Logger.Errorln("http adapter error reading body", "error", err) - return nil, statusCode, nil, err - } - elapsed = time.Since(start) - h.Logger.Debugln(fmt.Sprintf("http adapter finished after %s", elapsed), "statusCode", statusCode, "timeElapsedSeconds", elapsed) - - responseBody = bytes - - return responseBody, statusCode, r.Header, nil -} diff --git a/pipeline/http_allowed_ips.go b/pipeline/http_allowed_ips.go deleted file mode 100644 index 0e136f6..0000000 --- a/pipeline/http_allowed_ips.go +++ /dev/null @@ -1,81 +0,0 @@ -package pipeline - -import ( - "context" - "fmt" - "net" - "time" - - "github.com/pkg/errors" - "go.uber.org/multierr" -) - -var privateIPBlocks []*net.IPNet - -func init() { - for _, cidr := range []string{ - "127.0.0.0/8", // IPv4 loopback - "10.0.0.0/8", // RFC1918 - "172.16.0.0/12", // RFC1918 - "192.168.0.0/16", // RFC1918 - "169.254.0.0/16", // RFC3927 link-local - "::1/128", // IPv6 loopback - "fe80::/10", // IPv6 link-local - "fc00::/7", // IPv6 unique local addr - } { - _, block, err := net.ParseCIDR(cidr) - if err != nil { - panic(fmt.Errorf("parse error on %q: %v", cidr, err)) - } - privateIPBlocks = append(privateIPBlocks, block) - } -} - -func isRestrictedIP(ip net.IP) bool { - if !ip.IsGlobalUnicast() || - ip.IsLoopback() || - ip.IsLinkLocalUnicast() || - ip.IsLinkLocalMulticast() || - ip.IsInterfaceLocalMulticast() || - ip.IsUnspecified() || - ip.Equal(net.IPv4bcast) || - ip.Equal(net.IPv4allsys) || - ip.Equal(net.IPv4allrouter) || - ip.Equal(net.IPv4zero) || - ip.IsMulticast() { - return true - } - - for _, block := range privateIPBlocks { - if block.Contains(ip) { - return true - } - } - return false -} - -var ErrDisallowedIP = errors.New("disallowed IP") - -// restrictedDialContext wraps the Dialer such that after successful connection, -// we check the IP. -// If the resolved IP is restricted, close the connection and return an error. -func restrictedDialContext(ctx context.Context, network, address string) (net.Conn, error) { - con, err := (&net.Dialer{ - // Defaults from GoLang standard http package - // https://golang.org/pkg/net/http/#RoundTripper - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext(ctx, network, address) - if err == nil { - // If a connection could be established, ensure it's not local or private - a, _ := con.RemoteAddr().(*net.TCPAddr) - - if isRestrictedIP(a.IP) { - return nil, multierr.Combine( - errors.Wrapf(ErrDisallowedIP, "disallowed IP %s. Connections to local/private and multicast networks are disabled by default for security reasons", a.IP.String()), - con.Close()) - } - } - return con, err -} diff --git a/pipeline/models.go b/pipeline/models.go deleted file mode 100644 index dc13b31..0000000 --- a/pipeline/models.go +++ /dev/null @@ -1,315 +0,0 @@ -package pipeline - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "math/big" - "strconv" - "time" - - "github.com/pkg/errors" - uuid "github.com/satori/go.uuid" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - null "gopkg.in/guregu/null.v4" -) - -type Spec struct { - ID int32 - DotDagSource string `json:"dotDagSource"` - CreatedAt time.Time `json:"-"` - - JobID int32 `json:"-"` - JobName string `json:"-"` -} - -func (s Spec) Pipeline() (*Pipeline, error) { - return Parse(s.DotDagSource) -} - -type Run struct { - ID int64 `json:"-"` - PipelineSpecID int32 `json:"-"` - PipelineSpec Spec `json:"pipelineSpec"` - Meta JSONSerializable `json:"meta"` - // The errors are only ever strings - // DB example: [null, null, "my error"] - AllErrors RunErrors `json:"all_errors"` - FatalErrors RunErrors `json:"fatal_errors"` - Inputs JSONSerializable `json:"inputs"` - // Its expected that Output.Val is of type []interface{}. - // DB example: [1234, {"a": 10}, null] - Outputs JSONSerializable `json:"outputs"` - CreatedAt time.Time `json:"createdAt"` - FinishedAt null.Time `json:"finishedAt"` - PipelineTaskRuns []TaskRun `json:"taskRuns"` - State RunStatus `json:"state"` - - Pending bool - FailEarly bool -} - -func (r Run) GetID() string { - return fmt.Sprintf("%v", r.ID) -} - -func (r *Run) SetID(value string) error { - ID, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return err - } - r.ID = int64(ID) - return nil -} - -func (r Run) HasFatalErrors() bool { - for _, err := range r.FatalErrors { - if !err.IsZero() { - return true - } - } - return false -} - -func (r Run) HasErrors() bool { - for _, err := range r.AllErrors { - if !err.IsZero() { - return true - } - } - return false -} - -// Status determines the status of the run. -func (r *Run) Status() RunStatus { - if r.HasFatalErrors() { - return RunStatusErrored - } else if r.FinishedAt.Valid { - return RunStatusCompleted - } - - return RunStatusRunning -} - -func (r *Run) ByDotID(id string) *TaskRun { - for i, run := range r.PipelineTaskRuns { - if run.DotID == id { - return &r.PipelineTaskRuns[i] - } - } - return nil -} - -func (r *Run) StringOutputs() ([]*string, error) { - // The UI expects all outputs to be strings. - var outputs []*string - // Note for async jobs, Outputs can be nil/invalid - if r.Outputs.Valid { - outs, ok := r.Outputs.Val.([]interface{}) - if !ok { - return nil, fmt.Errorf("unable to process output type %T", r.Outputs.Val) - } - - if r.Outputs.Valid && r.Outputs.Val != nil { - for _, out := range outs { - switch v := out.(type) { - case string: - s := v - outputs = append(outputs, &s) - case map[string]interface{}: - b, _ := json.Marshal(v) - bs := string(b) - outputs = append(outputs, &bs) - case decimal.Decimal: - s := v.String() - outputs = append(outputs, &s) - case *big.Int: - s := v.String() - outputs = append(outputs, &s) - case float64: - s := fmt.Sprintf("%f", v) - outputs = append(outputs, &s) - case nil: - outputs = append(outputs, nil) - default: - return nil, fmt.Errorf("unable to process output type %T", out) - } - } - } - } - - return outputs, nil -} - -func (r *Run) StringFatalErrors() []*string { - var fatalErrors []*string - - for _, err := range r.FatalErrors { - if err.Valid { - s := err.String - fatalErrors = append(fatalErrors, &s) - } else { - fatalErrors = append(fatalErrors, nil) - } - } - - return fatalErrors -} - -func (r *Run) StringAllErrors() []*string { - var allErrors []*string - - for _, err := range r.AllErrors { - if err.Valid { - s := err.String - allErrors = append(allErrors, &s) - } else { - allErrors = append(allErrors, nil) - } - } - - return allErrors -} - -type RunErrors []null.String - -func (re *RunErrors) Scan(value interface{}) error { - if value == nil { - return nil - } - bytes, ok := value.([]byte) - if !ok { - return errors.Errorf("RunErrors#Scan received a value of type %T", value) - } - return json.Unmarshal(bytes, re) -} - -func (re RunErrors) Value() (driver.Value, error) { - if len(re) == 0 { - return nil, nil - } - return json.Marshal(re) -} - -func (re RunErrors) HasError() bool { - for _, e := range re { - if !e.IsZero() { - return true - } - } - return false -} - -// ToError coalesces all non-nil errors into a single error object. -// This is useful for logging. -func (re RunErrors) ToError() error { - toErr := func(ns null.String) error { - if !ns.IsZero() { - return errors.New(ns.String) - } - return nil - } - errs := []error{} - for _, e := range re { - errs = append(errs, toErr(e)) - } - return multierr.Combine(errs...) -} - -type ResumeRequest struct { - Error null.String `json:"error"` - Value json.RawMessage `json:"value"` -} - -func (rr ResumeRequest) ToResult() (Result, error) { - var res Result - if rr.Error.Valid && rr.Value == nil { - res.Error = errors.New(rr.Error.ValueOrZero()) - return res, nil - } - if !rr.Error.Valid && rr.Value != nil { - res.Value = []byte(rr.Value) - return res, nil - } - return Result{}, errors.New("must provide only one of either 'value' or 'error' key") -} - -type TaskRun struct { - ID uuid.UUID `json:"id"` - Type TaskType `json:"type"` - PipelineRun Run `json:"-"` - PipelineRunID int64 `json:"-"` - Output JSONSerializable `json:"output"` - Error null.String `json:"error"` - CreatedAt time.Time `json:"createdAt"` - FinishedAt null.Time `json:"finishedAt"` - Index int32 `json:"index"` - DotID string `json:"dotId"` - - // Used internally for sorting completed results - task Task -} - -func (tr TaskRun) GetID() string { - return fmt.Sprintf("%v", tr.ID) -} - -func (tr *TaskRun) SetID(value string) error { - ID, err := uuid.FromString(value) - if err != nil { - return err - } - tr.ID = ID - return nil -} - -func (tr TaskRun) GetDotID() string { - return tr.DotID -} - -func (tr TaskRun) Result() Result { - var result Result - if !tr.Error.IsZero() { - result.Error = errors.New(tr.Error.ValueOrZero()) - } else if tr.Output.Valid && tr.Output.Val != nil { - result.Value = tr.Output.Val - } - return result -} - -func (tr *TaskRun) IsPending() bool { - return !tr.FinishedAt.Valid && tr.Output.Empty() && tr.Error.IsZero() -} - -// RunStatus represents the status of a run -type RunStatus string - -const ( - // RunStatusUnknown is the when the run status cannot be determined. - RunStatusUnknown RunStatus = "unknown" - // RunStatusRunning is used for when a run is actively being executed. - RunStatusRunning RunStatus = "running" - // RunStatusSuspended is used when a run is paused and awaiting further results. - RunStatusSuspended RunStatus = "suspended" - // RunStatusErrored is used for when a run has errored and will not complete. - RunStatusErrored RunStatus = "errored" - // RunStatusCompleted is used for when a run has successfully completed execution. - RunStatusCompleted RunStatus = "completed" -) - -// Completed returns true if the status is RunStatusCompleted. -func (s RunStatus) Completed() bool { - return s == RunStatusCompleted -} - -// Errored returns true if the status is RunStatusErrored. -func (s RunStatus) Errored() bool { - return s == RunStatusErrored -} - -// Finished returns true if the status is final and can't be changed. -func (s RunStatus) Finished() bool { - return s.Completed() || s.Errored() -} diff --git a/pipeline/null/int64.go b/pipeline/null/int64.go deleted file mode 100644 index e46fe26..0000000 --- a/pipeline/null/int64.go +++ /dev/null @@ -1,151 +0,0 @@ -package null - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "math" - "reflect" - "strconv" -) - -// Int64 encapsulates the value and validity (not null) of a int64 value, -// to differentiate nil from 0 in json and sql. -type Int64 struct { - Int64 int64 - Valid bool -} - -// NewInt64 returns an instance of Int64 with the passed parameters. -func NewInt64(i int64, valid bool) Int64 { - return Int64{ - Int64: i, - Valid: valid, - } -} - -// Int64From creates a new Int64 that will always be valid. -func Int64From(i int64) Int64 { - return NewInt64(i, true) -} - -// UnmarshalJSON implements json.Unmarshaler. -// It supports number and null input. -// 0 will not be considered a null Int. -func (i *Int64) UnmarshalJSON(data []byte) error { - var err error - var v interface{} - if err = json.Unmarshal(data, &v); err != nil { - return err - } - switch x := v.(type) { - case float64: - // Unmarshal again, directly to value, to avoid intermediate float64 - err = json.Unmarshal(data, &i.Int64) - case string: - str := string(x) - if len(str) == 0 { - i.Valid = false - return nil - } - i.Int64, err = parse64(str) - case nil: - i.Valid = false - return nil - default: - err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int64", reflect.TypeOf(v).Name()) - } - i.Valid = err == nil - return err -} - -// UnmarshalText implements encoding.TextUnmarshaler. -// It will unmarshal to a null Int64 if the input is a blank or not an integer. -// It will return an error if the input is not an integer, blank, or "null". -func (i *Int64) UnmarshalText(text []byte) error { - str := string(text) - if str == "" || str == "null" { - i.Valid = false - return nil - } - var err error - i.Int64, err = parse64(string(text)) - i.Valid = err == nil - return err -} - -func parse64(str string) (int64, error) { - v, err := strconv.ParseInt(str, 10, 64) - return v, err -} - -// MarshalJSON implements json.Marshaler. -// It will encode null if this Int64 is null. -func (i Int64) MarshalJSON() ([]byte, error) { - if !i.Valid { - return []byte("null"), nil - } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil -} - -// MarshalText implements encoding.TextMarshaler. -// It will encode a blank string if this Int64 is null. -func (i Int64) MarshalText() ([]byte, error) { - if !i.Valid { - return []byte{}, nil - } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil -} - -// SetValid changes this Int64's value and also sets it to be non-null. -func (i *Int64) SetValid(n int64) { - i.Int64 = n - i.Valid = true -} - -// Value returns this instance serialized for database storage. -func (i Int64) Value() (driver.Value, error) { - if !i.Valid { - return nil, nil - } - - // golang's sql driver types as determined by IsValue only supports: - // []byte, bool, float64, int64, string, time.Time - // https://golang.org/src/database/sql/driver/types.go - return int64(i.Int64), nil -} - -// Scan reads the database value and returns an instance. -func (i *Int64) Scan(value interface{}) error { - if value == nil { - *i = Int64{} - return nil - } - - switch typed := value.(type) { - case int: - safe := int64(typed) - *i = Int64From(safe) - case int32: - safe := int64(typed) - *i = Int64From(safe) - case int64: - safe := int64(typed) - *i = Int64From(safe) - case uint: - if typed > uint(math.MaxInt64) { - return fmt.Errorf("unable to convert %v of %T to Int64; overflow", value, value) - } - safe := int64(typed) - *i = Int64From(safe) - case uint64: - if typed > uint64(math.MaxInt64) { - return fmt.Errorf("unable to convert %v of %T to Int64; overflow", value, value) - } - safe := int64(typed) - *i = Int64From(safe) - default: - return fmt.Errorf("unable to convert %v of %T to Int64", value, value) - } - return nil -} diff --git a/pipeline/null/uint32.go b/pipeline/null/uint32.go deleted file mode 100644 index 0bafef0..0000000 --- a/pipeline/null/uint32.go +++ /dev/null @@ -1,150 +0,0 @@ -package null - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "reflect" - "strconv" -) - -// Uint32 encapsulates the value and validity (not null) of a uint32 value, -// to differentiate nil from 0 in json and sql. -type Uint32 struct { - Uint32 uint32 - Valid bool -} - -// NewUint32 returns an instance of Uint32 with the passed parameters. -func NewUint32(i uint32, valid bool) Uint32 { - return Uint32{ - Uint32: i, - Valid: valid, - } -} - -// Uint32From creates a new Uint32 that will always be valid. -func Uint32From(i uint32) Uint32 { - return NewUint32(i, true) -} - -// UnmarshalJSON implements json.Unmarshaler. -// It supports number and null input. -// 0 will not be considered a null Int. -func (i *Uint32) UnmarshalJSON(data []byte) error { - var err error - var v interface{} - if err = json.Unmarshal(data, &v); err != nil { - return err - } - switch x := v.(type) { - case float64: - // Unmarshal again, directly to value, to avoid intermediate float64 - err = json.Unmarshal(data, &i.Uint32) - case string: - str := string(x) - if len(str) == 0 { - i.Valid = false - return nil - } - i.Uint32, err = parse(str) - case nil: - i.Valid = false - return nil - default: - err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Uint32", reflect.TypeOf(v).Name()) - } - i.Valid = err == nil - return err -} - -// UnmarshalText implements encoding.TextUnmarshaler. -// It will unmarshal to a null Uint32 if the input is a blank or not an integer. -// It will return an error if the input is not an integer, blank, or "null". -func (i *Uint32) UnmarshalText(text []byte) error { - str := string(text) - if str == "" || str == "null" { - i.Valid = false - return nil - } - var err error - i.Uint32, err = parse(string(text)) - i.Valid = err == nil - return err -} - -func parse(str string) (uint32, error) { - v, err := strconv.ParseUint(str, 10, 32) - return uint32(v), err -} - -// MarshalJSON implements json.Marshaler. -// It will encode null if this Uint32 is null. -func (i Uint32) MarshalJSON() ([]byte, error) { - if !i.Valid { - return []byte("null"), nil - } - return []byte(strconv.FormatUint(uint64(i.Uint32), 10)), nil -} - -// MarshalText implements encoding.TextMarshaler. -// It will encode a blank string if this Uint32 is null. -func (i Uint32) MarshalText() ([]byte, error) { - if !i.Valid { - return []byte{}, nil - } - return []byte(strconv.FormatUint(uint64(i.Uint32), 10)), nil -} - -// SetValid changes this Uint32's value and also sets it to be non-null. -func (i *Uint32) SetValid(n uint32) { - i.Uint32 = n - i.Valid = true -} - -// Value returns this instance serialized for database storage. -func (i Uint32) Value() (driver.Value, error) { - if !i.Valid { - return nil, nil - } - - // golang's sql driver types as determined by IsValue only supports: - // []byte, bool, float64, int64, string, time.Time - // https://golang.org/src/database/sql/driver/types.go - return int64(i.Uint32), nil -} - -// Scan reads the database value and returns an instance. -func (i *Uint32) Scan(value interface{}) error { - if value == nil { - *i = Uint32{} - return nil - } - - switch typed := value.(type) { - case int: - safe := uint32(typed) - if int(safe) != typed { - return fmt.Errorf("unable to convert %v of %T to Uint32; overflow", value, value) - } - *i = Uint32From(safe) - case int64: - safe := uint32(typed) - if int64(safe) != typed { - return fmt.Errorf("unable to convert %v of %T to Uint32; overflow", value, value) - } - *i = Uint32From(safe) - case uint: - safe := uint32(typed) - if uint(safe) != typed { - return fmt.Errorf("unable to convert %v of %T to Uint32; overflow", value, value) - } - *i = Uint32From(safe) - case uint32: - safe := typed - *i = Uint32From(safe) - default: - return fmt.Errorf("unable to convert %v of %T to Uint32", value, value) - } - return nil -} diff --git a/pipeline/runner.go b/pipeline/runner.go deleted file mode 100644 index 831da4b..0000000 --- a/pipeline/runner.go +++ /dev/null @@ -1,272 +0,0 @@ -package pipeline - -import ( - "context" - "fmt" - "sort" - "time" - - log "github.com/InjectiveLabs/suplog" - "github.com/pkg/errors" - uuid "github.com/satori/go.uuid" - null "gopkg.in/guregu/null.v4" -) - -type Runner interface { - // ExecuteRun executes a new run in-memory according to a spec and returns the results. - ExecuteRun(ctx context.Context, spec Spec, vars Vars, l log.Logger) (run Run, trrs TaskRunResults, err error) -} - -type runner struct { - lggr log.Logger -} - -func NewRunner(lggr log.Logger) *runner { - r := &runner{ - lggr: lggr.WithField("svc", "PipelineRunner"), - } - - return r -} - -type memoryTaskRun struct { - task Task - inputs []Result // sorted by input index - vars Vars - attempts uint -} - -// When a task panics, we catch the panic and wrap it in an error for reporting to the scheduler. -type ErrRunPanicked struct { - v interface{} -} - -func (err ErrRunPanicked) Error() string { - return fmt.Sprintf("goroutine panicked when executing run: %v", err.v) -} - -func NewRun(spec Spec, vars Vars) Run { - return Run{ - State: RunStatusRunning, - PipelineSpec: spec, - PipelineSpecID: spec.ID, - Inputs: JSONSerializable{Val: vars.vars, Valid: true}, - Outputs: JSONSerializable{Val: nil, Valid: false}, - CreatedAt: time.Now(), - } -} - -func (r *runner) ExecuteRun( - ctx context.Context, - spec Spec, - vars Vars, - l log.Logger, -) (Run, TaskRunResults, error) { - run := NewRun(spec, vars) - - pipeline, err := r.initializePipeline(&run) - - if err != nil { - return run, nil, err - } - - taskRunResults, err := r.run(ctx, pipeline, &run, vars, l) - if err != nil { - return run, nil, err - } - - if run.Pending { - return run, nil, errors.Wrapf(err, "unexpected async run for spec ID %v, tried executing via ExecuteAndInsertFinishedRun", spec.ID) - } - - return run, taskRunResults, nil -} - -func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { - pipeline, err := Parse(run.PipelineSpec.DotDagSource) - if err != nil { - return nil, err - } - - // initialize certain task params - for _, task := range pipeline.Tasks { - task.Base().uuid = uuid.NewV4() - } - - // retain old UUID values - for _, taskRun := range run.PipelineTaskRuns { - task := pipeline.ByDotID(taskRun.DotID) - task.Base().uuid = taskRun.ID - } - - return pipeline, nil -} - -func (r *runner) run( - ctx context.Context, - pipeline *Pipeline, - run *Run, - vars Vars, - l log.Logger, -) (TaskRunResults, error) { - l.Debugln("Initiating tasks for pipeline run of spec", "job ID", run.PipelineSpec.JobID, "job name", run.PipelineSpec.JobName) - - scheduler := newScheduler(pipeline, run, vars, l) - go scheduler.Run() - - // This is "just in case" for cleaning up any stray reports. - // Normally the scheduler loop doesn't stop until all in progress runs report back - reportCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - ctx, cancel = context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - - for taskRun := range scheduler.taskCh { - taskRun := taskRun - // execute - go WrapRecoverHandle(l, func() { - result := r.executeTaskRun(ctx, run.PipelineSpec, taskRun, l) - - scheduler.report(reportCtx, result) - }, func(err interface{}) { - t := time.Now() - scheduler.report(reportCtx, TaskRunResult{ - ID: uuid.NewV4(), - Task: taskRun.task, - Result: Result{Error: ErrRunPanicked{err}}, - FinishedAt: null.TimeFrom(t), - CreatedAt: t, // TODO: more accurate start time - }) - }) - } - - // if the run is suspended, awaiting resumption - run.Pending = scheduler.pending - run.FailEarly = scheduler.exiting - run.State = RunStatusSuspended - - if !scheduler.pending { - run.FinishedAt = null.TimeFrom(time.Now()) - - // NOTE: runTime can be very long now because it'll include suspend - runTime := run.FinishedAt.Time.Sub(run.CreatedAt) - l.Debugln("Finished all tasks for pipeline run", "specID", run.PipelineSpecID, "runTime", runTime) - } - - // Update run results - run.PipelineTaskRuns = nil - for _, result := range scheduler.results { - output := result.Result.OutputDB() - run.PipelineTaskRuns = append(run.PipelineTaskRuns, TaskRun{ - ID: result.ID, - PipelineRunID: run.ID, - Type: result.Task.Type(), - Index: result.Task.OutputIndex(), - Output: output, - Error: result.Result.ErrorDB(), - DotID: result.Task.DotID(), - CreatedAt: result.CreatedAt, - FinishedAt: result.FinishedAt, - task: result.Task, - }) - - sort.Slice(run.PipelineTaskRuns, func(i, j int) bool { - return run.PipelineTaskRuns[i].task.OutputIndex() < run.PipelineTaskRuns[j].task.OutputIndex() - }) - } - - // Update run errors/outputs - if run.FinishedAt.Valid { - var errors []null.String - var fatalErrors []null.String - var outputs []interface{} - for _, result := range run.PipelineTaskRuns { - if result.Error.Valid { - errors = append(errors, result.Error) - } - // skip non-terminal results - if len(result.task.Outputs()) != 0 { - continue - } - fatalErrors = append(fatalErrors, result.Error) - outputs = append(outputs, result.Output.Val) - } - run.AllErrors = errors - run.FatalErrors = fatalErrors - run.Outputs = JSONSerializable{Val: outputs, Valid: true} - - if run.HasFatalErrors() { - run.State = RunStatusErrored - } else { - run.State = RunStatusCompleted - } - } - - // TODO: drop this once we stop using TaskRunResults - var taskRunResults TaskRunResults - for _, result := range scheduler.results { - taskRunResults = append(taskRunResults, result) - } - - return taskRunResults, nil -} - -func (r *runner) executeTaskRun(ctx context.Context, spec Spec, taskRun *memoryTaskRun, l log.Logger) TaskRunResult { - start := time.Now() - l = l.WithFields(log.Fields{ - "taskName": taskRun.task.DotID(), - "taskType": taskRun.task.Type(), - "attempt": taskRun.attempts, - }) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - if taskTimeout, isSet := taskRun.task.TaskTimeout(); isSet && taskTimeout > 0 { - ctx, cancel = context.WithTimeout(ctx, taskTimeout) - defer cancel() - } - - result, runInfo := taskRun.task.Run(ctx, l, taskRun.vars, taskRun.inputs) - loggerFields := log.Fields{"runInfo": runInfo, - "resultValue": result.Value, - "resultError": result.Error, - "resultType": fmt.Sprintf("%T", result.Value), - } - switch v := result.Value.(type) { - case []byte: - loggerFields["resultString"] = fmt.Sprintf("%q", v) - loggerFields["resultHex"] = fmt.Sprintf("%x", v) - } - - l.WithFields(loggerFields).Debugln("Pipeline task completed") - - now := time.Now() - - var finishedAt null.Time - if !runInfo.IsPending { - finishedAt = null.TimeFrom(now) - } - return TaskRunResult{ - ID: taskRun.task.Base().uuid, - Task: taskRun.task, - Result: result, - CreatedAt: start, - FinishedAt: finishedAt, - runInfo: runInfo, - } -} - -func WrapRecoverHandle(lggr log.Logger, fn func(), onPanic func(interface{})) { - defer func() { - if err := recover(); err != nil { - lggr.WithError(err.(error)).Errorln("recovered after panic") - - if onPanic != nil { - onPanic(err) - } - } - }() - fn() -} diff --git a/pipeline/scheduler.go b/pipeline/scheduler.go deleted file mode 100644 index 2966c43..0000000 --- a/pipeline/scheduler.go +++ /dev/null @@ -1,294 +0,0 @@ -package pipeline - -import ( - "context" - "sort" - "time" - - log "github.com/InjectiveLabs/suplog" - "github.com/jpillora/backoff" - "github.com/pkg/errors" - null "gopkg.in/guregu/null.v4" -) - -func (s *scheduler) newMemoryTaskRun(task Task) *memoryTaskRun { - run := &memoryTaskRun{task: task, vars: s.vars.Copy()} - - propagatableInputs := 0 - for _, i := range task.Inputs() { - if i.PropagateResult { - propagatableInputs++ - } - } - // fill in the inputs, fast path for no inputs - if propagatableInputs != 0 { - // construct a list of inputs, sorted by OutputIndex - type input struct { - index int32 - result Result - } - inputs := make([]input, 0, propagatableInputs) - // NOTE: we could just allocate via make, then assign directly to run.inputs[i.OutputIndex()] - // if we're confident that indices are within range - for _, i := range task.Inputs() { - if i.PropagateResult { - inputs = append(inputs, input{index: int32(i.InputTask.OutputIndex()), result: s.results[i.InputTask.ID()].Result}) - } - } - sort.Slice(inputs, func(i, j int) bool { - return inputs[i].index < inputs[j].index - }) - run.inputs = make([]Result, len(inputs)) - for i, input := range inputs { - run.inputs[i] = input.result - } - } - - return run -} - -type scheduler struct { - ctx context.Context - cancel context.CancelFunc - pipeline *Pipeline - run *Run - dependencies map[int]uint - waiting uint - results map[int]TaskRunResult - vars Vars - logger log.Logger - - pending bool - exiting bool - - taskCh chan *memoryTaskRun - resultCh chan TaskRunResult -} - -func newScheduler(p *Pipeline, run *Run, vars Vars, lggr log.Logger) *scheduler { - lggr = lggr.WithField("svc", "Scheduler") - dependencies := make(map[int]uint, len(p.Tasks)) - - for id, task := range p.Tasks { - len := len(task.Inputs()) - dependencies[id] = uint(len) - } - - ctx, cancel := context.WithCancel(context.Background()) - - s := &scheduler{ - ctx: ctx, - cancel: cancel, - pipeline: p, - run: run, - dependencies: dependencies, - results: make(map[int]TaskRunResult, len(p.Tasks)), - vars: vars, - logger: lggr, - - // taskCh should never block - taskCh: make(chan *memoryTaskRun, len(dependencies)), - resultCh: make(chan TaskRunResult), - } - - // if there's results already present on Run, then this is a resumption. Loop over them and fill results table - s.reconstructResults() - - // immediately schedule all doable tasks - for id, task := range p.Tasks { - // skip tasks that are not ready - if s.dependencies[id] != 0 { - continue - } - - // skip finished tasks - if _, exists := s.results[id]; exists { - continue - } - - run := s.newMemoryTaskRun(task) - - lggr.Debugln("scheduling task run", "dot_id", task.DotID(), "attempts", run.attempts) - - s.taskCh <- run - s.waiting++ - } - - return s -} - -func (s *scheduler) reconstructResults() { - // if there's results already present on Run, then this is a resumption. Loop over them and fill results table - for _, r := range s.run.PipelineTaskRuns { - task := s.pipeline.ByDotID(r.DotID) - - if task == nil { - panic("can't find task by dot id") - } - - if r.IsPending() { - continue - } - - result := Result{} - - if r.Error.Valid { - result.Error = errors.New(r.Error.String) - } - - if r.Output.Valid { - result.Value = r.Output.Val - } - - s.results[task.ID()] = TaskRunResult{ - Task: task, - Result: result, - CreatedAt: r.CreatedAt, - FinishedAt: r.FinishedAt, - } - - // store the result in vars - if result.Error != nil { - s.vars.Set(task.DotID(), result.Error) - } else { - s.vars.Set(task.DotID(), result.Value) - } - - // mark all outputs as complete - for _, output := range task.Outputs() { - id := output.ID() - s.dependencies[id]-- - } - } -} - -func (s *scheduler) Run() { - for s.waiting > 0 { - // we don't "for result in resultCh" because it would stall if the - // pipeline is completely empty - - result := <-s.resultCh - // TODO: if for some reason the cleanup didn't succeed and we're stuck waiting for reports forever - // we should be able to timeout and finish shutting down - // See: https://app.shortcut.com/chainlinklabs/story/21225/straighten-out-and-clarify-context-usage-in-the-pipeline - - s.waiting-- - - // retrieve previous attempt count - result.Attempts = s.results[result.Task.ID()].Attempts - - // only count as an attempt if the job actually ran. If we're exiting then it got cancelled - if !s.exiting { - result.Attempts++ - } - - // store task run - s.results[result.Task.ID()] = result - - // catch the pending state, we will keep the pipeline running until no more progress is made - if result.runInfo.IsPending { - s.pending = true - - // skip output wrangling because this task isn't actually complete yet - continue - } - - // store the result in vars - if result.Result.Error != nil { - s.vars.Set(result.Task.DotID(), result.Result.Error) - } else { - s.vars.Set(result.Task.DotID(), result.Result.Value) - } - - // if the task was marked as fail early, and the result is a fail - if result.Result.Error != nil && result.Task.Base().FailEarly { - // drain remaining jobs (continue the loop until waiting = 0) then exit - s.exiting = true - s.cancel() // cleanup: terminate pending retries - - // mark remaining jobs as cancelled - s.markRemaining(ErrCancelled) - } - - if s.exiting { - // skip scheduling dependencies if we're exiting early - continue - } - - // if task hasn't reached it's max retry count yet, we schedule it again - if result.Attempts < uint(result.Task.TaskRetries()) && result.Result.Error != nil { - // we immediately increase the in-flight counter so the pipeline doesn't terminate - // while we wait for the next retry - s.waiting++ - - backoff := backoff.Backoff{ - Factor: 2, - Min: result.Task.TaskMinBackoff(), - Max: result.Task.TaskMaxBackoff(), - } - - go func() { - select { - case <-s.ctx.Done(): - // report back so the waiting counter gets decreased - now := time.Now() - s.report(context.Background(), TaskRunResult{ - Task: result.Task, - Result: Result{Error: ErrCancelled}, - CreatedAt: now, // TODO: more accurate start time - FinishedAt: null.TimeFrom(now), - }) - case <-time.After(backoff.ForAttempt(float64(result.Attempts - 1))): // we subtract 1 because backoff 0-indexes - // schedule a new attempt - run := s.newMemoryTaskRun(result.Task) - run.attempts = result.Attempts - s.logger.Debugln("scheduling task run", "dot_id", run.task.DotID(), "attempts", run.attempts) - s.taskCh <- run - } - }() - - // skip scheduling dependencies since it's the task is not complete yet - continue - } - - for _, output := range result.Task.Outputs() { - id := output.ID() - s.dependencies[id]-- - - // if all dependencies are done, schedule task run - if s.dependencies[id] == 0 { - task := s.pipeline.Tasks[id] - run := s.newMemoryTaskRun(task) - - s.logger.Debugln("scheduling task run", "dot_id", run.task.DotID(), "attempts", run.attempts) - s.taskCh <- run - s.waiting++ - } - } - - } - - close(s.taskCh) -} - -func (s *scheduler) markRemaining(err error) { - now := time.Now() - for _, task := range s.pipeline.Tasks { - if _, ok := s.results[task.ID()]; !ok { - s.results[task.ID()] = TaskRunResult{ - Task: task, - Result: Result{Error: err}, - CreatedAt: now, // TODO: more accurate start time - FinishedAt: null.TimeFrom(now), - } - } - } -} - -func (s *scheduler) report(ctx context.Context, result TaskRunResult) { - select { - case s.resultCh <- result: - case <-ctx.Done(): - s.logger.Errorln("pipeline.scheduler: discarding result; report context timed out", "result", result, "err", ctx.Err()) - } -} diff --git a/pipeline/task.any.go b/pipeline/task.any.go deleted file mode 100644 index 378f8b2..0000000 --- a/pipeline/task.any.go +++ /dev/null @@ -1,52 +0,0 @@ -package pipeline - -import ( - "context" - "crypto/rand" - "math/big" - - "github.com/pkg/errors" - - log "github.com/InjectiveLabs/suplog" -) - -// AnyTask picks a value at random from the set of non-errored inputs. -// If there are zero non-errored inputs then it returns an error. -type AnyTask struct { - BaseTask `mapstructure:",squash"` -} - -var _ Task = (*AnyTask)(nil) - -func (t *AnyTask) Type() TaskType { - return TaskTypeAny -} - -func (t *AnyTask) Run(_ context.Context, _ log.Logger, _ Vars, inputs []Result) (result Result, runInfo RunInfo) { - if len(inputs) == 0 { - return Result{Error: errors.Wrapf(ErrWrongInputCardinality, "AnyTask requires at least 1 input")}, runInfo - } - - var answers []interface{} - - for _, input := range inputs { - if input.Error != nil { - continue - } - - answers = append(answers, input.Value) - } - - if len(answers) == 0 { - return Result{Error: errors.Wrapf(ErrBadInput, "There were zero non-errored inputs")}, runInfo - } - - nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(answers)))) - if err != nil { - return Result{Error: errors.Wrapf(err, "Failed to generate random number for picking input")}, retryableRunInfo() - } - i := int(nBig.Int64()) - answer := answers[i] - - return Result{Value: answer}, runInfo -} diff --git a/pipeline/task.base.go b/pipeline/task.base.go deleted file mode 100644 index c1fb38a..0000000 --- a/pipeline/task.base.go +++ /dev/null @@ -1,78 +0,0 @@ -package pipeline - -import ( - "time" - - "github.com/InjectiveLabs/injective-price-oracle/pipeline/null" - uuid "github.com/satori/go.uuid" -) - -type BaseTask struct { - outputs []Task - inputs []TaskDependency - - id int - dotID string - Index int32 `mapstructure:"index" json:"-" ` - Timeout *time.Duration `mapstructure:"timeout"` - FailEarly bool `mapstructure:"failEarly"` - - Retries null.Uint32 `mapstructure:"retries"` - MinBackoff time.Duration `mapstructure:"minBackoff"` - MaxBackoff time.Duration `mapstructure:"maxBackoff"` - - uuid uuid.UUID -} - -func NewBaseTask(id int, dotID string, inputs []TaskDependency, outputs []Task, index int32) BaseTask { - return BaseTask{id: id, dotID: dotID, inputs: inputs, outputs: outputs, Index: index} -} - -func (t *BaseTask) Base() *BaseTask { - return t -} - -func (t BaseTask) ID() int { - return t.id -} - -func (t BaseTask) DotID() string { - return t.dotID -} - -func (t BaseTask) OutputIndex() int32 { - return t.Index -} - -func (t BaseTask) Outputs() []Task { - return t.outputs -} - -func (t BaseTask) Inputs() []TaskDependency { - return t.inputs -} - -func (t BaseTask) TaskTimeout() (time.Duration, bool) { - if t.Timeout == nil { - return time.Duration(0), false - } - return *t.Timeout, true -} - -func (t BaseTask) TaskRetries() uint32 { - return t.Retries.Uint32 -} - -func (t BaseTask) TaskMinBackoff() time.Duration { - if t.MinBackoff > 0 { - return t.MinBackoff - } - return time.Second * 5 -} - -func (t BaseTask) TaskMaxBackoff() time.Duration { - if t.MinBackoff > 0 { - return t.MaxBackoff - } - return time.Minute -} diff --git a/pipeline/task.divide.go b/pipeline/task.divide.go deleted file mode 100644 index 9837d2e..0000000 --- a/pipeline/task.divide.go +++ /dev/null @@ -1,54 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// *decimal.Decimal -type DivideTask struct { - BaseTask `mapstructure:",squash"` - Input string `json:"input"` - Divisor string `json:"divisor"` - Precision string `json:"precision"` -} - -var _ Task = (*DivideTask)(nil) - -func (t *DivideTask) Type() TaskType { - return TaskTypeDivide -} - -func (t *DivideTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, -1, -1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - a DecimalParam - b DecimalParam - maybePrecision MaybeInt32Param - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&a, From(VarExpr(t.Input, vars), Input(inputs, 0))), "input"), - errors.Wrap(ResolveParam(&b, From(VarExpr(t.Divisor, vars), NonemptyString(t.Divisor))), "divisor"), - errors.Wrap(ResolveParam(&maybePrecision, From(VarExpr(t.Precision, vars), t.Precision)), "precision"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - if precision, isSet := maybePrecision.Int32(); isSet { - return Result{Value: a.Decimal().DivRound(b.Decimal(), precision)}, runInfo - } - // Note that decimal library defaults to rounding to 16 precision - // https://github.com/shopspring/decimal/blob/2568a29459476f824f35433dfbef158d6ad8618c/decimal.go#L44 - return Result{Value: a.Decimal().Div(b.Decimal())}, runInfo -} diff --git a/pipeline/task.eth_abi_decode.go b/pipeline/task.eth_abi_decode.go deleted file mode 100644 index c8895a4..0000000 --- a/pipeline/task.eth_abi_decode.go +++ /dev/null @@ -1,57 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// map[string]interface{} with any geth/abigen value type -type ETHABIDecodeTask struct { - BaseTask `mapstructure:",squash"` - ABI string `json:"abi"` - Data string `json:"data"` -} - -var _ Task = (*ETHABIDecodeTask)(nil) - -func (t *ETHABIDecodeTask) Type() TaskType { - return TaskTypeETHABIDecode -} - -func (t *ETHABIDecodeTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - data BytesParam - theABI BytesParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&data, From(VarExpr(t.Data, vars), Input(inputs, 0))), "data"), - errors.Wrap(ResolveParam(&theABI, From(NonemptyString(t.ABI))), "abi"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - args, _, err := ParseETHABIArgsString([]byte(theABI), false) - if err != nil { - return Result{Error: errors.Wrap(ErrBadInput, err.Error())}, runInfo - } - - out := make(map[string]interface{}) - if len(data) > 0 { - if err := args.UnpackIntoMap(out, []byte(data)); err != nil { - return Result{Error: err}, runInfo - } - } - return Result{Value: out}, runInfo -} diff --git a/pipeline/task.eth_abi_decode_log.go b/pipeline/task.eth_abi_decode_log.go deleted file mode 100644 index 9637d6b..0000000 --- a/pipeline/task.eth_abi_decode_log.go +++ /dev/null @@ -1,70 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// map[string]interface{} with any geth/abigen value type -type ETHABIDecodeLogTask struct { - BaseTask `mapstructure:",squash"` - ABI string `json:"abi"` - Data string `json:"data"` - Topics string `json:"topics"` -} - -var _ Task = (*ETHABIDecodeLogTask)(nil) - -func (t *ETHABIDecodeLogTask) Type() TaskType { - return TaskTypeETHABIDecodeLog -} - -func (t *ETHABIDecodeLogTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, -1, -1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - theABI BytesParam - data BytesParam - topics HashSliceParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&data, From(VarExpr(t.Data, vars), nil)), "data"), - errors.Wrap(ResolveParam(&topics, From(VarExpr(t.Topics, vars))), "topics"), - errors.Wrap(ResolveParam(&theABI, From(NonemptyString(t.ABI))), "abi"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - _, args, indexedArgs, err := parseETHABIString([]byte(theABI), true) - if err != nil { - return Result{Error: errors.Wrap(ErrBadInput, err.Error())}, runInfo - } - - out := make(map[string]interface{}) - if len(data) > 0 { - if err2 := args.UnpackIntoMap(out, []byte(data)); err2 != nil { - return Result{Error: errors.Wrap(ErrBadInput, err2.Error())}, runInfo - } - } - if len(indexedArgs) > 0 { - if len(topics) != len(indexedArgs)+1 { - return Result{Error: errors.Wrap(ErrBadInput, "topic/field count mismatch")}, runInfo - } - err = abi.ParseTopicsIntoMap(out, indexedArgs, topics[1:]) - if err != nil { - return Result{Error: errors.Wrap(ErrBadInput, err.Error())}, runInfo - } - } - return Result{Value: out}, runInfo -} diff --git a/pipeline/task.eth_abi_encode.go b/pipeline/task.eth_abi_encode.go deleted file mode 100644 index eed74a9..0000000 --- a/pipeline/task.eth_abi_encode.go +++ /dev/null @@ -1,77 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// []byte -type ETHABIEncodeTask struct { - BaseTask `mapstructure:",squash"` - ABI string `json:"abi"` - Data string `json:"data"` -} - -var _ Task = (*ETHABIEncodeTask)(nil) - -func (t *ETHABIEncodeTask) Type() TaskType { - return TaskTypeETHABIEncode -} - -func (t *ETHABIEncodeTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, -1, -1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - inputValues MapParam - theABI BytesParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&inputValues, From(VarExpr(t.Data, vars), JSONWithVarExprs(t.Data, vars, false), nil)), "data"), - errors.Wrap(ResolveParam(&theABI, From(NonemptyString(t.ABI))), "abi"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - methodName, args, _, err := parseETHABIString([]byte(theABI), false) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: while parsing ABI string: %v", err)}, runInfo - } - method := abi.NewMethod(methodName, methodName, abi.Function, "", false, false, args, nil) - - var vals []interface{} - for _, arg := range args { - val, exists := inputValues[arg.Name] - if !exists { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: argument '%v' is missing", arg.Name)}, runInfo - } - val, err = convertToETHABIType(val, arg.Type) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: while converting argument '%v' from %T to %v: %v", arg.Name, val, arg.Type, err)}, runInfo - } - vals = append(vals, val) - } - - argsEncoded, err := method.Inputs.Pack(vals...) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: could not ABI encode values: %v", err)}, runInfo - } - var dataBytes []byte - if methodName != "" { - dataBytes = append(method.ID, argsEncoded...) - } else { - dataBytes = argsEncoded - } - return Result{Value: hexutil.Encode(dataBytes)}, runInfo -} diff --git a/pipeline/task.eth_abi_encode_2.go b/pipeline/task.eth_abi_encode_2.go deleted file mode 100644 index 0f590f5..0000000 --- a/pipeline/task.eth_abi_encode_2.go +++ /dev/null @@ -1,90 +0,0 @@ -package pipeline - -import ( - "context" - "encoding/json" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// []byte -type ETHABIEncodeTask2 struct { - BaseTask `mapstructure:",squash"` - ABI string `json:"abi"` - Data string `json:"data"` -} - -var _ Task = (*ETHABIEncodeTask2)(nil) - -func (t *ETHABIEncodeTask2) Type() TaskType { - return TaskTypeETHABIEncode -} - -func (t *ETHABIEncodeTask2) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (Result, RunInfo) { - _, err := CheckInputs(inputs, -1, -1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, RunInfo{} - } - - var ( - inputValues MapParam - theABI BytesParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&inputValues, From(VarExpr(t.Data, vars), JSONWithVarExprs(t.Data, vars, false), nil)), "data"), - errors.Wrap(ResolveParam(&theABI, From(NonemptyString(t.ABI))), "abi"), - ) - if err != nil { - return Result{Error: err}, RunInfo{} - } - - inputMethod := Method{} - err = json.Unmarshal(theABI, &inputMethod) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: while parsing ABI string: %v", err)}, RunInfo{} - } - - method := abi.NewMethod(inputMethod.Name, inputMethod.Name, abi.Function, "", false, false, inputMethod.Inputs, nil) - - var vals []interface{} - for _, arg := range method.Inputs { - if len(arg.Name) == 0 { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: bad ABI specification, missing argument name")}, RunInfo{} - } - val, exists := inputValues[arg.Name] - if !exists { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: argument '%v' is missing", arg.Name)}, RunInfo{} - } - val, err = convertToETHABIType(val, arg.Type) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: while converting argument '%v' from %T to %v: %v", arg.Name, val, arg.Type, err)}, RunInfo{} - } - vals = append(vals, val) - } - - argsEncoded, err := method.Inputs.Pack(vals...) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "ETHABIEncode: could not ABI encode values: %v", err)}, RunInfo{} - } - var dataBytes []byte - if method.Name != "" { - dataBytes = append(method.ID, argsEncoded...) - } else { - dataBytes = argsEncoded - } - return Result{Value: hexutil.Encode(dataBytes)}, RunInfo{} -} - -// go-ethereum's abi.Method doesn't implement json.Marshal for Type, but -// otherwise would have worked fine, in any case we only care about these... -type Method struct { - Name string - Inputs abi.Arguments -} diff --git a/pipeline/task.fail.go b/pipeline/task.fail.go deleted file mode 100644 index 63e379c..0000000 --- a/pipeline/task.fail.go +++ /dev/null @@ -1,26 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - - log "github.com/InjectiveLabs/suplog" -) - -// FailTask is like the Panic task but without all the drama and stack -// unwinding of a panic -type FailTask struct { - BaseTask `mapstructure:",squash"` - Msg string -} - -var _ Task = (*FailTask)(nil) - -func (t *FailTask) Type() TaskType { - return TaskTypeFail -} - -func (t *FailTask) Run(_ context.Context, _ log.Logger, vars Vars, _ []Result) (Result, RunInfo) { - return Result{Error: errors.New(t.Msg)}, RunInfo{} -} diff --git a/pipeline/task.http.go b/pipeline/task.http.go deleted file mode 100644 index 41dcd16..0000000 --- a/pipeline/task.http.go +++ /dev/null @@ -1,90 +0,0 @@ -package pipeline - -import ( - "context" - "encoding/json" - - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" - "github.com/pkg/errors" -) - -// Return types: -// -// string -type HTTPTask struct { - BaseTask `mapstructure:",squash"` - Method string - URL string - RequestData string `json:"requestData"` - HeaderMap string `json:"headerMap"` -} - -var _ Task = (*HTTPTask)(nil) - -func (t *HTTPTask) Type() TaskType { - return TaskTypeHTTP -} - -func (t *HTTPTask) Run(ctx context.Context, lggr log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, -1, -1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - method StringParam - url URLParam - requestData MapParam - headerMap MapParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&method, From(NonemptyString(t.Method), "GET")), "method"), - errors.Wrap(ResolveParam(&url, From(VarExpr(t.URL, vars), NonemptyString(t.URL))), "url"), - errors.Wrap(ResolveParam(&requestData, From(VarExpr(t.RequestData, vars), JSONWithVarExprs(t.RequestData, vars, false), nil)), "requestData"), - errors.Wrap(ResolveParam(&headerMap, From(VarExpr(t.HeaderMap, vars), JSONWithVarExprs(t.HeaderMap, vars, false), nil)), "headerMap"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - requestDataJSON, err := json.Marshal(requestData) - if err != nil { - return Result{Error: err}, runInfo - } - - headerMapJSON, err := json.Marshal(headerMap) - if err != nil { - return Result{Error: err}, runInfo - } - - lggr.Debugln("HTTP task: sending request", - "requestData", string(requestDataJSON), - "headerMap", string(headerMapJSON), - "url", url.String(), - "method", method, - ) - - requestCtx, cancel := httpRequestCtx(ctx, t) - defer cancel() - - responseBytes, statusCode, _, elapsed, err := makeHTTPRequest(requestCtx, lggr, method, url, requestData, headerMap) - if err != nil { - return Result{Error: err}, RunInfo{IsRetryable: isRetryableHTTPError(statusCode, err)} - } - - _ = elapsed - - lggr.Debugln("HTTP task got response", - "response", string(responseBytes), - "url", url.String(), - "dotID", t.DotID(), - ) - - // NOTE: We always stringify the response since this is required for all current jobs. - // If a binary response is required we might consider adding an adapter - // flag such as "BinaryMode: true" which passes through raw binary as the - // value instead. - return Result{Value: string(responseBytes)}, runInfo -} diff --git a/pipeline/task.jsonparse.go b/pipeline/task.jsonparse.go deleted file mode 100644 index 7be634c..0000000 --- a/pipeline/task.jsonparse.go +++ /dev/null @@ -1,106 +0,0 @@ -package pipeline - -import ( - "context" - "encoding/json" - "math/big" - "strings" - - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// float64 -// string -// bool -// map[string]interface{} -// []interface{} -// nil -type JSONParseTask struct { - BaseTask `mapstructure:",squash"` - Path string `json:"path"` - Data string `json:"data"` - // Lax when disabled will return an error if the path does not exist - // Lax when enabled will return nil with no error if the path does not exist - Lax string -} - -var _ Task = (*JSONParseTask)(nil) - -func (t *JSONParseTask) Type() TaskType { - return TaskTypeJSONParse -} - -func (t *JSONParseTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - path JSONPathParam - data StringParam - lax BoolParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&path, From(VarExpr(t.Path, vars), t.Path)), "path"), - errors.Wrap(ResolveParam(&data, From(VarExpr(t.Data, vars), Input(inputs, 0))), "data"), - errors.Wrap(ResolveParam(&lax, From(NonemptyString(t.Lax), false)), "lax"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - var decoded interface{} - err = json.Unmarshal([]byte(data), &decoded) - if err != nil { - return Result{Error: err}, runInfo - } - - for _, part := range path { - switch d := decoded.(type) { - case map[string]interface{}: - var exists bool - decoded, exists = d[part] - if !exists && bool(lax) { - decoded = nil - break - } else if !exists { - return Result{Error: errors.Wrapf(ErrKeypathNotFound, `could not resolve path ["%v"] in %s`, strings.Join(path, `","`), data)}, runInfo - } - - case []interface{}: - bigindex, ok := big.NewInt(0).SetString(part, 10) - if !ok { - return Result{Error: errors.Wrapf(ErrKeypathNotFound, "JSONParse task error: %v is not a valid array index", part)}, runInfo - } else if !bigindex.IsInt64() { - if bool(lax) { - decoded = nil - break - } - return Result{Error: errors.Wrapf(ErrKeypathNotFound, `could not resolve path ["%v"] in %s`, strings.Join(path, `","`), data)}, runInfo - } - index := int(bigindex.Int64()) - if index < 0 { - index = len(d) + index - } - - exists := index >= 0 && index < len(d) - if !exists && bool(lax) { - decoded = nil - break - } else if !exists { - return Result{Error: errors.Wrapf(ErrKeypathNotFound, `could not resolve path ["%v"] in %s`, strings.Join(path, `","`), data)}, runInfo - } - decoded = d[index] - - default: - return Result{Error: errors.Wrapf(ErrKeypathNotFound, `could not resolve path ["%v"] in %s`, strings.Join(path, `","`), data)}, runInfo - } - } - return Result{Value: decoded}, runInfo -} diff --git a/pipeline/task.lowercase.go b/pipeline/task.lowercase.go deleted file mode 100644 index ad57894..0000000 --- a/pipeline/task.lowercase.go +++ /dev/null @@ -1,42 +0,0 @@ -package pipeline - -import ( - "context" - "strings" - - log "github.com/InjectiveLabs/suplog" - "github.com/pkg/errors" - "go.uber.org/multierr" -) - -// Return types: -// -// string -type LowercaseTask struct { - BaseTask `mapstructure:",squash"` - Input string `json:"input"` -} - -var _ Task = (*LowercaseTask)(nil) - -func (t *LowercaseTask) Type() TaskType { - return TaskTypeLowercase -} - -func (t *LowercaseTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var input StringParam - - err = multierr.Combine( - errors.Wrap(ResolveParam(&input, From(VarExpr(t.Input, vars), Input(inputs, 0))), "input"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - return Result{Value: strings.ToLower(string(input))}, runInfo -} diff --git a/pipeline/task.mean.go b/pipeline/task.mean.go deleted file mode 100644 index 2ea961b..0000000 --- a/pipeline/task.mean.go +++ /dev/null @@ -1,78 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// *decimal.Decimal -type MeanTask struct { - BaseTask `mapstructure:",squash"` - Values string `json:"values"` - AllowedFaults string `json:"allowedFaults"` - Precision string `json:"precision"` -} - -var _ Task = (*MeanTask)(nil) - -func (t *MeanTask) Type() TaskType { - return TaskTypeMean -} - -func (t *MeanTask) Run(ctx context.Context, lggr log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - var ( - maybeAllowedFaults MaybeUint64Param - maybePrecision MaybeInt32Param - valuesAndErrs SliceParam - decimalValues DecimalSliceParam - allowedFaults int - faults int - ) - err := multierr.Combine( - errors.Wrap(ResolveParam(&maybeAllowedFaults, From(t.AllowedFaults)), "allowedFaults"), - errors.Wrap(ResolveParam(&maybePrecision, From(VarExpr(t.Precision, vars), t.Precision)), "precision"), - errors.Wrap(ResolveParam(&valuesAndErrs, From(VarExpr(t.Values, vars), JSONWithVarExprs(t.Values, vars, true), Inputs(inputs))), "values"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - if allowed, isSet := maybeAllowedFaults.Uint64(); isSet { - allowedFaults = int(allowed) - } else { - allowedFaults = len(valuesAndErrs) - 1 - } - - values, faults := valuesAndErrs.FilterErrors() - if faults > allowedFaults { - return Result{Error: errors.Wrapf(ErrTooManyErrors, "Number of faulty inputs %v to mean task > number allowed faults %v", faults, allowedFaults)}, runInfo - } else if len(values) == 0 { - return Result{Error: errors.Wrap(ErrWrongInputCardinality, "values")}, runInfo - } - - err = decimalValues.UnmarshalPipelineParam(values) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "values: %v", err)}, runInfo - } - - total := decimal.NewFromInt(0) - for _, val := range decimalValues { - total = total.Add(val) - } - - numValues := decimal.NewFromInt(int64(len(decimalValues))) - - if precision, isSet := maybePrecision.Int32(); isSet { - return Result{Value: total.DivRound(numValues, precision)}, runInfo - } - // Note that decimal library defaults to rounding to 16 precision - //https://github.com/shopspring/decimal/blob/2568a29459476f824f35433dfbef158d6ad8618c/decimal.go#L44 - return Result{Value: total.Div(numValues)}, runInfo -} diff --git a/pipeline/task.median.go b/pipeline/task.median.go deleted file mode 100644 index 5d36358..0000000 --- a/pipeline/task.median.go +++ /dev/null @@ -1,72 +0,0 @@ -package pipeline - -import ( - "context" - "sort" - - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// *decimal.Decimal -type MedianTask struct { - BaseTask `mapstructure:",squash"` - Values string `json:"values"` - AllowedFaults string `json:"allowedFaults"` -} - -var _ Task = (*MedianTask)(nil) - -func (t *MedianTask) Type() TaskType { - return TaskTypeMedian -} - -func (t *MedianTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - var ( - maybeAllowedFaults MaybeUint64Param - valuesAndErrs SliceParam - decimalValues DecimalSliceParam - allowedFaults int - faults int - ) - err := multierr.Combine( - errors.Wrap(ResolveParam(&maybeAllowedFaults, From(t.AllowedFaults)), "allowedFaults"), - errors.Wrap(ResolveParam(&valuesAndErrs, From(VarExpr(t.Values, vars), JSONWithVarExprs(t.Values, vars, true), Inputs(inputs))), "values"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - if allowed, isSet := maybeAllowedFaults.Uint64(); isSet { - allowedFaults = int(allowed) - } else { - allowedFaults = len(valuesAndErrs) - 1 - } - - values, faults := valuesAndErrs.FilterErrors() - if faults > allowedFaults { - return Result{Error: errors.Wrapf(ErrTooManyErrors, "Number of faulty inputs %v to median task > number allowed faults %v", faults, allowedFaults)}, runInfo - } else if len(values) == 0 { - return Result{Error: errors.Wrap(ErrWrongInputCardinality, "no values to medianize")}, runInfo - } - - err = decimalValues.UnmarshalPipelineParam(values) - if err != nil { - return Result{Error: err}, runInfo - } - - sort.Slice(decimalValues, func(i, j int) bool { - return decimalValues[i].LessThan(decimalValues[j]) - }) - k := len(decimalValues) / 2 - if len(decimalValues)%2 == 1 { - return Result{Value: decimalValues[k]}, runInfo - } - median := decimalValues[k].Add(decimalValues[k-1]).Div(decimal.NewFromInt(2)) - return Result{Value: median}, runInfo -} diff --git a/pipeline/task.memo.go b/pipeline/task.memo.go deleted file mode 100644 index 41a9ad9..0000000 --- a/pipeline/task.memo.go +++ /dev/null @@ -1,35 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - - log "github.com/InjectiveLabs/suplog" -) - -type MemoTask struct { - BaseTask `mapstructure:",squash"` - Value string `json:"value"` -} - -var _ Task = (*MemoTask)(nil) - -func (t *MemoTask) Type() TaskType { - return TaskTypeMemo -} - -func (t *MemoTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (Result, RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task value missing")}, RunInfo{} - } - - var value ObjectParam - err = errors.Wrap(ResolveParam(&value, From(JSONWithVarExprs(t.Value, vars, false), Input(inputs, 0))), "value") - if err != nil { - return Result{Error: err}, RunInfo{} - } - - return Result{Value: value}, RunInfo{} -} diff --git a/pipeline/task.merge.go b/pipeline/task.merge.go deleted file mode 100644 index fac2c07..0000000 --- a/pipeline/task.merge.go +++ /dev/null @@ -1,52 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// map[string]interface{} -type MergeTask struct { - BaseTask `mapstructure:",squash"` - Left string `json:"left"` - Right string `json:"right"` -} - -var _ Task = (*MergeTask)(nil) - -func (t *MergeTask) Type() TaskType { - return TaskTypeMerge -} - -func (t *MergeTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - lMap MapParam - rMap MapParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&lMap, From(VarExpr(t.Left, vars), NonemptyString(t.Left), Input(inputs, 0))), "left-side"), - errors.Wrap(ResolveParam(&rMap, From(VarExpr(t.Right, vars), NonemptyString(t.Right))), "right-side"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - // clobber lMap with rMap values - // "nil" values on the right will clobber - for key, value := range rMap { - lMap[key] = value - } - - return Result{Value: lMap.Map()}, runInfo -} diff --git a/pipeline/task.mode.go b/pipeline/task.mode.go deleted file mode 100644 index 05382a1..0000000 --- a/pipeline/task.mode.go +++ /dev/null @@ -1,112 +0,0 @@ -package pipeline - -import ( - "context" - "encoding/json" - "fmt" - "math/big" - - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// map[string]interface{}{ -// "results": []interface{} containing any other type other pipeline tasks can return -// "occurrences": (int64) -// } -type ModeTask struct { - BaseTask `mapstructure:",squash"` - Values string `json:"values"` - AllowedFaults string `json:"allowedFaults"` -} - -var _ Task = (*ModeTask)(nil) - -func (t *ModeTask) Type() TaskType { - return TaskTypeMode -} - -func (t *ModeTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - var ( - maybeAllowedFaults MaybeUint64Param - valuesAndErrs SliceParam - allowedFaults int - faults int - ) - err := multierr.Combine( - errors.Wrap(ResolveParam(&maybeAllowedFaults, From(t.AllowedFaults)), "allowedFaults"), - errors.Wrap(ResolveParam(&valuesAndErrs, From(VarExpr(t.Values, vars), JSONWithVarExprs(t.Values, vars, true), Inputs(inputs))), "values"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - if allowed, isSet := maybeAllowedFaults.Uint64(); isSet { - allowedFaults = int(allowed) - } else { - allowedFaults = len(valuesAndErrs) - 1 - } - - values, faults := valuesAndErrs.FilterErrors() - if faults > allowedFaults { - return Result{Error: errors.Wrapf(ErrTooManyErrors, "Number of faulty inputs %v to mode task > number allowed faults %v", faults, allowedFaults)}, runInfo - } else if len(values) == 0 { - return Result{Error: errors.Wrap(ErrWrongInputCardinality, "values")}, runInfo - } - - type entry struct { - count uint64 - original interface{} - } - - var ( - m = make(map[string]entry, len(values)) - max uint64 - modes []interface{} - ) - for _, val := range values { - var comparable string - switch v := val.(type) { - case []byte: - comparable = string(v) - case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float64, float32, - string, bool: - comparable = fmt.Sprintf("%v", v) - case *big.Int: - comparable = v.String() - case big.Int: - comparable = v.String() - case *decimal.Decimal: - comparable = v.String() - case decimal.Decimal: - comparable = v.String() - default: - bs, err := json.Marshal(v) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "could not json stringify value: %v", err)}, runInfo - } - comparable = string(bs) - } - - m[comparable] = entry{ - count: m[comparable].count + 1, - original: val, - } - - if m[comparable].count > max { - modes = []interface{}{val} - max = m[comparable].count - } else if m[comparable].count == max { - modes = append(modes, val) - } - } - return Result{Value: map[string]interface{}{ - "results": modes, - "occurrences": max, - }}, runInfo -} diff --git a/pipeline/task.multiply.go b/pipeline/task.multiply.go deleted file mode 100644 index c8d3fc7..0000000 --- a/pipeline/task.multiply.go +++ /dev/null @@ -1,47 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// *decimal.Decimal -type MultiplyTask struct { - BaseTask `mapstructure:",squash"` - Input string `json:"input"` - Times string `json:"times"` -} - -var _ Task = (*MultiplyTask)(nil) - -func (t *MultiplyTask) Type() TaskType { - return TaskTypeMultiply -} - -func (t *MultiplyTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var ( - a DecimalParam - b DecimalParam - ) - err = multierr.Combine( - errors.Wrap(ResolveParam(&a, From(VarExpr(t.Input, vars), Input(inputs, 0))), "input"), - errors.Wrap(ResolveParam(&b, From(VarExpr(t.Times, vars), NonemptyString(t.Times))), "times"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - value := a.Decimal().Mul(b.Decimal()) - return Result{Value: value}, runInfo -} diff --git a/pipeline/task.panic.go b/pipeline/task.panic.go deleted file mode 100644 index 99e4317..0000000 --- a/pipeline/task.panic.go +++ /dev/null @@ -1,22 +0,0 @@ -package pipeline - -import ( - "context" - - log "github.com/InjectiveLabs/suplog" -) - -type PanicTask struct { - BaseTask `mapstructure:",squash"` - Msg string -} - -var _ Task = (*PanicTask)(nil) - -func (t *PanicTask) Type() TaskType { - return TaskTypePanic -} - -func (t *PanicTask) Run(_ context.Context, _ log.Logger, vars Vars, _ []Result) (result Result, runInfo RunInfo) { - panic(t.Msg) -} diff --git a/pipeline/task.sum.go b/pipeline/task.sum.go deleted file mode 100644 index 94fe928..0000000 --- a/pipeline/task.sum.go +++ /dev/null @@ -1,67 +0,0 @@ -package pipeline - -import ( - "context" - - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "go.uber.org/multierr" - - log "github.com/InjectiveLabs/suplog" -) - -// Return types: -// -// *decimal.Decimal -type SumTask struct { - BaseTask `mapstructure:",squash"` - Values string `json:"values"` - AllowedFaults string `json:"allowedFaults"` -} - -var _ Task = (*SumTask)(nil) - -func (t *SumTask) Type() TaskType { - return TaskTypeSum -} - -func (t *SumTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - var ( - maybeAllowedFaults MaybeUint64Param - valuesAndErrs SliceParam - decimalValues DecimalSliceParam - allowedFaults int - faults int - ) - err := multierr.Combine( - errors.Wrap(ResolveParam(&maybeAllowedFaults, From(t.AllowedFaults)), "allowedFaults"), - errors.Wrap(ResolveParam(&valuesAndErrs, From(VarExpr(t.Values, vars), JSONWithVarExprs(t.Values, vars, true), Inputs(inputs))), "values"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - if allowed, isSet := maybeAllowedFaults.Uint64(); isSet { - allowedFaults = int(allowed) - } else { - allowedFaults = len(valuesAndErrs) - 1 - } - - values, faults := valuesAndErrs.FilterErrors() - if faults > allowedFaults { - return Result{Error: errors.Wrapf(ErrTooManyErrors, "Number of faulty inputs %v to sum task > number allowed faults %v", faults, allowedFaults)}, runInfo - } else if len(values) == 0 { - return Result{Error: errors.Wrap(ErrWrongInputCardinality, "values")}, runInfo - } - - err = decimalValues.UnmarshalPipelineParam(values) - if err != nil { - return Result{Error: errors.Wrapf(ErrBadInput, "values: %v", err)}, runInfo - } - - sum := decimal.NewFromInt(0) - for _, val := range decimalValues { - sum = sum.Add(val) - } - return Result{Value: sum}, runInfo -} diff --git a/pipeline/task.uppercase.go b/pipeline/task.uppercase.go deleted file mode 100644 index dbb18b6..0000000 --- a/pipeline/task.uppercase.go +++ /dev/null @@ -1,42 +0,0 @@ -package pipeline - -import ( - "context" - "strings" - - log "github.com/InjectiveLabs/suplog" - "github.com/pkg/errors" - "go.uber.org/multierr" -) - -// Return types: -// -// string -type UppercaseTask struct { - BaseTask `mapstructure:",squash"` - Input string `json:"input"` -} - -var _ Task = (*UppercaseTask)(nil) - -func (t *UppercaseTask) Type() TaskType { - return TaskTypeUppercase -} - -func (t *UppercaseTask) Run(_ context.Context, _ log.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { - _, err := CheckInputs(inputs, 0, 1, 0) - if err != nil { - return Result{Error: errors.Wrap(err, "task inputs")}, runInfo - } - - var input StringParam - - err = multierr.Combine( - errors.Wrap(ResolveParam(&input, From(VarExpr(t.Input, vars), Input(inputs, 0))), "input"), - ) - if err != nil { - return Result{Error: err}, runInfo - } - - return Result{Value: strings.ToUpper(string(input))}, runInfo -} diff --git a/pipeline/task_object_params.go b/pipeline/task_object_params.go deleted file mode 100644 index ed4b4a0..0000000 --- a/pipeline/task_object_params.go +++ /dev/null @@ -1,140 +0,0 @@ -package pipeline - -import ( - "encoding/json" - "fmt" - "math/big" - - "github.com/shopspring/decimal" -) - -type ObjectType int - -const ( - NilType ObjectType = iota - BoolType - DecimalType - StringType - SliceType - MapType -) - -// ObjectParam represents a kind of any type that could be used by the -// memo task -type ObjectParam struct { - Type ObjectType - BoolValue BoolParam - DecimalValue DecimalParam - StringValue StringParam - SliceValue SliceParam - MapValue MapParam -} - -func (o ObjectParam) MarshalJSON() ([]byte, error) { - switch o.Type { - case NilType: - return json.Marshal(nil) - case BoolType: - return json.Marshal(o.BoolValue) - case DecimalType: - return json.Marshal(o.DecimalValue.Decimal()) - case StringType: - return json.Marshal(o.StringValue) - case MapType: - return json.Marshal(o.MapValue) - case SliceType: - return json.Marshal(o.SliceValue) - } - panic(fmt.Sprintf("Invalid type for ObjectParam %v", o.Type)) -} - -func (o ObjectParam) Marshal() (string, error) { - b, err := o.MarshalJSON() - if err != nil { - return "", err - } - return string(b), nil -} - -func (o ObjectParam) String() string { - value, err := o.Marshal() - if err != nil { - return fmt.Sprintf("", err) - } - return value -} - -func (o *ObjectParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case nil: - o.Type = NilType - return nil - - case bool: - o.Type = BoolType - o.BoolValue = BoolParam(v) - return nil - - case uint8, uint16, uint32, uint64, uint, int8, int16, int32, int64, int, float32, float64, decimal.Decimal, *decimal.Decimal, big.Int, *big.Int: - o.Type = DecimalType - return o.DecimalValue.UnmarshalPipelineParam(v) - - case string: - o.Type = StringType - return o.StringValue.UnmarshalPipelineParam(v) - - // Maps - case MapParam: - o.Type = MapType - o.MapValue = v - return nil - - case map[string]interface{}: - o.Type = MapType - return o.MapValue.UnmarshalPipelineParam(v) - - // Slices - case SliceParam: - o.Type = SliceType - o.SliceValue = v - return nil - - case []interface{}: - o.Type = SliceType - return o.SliceValue.UnmarshalPipelineParam(v) - - case []int: - o.Type = SliceType - for _, value := range v { - o.SliceValue = append(o.SliceValue, value) - } - return nil - - case []string: - o.Type = SliceType - for _, value := range v { - o.SliceValue = append(o.SliceValue, value) - } - return nil - - case ObjectParam: - o.Type = v.Type - o.BoolValue = v.BoolValue - o.MapValue = v.MapValue - o.StringValue = v.StringValue - o.DecimalValue = v.DecimalValue - return nil - - } - - return fmt.Errorf("bad input for task: %T", val) -} - -func MustNewObjectParam(val interface{}) *ObjectParam { - var value ObjectParam - err := value.UnmarshalPipelineParam(val) - if err != nil { - panic(fmt.Errorf("failed to init ObjectParam from %v, err: %w", val, err)) - } - return &value -} diff --git a/pipeline/task_params.go b/pipeline/task_params.go deleted file mode 100644 index fdc5509..0000000 --- a/pipeline/task_params.go +++ /dev/null @@ -1,843 +0,0 @@ -package pipeline - -import ( - "bytes" - "encoding/base64" - "encoding/hex" - "encoding/json" - "fmt" - "math" - "math/big" - "net/url" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - "github.com/shopspring/decimal" -) - -type PipelineParamUnmarshaler interface { - UnmarshalPipelineParam(val interface{}) error -} - -func ResolveParam(out PipelineParamUnmarshaler, getters []GetterFunc) error { - var val interface{} - var err error - var found bool - for _, get := range getters { - val, err = get() - if errors.Cause(err) == ErrParameterEmpty { - continue - } else if err != nil { - return err - } - found = true - break - } - if !found { - return ErrParameterEmpty - } - - err = out.UnmarshalPipelineParam(val) - if err != nil { - return err - } - return nil -} - -type GetterFunc func() (interface{}, error) - -func From(getters ...interface{}) []GetterFunc { - var gfs []GetterFunc - for _, g := range getters { - switch v := g.(type) { - case GetterFunc: - gfs = append(gfs, v) - - default: - // If a bare value is passed in, create a simple getter - gfs = append(gfs, func() (interface{}, error) { - return v, nil - }) - } - } - return gfs -} - -func VarExpr(s string, vars Vars) GetterFunc { - return func() (interface{}, error) { - trimmed := strings.TrimSpace(s) - if len(trimmed) == 0 { - return nil, ErrParameterEmpty - } - isVariableExpr := strings.Count(trimmed, "$") == 1 && trimmed[:2] == "$(" && trimmed[len(trimmed)-1] == ')' - if !isVariableExpr { - return nil, ErrParameterEmpty - } - keypath := strings.TrimSpace(trimmed[2 : len(trimmed)-1]) - val, err := vars.Get(keypath) - if err != nil { - return nil, err - } else if as, is := val.(error); is { - return nil, errors.Wrapf(ErrTooManyErrors, "VarExpr: %v", as) - } - return val, nil - } -} - -func JSONWithVarExprs(s string, vars Vars, allowErrors bool) GetterFunc { - return func() (interface{}, error) { - if strings.TrimSpace(s) == "" { - return nil, ErrParameterEmpty - } - replaced := variableRegexp.ReplaceAllFunc([]byte(s), func(expr []byte) []byte { - keypathStr := strings.TrimSpace(string(expr[2 : len(expr)-1])) - return []byte(fmt.Sprintf(`{ "__spec_var_expr__": "%v" }`, keypathStr)) - }) - var val interface{} - err := json.Unmarshal(replaced, &val) - if err != nil { - return nil, errors.Wrapf(ErrBadInput, "while interpolating variables in JSON payload: %v", err) - } - return mapGoValue(val, func(val interface{}) (interface{}, error) { - if m, is := val.(map[string]interface{}); is { - maybeKeypath, exists := m["__spec_var_expr__"] - if !exists { - return val, nil - } - keypath, is := maybeKeypath.(string) - if !is { - return nil, errors.New("you cannot use __spec_var_expr__ in your JSON") - } - newVal, err := vars.Get(keypath) - if err != nil { - return nil, err - } else if err, is := newVal.(error); is && !allowErrors { - return nil, errors.Wrapf(ErrBadInput, "JSONWithVarExprs: %v", err) - } - return newVal, nil - } - return val, nil - }) - } -} - -func mapGoValue(v interface{}, fn func(val interface{}) (interface{}, error)) (x interface{}, err error) { - type item struct { - val interface{} - parentMap map[string]interface{} - parentKey string - parentSlice []interface{} - parentIdx int - } - - stack := []item{{val: v}} - var current item - - for len(stack) > 0 { - current = stack[0] - stack = stack[1:] - - val, err := fn(current.val) - if err != nil { - return nil, err - } - - if current.parentMap != nil { - current.parentMap[current.parentKey] = val - } else if current.parentSlice != nil { - current.parentSlice[current.parentIdx] = val - } - - if asMap, isMap := val.(map[string]interface{}); isMap { - for key := range asMap { - stack = append(stack, item{val: asMap[key], parentMap: asMap, parentKey: key}) - } - } else if asSlice, isSlice := val.([]interface{}); isSlice { - for i := range asSlice { - stack = append(stack, item{val: asSlice[i], parentSlice: asSlice, parentIdx: i}) - } - } - } - return v, nil -} - -func NonemptyString(s string) GetterFunc { - return func() (interface{}, error) { - trimmed := strings.TrimSpace(s) - if len(trimmed) == 0 { - return nil, ErrParameterEmpty - } - return trimmed, nil - } -} - -func Input(inputs []Result, index int) GetterFunc { - return func() (interface{}, error) { - if len(inputs)-1 < index { - return nil, ErrParameterEmpty - } - return inputs[index].Value, inputs[index].Error - } -} - -func Inputs(inputs []Result) GetterFunc { - return func() (interface{}, error) { - var vals []interface{} - for _, input := range inputs { - if input.Error != nil { - vals = append(vals, input.Error) - } else { - vals = append(vals, input.Value) - } - } - return vals, nil - } -} - -type StringParam string - -func (s *StringParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case string: - *s = StringParam(v) - return nil - case []byte: - *s = StringParam(string(v)) - return nil - - case ObjectParam: - if v.Type == StringType { - *s = v.StringValue - return nil - } - - case *ObjectParam: - if v.Type == StringType { - *s = v.StringValue - return nil - } - - } - return errors.Wrapf(ErrBadInput, "expected string, got %T", val) -} - -type BytesParam []byte - -func (b *BytesParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case string: - if len(v) >= 2 && v[:2] == "0x" { - bs, err := hex.DecodeString(v[2:]) - if err != nil { - return err - } - *b = BytesParam(bs) - return nil - } - // try decoding as base64 first, in case this is a string from the database - bs, err := base64.StdEncoding.DecodeString(v) - if err != nil { - bs = []byte(v) - } - *b = BytesParam(bs) - case []byte: - *b = BytesParam(v) - case nil: - *b = BytesParam(nil) - default: - return errors.Wrapf(ErrBadInput, "expected array of bytes, got %T", val) - } - return nil -} - -type Uint64Param uint64 - -func (u *Uint64Param) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case uint: - *u = Uint64Param(v) - case uint8: - *u = Uint64Param(v) - case uint16: - *u = Uint64Param(v) - case uint32: - *u = Uint64Param(v) - case uint64: - *u = Uint64Param(v) - case int: - *u = Uint64Param(v) - case int8: - *u = Uint64Param(v) - case int16: - *u = Uint64Param(v) - case int32: - *u = Uint64Param(v) - case int64: - *u = Uint64Param(v) - case float64: // when decoding from db: JSON numbers are floats - *u = Uint64Param(v) - case string: - n, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - *u = Uint64Param(n) - default: - return errors.Wrapf(ErrBadInput, "expected unsiend integer, got %T", val) - } - return nil -} - -type MaybeUint64Param struct { - n uint64 - isSet bool -} - -func (p *MaybeUint64Param) UnmarshalPipelineParam(val interface{}) error { - var n uint64 - switch v := val.(type) { - case uint: - n = uint64(v) - case uint8: - n = uint64(v) - case uint16: - n = uint64(v) - case uint32: - n = uint64(v) - case uint64: - n = v - case int: - n = uint64(v) - case int8: - n = uint64(v) - case int16: - n = uint64(v) - case int32: - n = uint64(v) - case int64: - n = uint64(v) - case float64: // when decoding from db: JSON numbers are floats - n = uint64(v) - case string: - if strings.TrimSpace(v) == "" { - *p = MaybeUint64Param{0, false} - return nil - } - var err error - n, err = strconv.ParseUint(v, 10, 64) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - - default: - return errors.Wrapf(ErrBadInput, "expected unsigned integer or nil, got %T", val) - } - - *p = MaybeUint64Param{n, true} - return nil -} - -func (p MaybeUint64Param) Uint64() (uint64, bool) { - return p.n, p.isSet -} - -type MaybeInt32Param struct { - n int32 - isSet bool -} - -func (p *MaybeInt32Param) UnmarshalPipelineParam(val interface{}) error { - var n int32 - switch v := val.(type) { - case uint: - if v > math.MaxInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case uint8: - n = int32(v) - case uint16: - n = int32(v) - case uint32: - if v > math.MaxInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case uint64: - if v > math.MaxInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case int: - if v > math.MaxInt32 || v < math.MinInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case int8: - n = int32(v) - case int16: - n = int32(v) - case int32: - n = int32(v) - case int64: - if v > math.MaxInt32 || v < math.MinInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case float64: // when decoding from db: JSON numbers are floats - if v > math.MaxInt32 || v < math.MinInt32 { - return errors.Wrap(ErrBadInput, "overflows int32") - } - n = int32(v) - case string: - if strings.TrimSpace(v) == "" { - *p = MaybeInt32Param{0, false} - return nil - } - i, err := strconv.ParseInt(v, 10, 32) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - n = int32(i) - - default: - return errors.Wrapf(ErrBadInput, "expected signed integer or nil, got %T", val) - } - - *p = MaybeInt32Param{n, true} - return nil -} - -func (p MaybeInt32Param) Int32() (int32, bool) { - return p.n, p.isSet -} - -type BoolParam bool - -func (b *BoolParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case string: - theBool, err := strconv.ParseBool(v) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - *b = BoolParam(theBool) - return nil - case bool: - *b = BoolParam(v) - return nil - - case ObjectParam: - if v.Type == BoolType { - *b = v.BoolValue - return nil - } - - case *ObjectParam: - if v.Type == BoolType { - *b = v.BoolValue - return nil - } - - } - return errors.Wrapf(ErrBadInput, "expected true or false, got %T", val) -} - -type DecimalParam decimal.Decimal - -func (d *DecimalParam) UnmarshalPipelineParam(val interface{}) error { - if v, ok := val.(ObjectParam); ok && v.Type == DecimalType { - *d = v.DecimalValue - return nil - } else if v, ok := val.(*ObjectParam); ok && v.Type == DecimalType { - *d = v.DecimalValue - return nil - } - x, err := ToDecimal(val) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - *d = DecimalParam(x) - return nil -} - -func (d DecimalParam) Decimal() decimal.Decimal { - return decimal.Decimal(d) -} - -// ToDecimal converts an input to a decimal -func ToDecimal(input interface{}) (decimal.Decimal, error) { - switch v := input.(type) { - case string: - return decimal.NewFromString(v) - case int: - return decimal.New(int64(v), 0), nil - case int8: - return decimal.New(int64(v), 0), nil - case int16: - return decimal.New(int64(v), 0), nil - case int32: - return decimal.New(int64(v), 0), nil - case int64: - return decimal.New(v, 0), nil - case uint: - return decimal.New(int64(v), 0), nil - case uint8: - return decimal.New(int64(v), 0), nil - case uint16: - return decimal.New(int64(v), 0), nil - case uint32: - return decimal.New(int64(v), 0), nil - case uint64: - return decimal.New(int64(v), 0), nil - case float64: - return decimal.NewFromFloat(v), nil - case float32: - return decimal.NewFromFloat32(v), nil - case big.Int: - return decimal.NewFromBigInt(&v, 0), nil - case *big.Int: - return decimal.NewFromBigInt(v, 0), nil - case decimal.Decimal: - return v, nil - case *decimal.Decimal: - return *v, nil - default: - return decimal.Decimal{}, errors.Errorf("type %T cannot be converted to decimal.Decimal (%v)", input, input) - } -} - -type URLParam url.URL - -func (u *URLParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case string: - theURL, err := url.ParseRequestURI(v) - if err != nil { - return errors.Wrap(ErrBadInput, err.Error()) - } - *u = URLParam(*theURL) - return nil - default: - return ErrBadInput - } -} - -func (u *URLParam) String() string { - return (*url.URL)(u).String() -} - -type AddressParam common.Address - -func (a *AddressParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case string: - return a.UnmarshalPipelineParam([]byte(v)) - case []byte: - if bytes.Equal(v[:2], []byte("0x")) && len(v) == 42 { - *a = AddressParam(common.HexToAddress(string(v))) - return nil - } else if len(v) == 20 { - copy((*a)[:], v) - return nil - } - return ErrBadInput - case common.Address: - *a = AddressParam(v) - default: - return ErrBadInput - } - return nil -} - -// MapParam accepts maps or JSON-encoded strings -type MapParam map[string]interface{} - -func (m *MapParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case nil: - *m = nil - return nil - - case MapParam: - *m = v - return nil - - case map[string]interface{}: - *m = MapParam(v) - return nil - - case string: - return m.UnmarshalPipelineParam([]byte(v)) - - case []byte: - var theMap map[string]interface{} - err := json.Unmarshal(v, &theMap) - if err != nil { - return err - } - *m = MapParam(theMap) - return nil - - case ObjectParam: - if v.Type == MapType { - *m = v.MapValue - return nil - } - - case *ObjectParam: - if v.Type == MapType { - *m = v.MapValue - return nil - } - - } - - return errors.Wrapf(ErrBadInput, "expected map, got %T", val) -} - -func (m MapParam) Map() map[string]interface{} { - return (map[string]interface{})(m) -} - -type SliceParam []interface{} - -func (s *SliceParam) UnmarshalPipelineParam(val interface{}) error { - switch v := val.(type) { - case nil: - *s = nil - return nil - case []interface{}: - *s = v - return nil - case string: - return s.UnmarshalPipelineParam([]byte(v)) - - case []byte: - var theSlice []interface{} - err := json.Unmarshal(v, &theSlice) - if err != nil { - return err - } - *s = SliceParam(theSlice) - return nil - } - - return errors.Wrapf(ErrBadInput, "expected slice, got %T", val) -} - -func (s SliceParam) FilterErrors() (SliceParam, int) { - var s2 SliceParam - var errs int - for _, x := range s { - if _, is := x.(error); is { - errs++ - } else { - s2 = append(s2, x) - } - } - return s2, errs -} - -type DecimalSliceParam []decimal.Decimal - -func (s *DecimalSliceParam) UnmarshalPipelineParam(val interface{}) error { - var dsp DecimalSliceParam - switch v := val.(type) { - case nil: - dsp = nil - case []decimal.Decimal: - dsp = v - case []interface{}: - return s.UnmarshalPipelineParam(SliceParam(v)) - case SliceParam: - for _, x := range v { - var d DecimalParam - err := d.UnmarshalPipelineParam(x) - if err != nil { - return err - } - dsp = append(dsp, d.Decimal()) - } - case string: - return s.UnmarshalPipelineParam([]byte(v)) - - case []byte: - var theSlice []interface{} - err := json.Unmarshal(v, &theSlice) - if err != nil { - return err - } - return s.UnmarshalPipelineParam(SliceParam(theSlice)) - - default: - return errors.Wrapf(ErrBadInput, "expected number, got %T", val) - } - *s = dsp - return nil -} - -type HashSliceParam []common.Hash - -func (s *HashSliceParam) UnmarshalPipelineParam(val interface{}) error { - var dsp HashSliceParam - switch v := val.(type) { - case nil: - dsp = nil - case []common.Hash: - dsp = v - case string: - err := json.Unmarshal([]byte(v), &dsp) - if err != nil { - return err - } - case []byte: - err := json.Unmarshal(v, &dsp) - if err != nil { - return err - } - case []interface{}: - for _, h := range v { - if s, is := h.(string); is { - var hash common.Hash - err := hash.UnmarshalText([]byte(s)) - if err != nil { - return errors.Wrapf(ErrBadInput, "HashSliceParam: %v", err) - } - dsp = append(dsp, hash) - } else { - return errors.Wrap(ErrBadInput, "HashSliceParam") - } - } - default: - return errors.Wrap(ErrBadInput, "HashSliceParam") - } - *s = dsp - return nil -} - -type AddressSliceParam []common.Address - -func (s *AddressSliceParam) UnmarshalPipelineParam(val interface{}) error { - var asp AddressSliceParam - switch v := val.(type) { - case nil: - asp = nil - case []common.Address: - asp = v - case string: - err := json.Unmarshal([]byte(v), &asp) - if err != nil { - return errors.Wrapf(ErrBadInput, "AddressSliceParam: %v", err) - } - case []byte: - err := json.Unmarshal(v, &asp) - if err != nil { - return errors.Wrapf(ErrBadInput, "AddressSliceParam: %v", err) - } - case []interface{}: - for _, a := range v { - var addr AddressParam - err := addr.UnmarshalPipelineParam(a) - if err != nil { - return errors.Wrapf(ErrBadInput, "AddressSliceParam: %v", err) - } - asp = append(asp, common.Address(addr)) - } - default: - return errors.Wrapf(ErrBadInput, "AddressSliceParam: cannot convert %T", val) - } - *s = asp - return nil -} - -type JSONPathParam []string - -func (p *JSONPathParam) UnmarshalPipelineParam(val interface{}) error { - var ssp JSONPathParam - switch v := val.(type) { - case nil: - ssp = nil - case []string: - ssp = v - case []interface{}: - for _, x := range v { - if as, is := x.(string); is { - ssp = append(ssp, as) - } else { - return ErrBadInput - } - } - case string: - if len(v) == 0 { - return nil - } - ssp = strings.Split(v, ",") - case []byte: - if len(v) == 0 { - return nil - } - ssp = strings.Split(string(v), ",") - default: - return ErrBadInput - } - *p = ssp - return nil -} - -type MaybeBigIntParam struct { - n *big.Int -} - -func (p *MaybeBigIntParam) UnmarshalPipelineParam(val interface{}) error { - var n *big.Int - switch v := val.(type) { - case uint: - n = big.NewInt(0).SetUint64(uint64(v)) - case uint8: - n = big.NewInt(0).SetUint64(uint64(v)) - case uint16: - n = big.NewInt(0).SetUint64(uint64(v)) - case uint32: - n = big.NewInt(0).SetUint64(uint64(v)) - case uint64: - n = big.NewInt(0).SetUint64(v) - case int: - n = big.NewInt(int64(v)) - case int8: - n = big.NewInt(int64(v)) - case int16: - n = big.NewInt(int64(v)) - case int32: - n = big.NewInt(int64(v)) - case int64: - n = big.NewInt(int64(v)) - case float64: // when decoding from db: JSON numbers are floats - n = big.NewInt(0).SetUint64(uint64(v)) - case string: - if strings.TrimSpace(v) == "" { - *p = MaybeBigIntParam{n: nil} - return nil - } - var ok bool - n, ok = big.NewInt(0).SetString(v, 10) - if !ok { - return errors.Wrapf(ErrBadInput, "unable to convert %s to big.Int", v) - } - case *big.Int: - n = v - case nil: - *p = MaybeBigIntParam{n: nil} - return nil - default: - return ErrBadInput - } - *p = MaybeBigIntParam{n: n} - return nil -} - -func (p MaybeBigIntParam) BigInt() *big.Int { - return p.n -} diff --git a/pipeline/variables.go b/pipeline/variables.go deleted file mode 100644 index 33418b0..0000000 --- a/pipeline/variables.go +++ /dev/null @@ -1,142 +0,0 @@ -package pipeline - -import ( - "bytes" - "regexp" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -var ( - ErrKeypathNotFound = errors.New("keypath not found") - ErrKeypathTooDeep = errors.New("keypath too deep (maximum 2 keys)") - ErrVarsRoot = errors.New("cannot get/set the root of a pipeline.Vars") - - variableRegexp = regexp.MustCompile(`\$\(\s*([a-zA-Z0-9_\.]+)\s*\)`) -) - -type Vars struct { - vars map[string]interface{} -} - -func NewVarsFrom(m map[string]interface{}) Vars { - if m == nil { - m = make(map[string]interface{}) - } - return Vars{vars: m} -} - -func (vars Vars) Copy() Vars { - m := make(map[string]interface{}) - for k, v := range vars.vars { - m[k] = v - } - return Vars{vars: m} -} - -func (vars Vars) Get(keypathStr string) (interface{}, error) { - keypath, err := newKeypathFromString(keypathStr) - if err != nil { - return nil, err - } - - numParts := keypath.NumParts() - - if numParts == 0 { - return nil, ErrVarsRoot - } - - var val interface{} - var exists bool - - if numParts >= 1 { - val, exists = vars.vars[string(keypath[0])] - if !exists { - return nil, errors.Wrapf(ErrKeypathNotFound, "key %v / keypath %v", string(keypath[0]), keypath.String()) - } - } - - if numParts == 2 { - switch v := val.(type) { - case map[string]interface{}: - val, exists = v[string(keypath[1])] - if !exists { - return nil, errors.Wrapf(ErrKeypathNotFound, "key %v / keypath %v", string(keypath[1]), keypath.String()) - } - case []interface{}: - idx, err := strconv.ParseInt(string(keypath[1]), 10, 64) - if err != nil { - return nil, errors.Wrapf(ErrKeypathNotFound, "could not parse key as integer: %v", err) - } else if idx > int64(len(v)-1) { - return nil, errors.Wrapf(ErrKeypathNotFound, "index %v out of range (length %v / keypath %v)", idx, len(v), keypath.String()) - } - val = v[idx] - default: - return nil, errors.Wrapf(ErrKeypathNotFound, "value at key '%v' is a %T, not a map or slice", string(keypath[0]), val) - } - } - - return val, nil -} - -func (vars Vars) Set(dotID string, value interface{}) { - dotID = strings.TrimSpace(dotID) - if len(dotID) == 0 { - panic(ErrVarsRoot) - } else if strings.IndexByte(dotID, keypathSeparator[0]) >= 0 { - panic("cannot set a nested key of a pipeline.Vars") - } - vars.vars[dotID] = value -} - -type Keypath [2][]byte - -var keypathSeparator = []byte(".") - -func newKeypathFromString(keypathStr string) (Keypath, error) { - if len(keypathStr) == 0 { - return Keypath{}, nil - } - // The bytes package uses platform-dependent hardware optimizations and - // avoids the extra allocations that are required to work with strings. - // Keypaths have to be parsed quite a bit, so let's do it well. - kp := []byte(keypathStr) - - n := 1 + bytes.Count(kp, keypathSeparator) - if n > 2 { - return Keypath{}, errors.Wrapf(ErrKeypathTooDeep, "while parsing keypath '%v'", keypathStr) - } - idx := bytes.IndexByte(kp, keypathSeparator[0]) - if idx == -1 || idx == len(kp)-1 { - return Keypath{kp, nil}, nil - } - return Keypath{kp[:idx], kp[idx+1:]}, nil -} - -func (keypath Keypath) NumParts() int { - switch { - case keypath[0] == nil && keypath[1] == nil: - return 0 - case keypath[0] != nil && keypath[1] == nil: - return 1 - case keypath[0] == nil && keypath[1] != nil: - panic("invariant violation: keypath part 1 is non-nil but part 0 is nil") - default: - return 2 - } -} - -func (keypath Keypath) String() string { - switch keypath.NumParts() { - case 0: - return "(empty)" - case 1: - return string(keypath[0]) - case 2: - return string(keypath[0]) + string(keypathSeparator) + string(keypath[1]) - default: - panic("invariant violation: keypath must have 0, 1, or 2 parts") - } -} diff --git a/swagger/favicon-16x16.png b/swagger/favicon-16x16.png deleted file mode 100644 index 8b194e6..0000000 Binary files a/swagger/favicon-16x16.png and /dev/null differ diff --git a/swagger/favicon-32x32.png b/swagger/favicon-32x32.png deleted file mode 100644 index 249737f..0000000 Binary files a/swagger/favicon-32x32.png and /dev/null differ diff --git a/swagger/index.html b/swagger/index.html deleted file mode 100644 index 9989f1f..0000000 --- a/swagger/index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - Swagger UI - - - - - - - -
- - - - - - - \ No newline at end of file diff --git a/swagger/oauth2-redirect.html b/swagger/oauth2-redirect.html deleted file mode 100644 index 64b171f..0000000 --- a/swagger/oauth2-redirect.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - Swagger UI: OAuth2 Redirect - - - - - diff --git a/swagger/swagger-ui-bundle.js b/swagger/swagger-ui-bundle.js deleted file mode 100644 index 56af1c9..0000000 --- a/swagger/swagger-ui-bundle.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=543)}([function(e,t,n){"use strict";e.exports=n(132)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return i(e)?e:J(e)}function r(e){return s(e)?e:K(e)}function o(e){return u(e)?e:Y(e)}function a(e){return i(e)&&!c(e)?e:G(e)}function i(e){return!(!e||!e[p])}function s(e){return!(!e||!e[f])}function u(e){return!(!e||!e[h])}function c(e){return s(e)||u(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(a,n),n.isIterable=i,n.isKeyed=s,n.isIndexed=u,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=a;var p="@@__IMMUTABLE_ITERABLE__@@",f="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m="delete",v=5,g=1<>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?A(e)+t:t}function O(){return!0}function j(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function I(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var N=0,M=1,R=2,D="function"==typeof Symbol&&Symbol.iterator,L="@@iterator",B=D||L;function F(e){this.next=e}function U(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function q(){return{value:void 0,done:!0}}function z(e){return!!H(e)}function V(e){return e&&"function"==typeof e.next}function W(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(D&&e[D]||e[L]);if("function"==typeof t)return t}function $(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():i(e)?e.toSeq():ce(e)}function K(e){return null==e?ie().toKeyedSeq():i(e)?s(e)?e.toSeq():e.fromEntrySeq():se(e)}function Y(e){return null==e?ie():i(e)?s(e)?e.entrySeq():e.toIndexedSeq():ue(e)}function G(e){return(null==e?ie():i(e)?s(e)?e.entrySeq():e:ue(e)).toSetSeq()}F.prototype.toString=function(){return"[Iterator]"},F.KEYS=N,F.VALUES=M,F.ENTRIES=R,F.prototype.inspect=F.prototype.toSource=function(){return this.toString()},F.prototype[B]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return pe(this,e,t,!0)},J.prototype.__iterator=function(e,t){return fe(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return pe(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return fe(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=ae,J.Keyed=K,J.Set=G,J.Indexed=Y;var Z,X,Q,ee="@@__IMMUTABLE_SEQ__@@";function te(e){this._array=e,this.size=e.length}function ne(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function re(e){this._iterable=e,this.size=e.length||e.size}function oe(e){this._iterator=e,this._iteratorCache=[]}function ae(e){return!(!e||!e[ee])}function ie(){return Z||(Z=new te([]))}function se(e){var t=Array.isArray(e)?new te(e).fromEntrySeq():V(e)?new oe(e).fromEntrySeq():z(e)?new re(e).fromEntrySeq():"object"==typeof e?new ne(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function ue(e){var t=le(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function ce(e){var t=le(e)||"object"==typeof e&&new ne(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function le(e){return $(e)?new te(e):V(e)?new oe(e):z(e)?new re(e):void 0}function pe(e,t,n,r){var o=e._cache;if(o){for(var a=o.length-1,i=0;i<=a;i++){var s=o[n?a-i:i];if(!1===t(s[1],r?s[0]:i,e))return i+1}return i}return e.__iterateUncached(t,n)}function fe(e,t,n,r){var o=e._cache;if(o){var a=o.length-1,i=0;return new F((function(){var e=o[n?a-i:i];return i++>a?q():U(t,r?e[0]:i-1,e[1])}))}return e.__iteratorUncached(t,n)}function he(e,t){return t?de(t,e,"",{"":e}):me(e)}function de(e,t,n,r){return Array.isArray(t)?e.call(r,n,Y(t).map((function(n,r){return de(e,n,r,t)}))):ve(t)?e.call(r,n,K(t).map((function(n,r){return de(e,n,r,t)}))):t}function me(e){return Array.isArray(e)?Y(e).map(me).toList():ve(e)?K(e).map(me).toMap():e}function ve(e){return e&&(e.constructor===Object||void 0===e.constructor)}function ge(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function ye(e,t){if(e===t)return!0;if(!i(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||s(e)!==s(t)||u(e)!==u(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!c(e);if(l(e)){var r=e.entries();return t.every((function(e,t){var o=r.next().value;return o&&ge(o[1],e)&&(n||ge(o[0],t))}))&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var a=e;e=t,t=a}var p=!0,f=t.__iterate((function(t,r){if(n?!e.has(t):o?!ge(t,e.get(r,b)):!ge(e.get(r,b),t))return p=!1,!1}));return p&&e.size===f}function be(e,t){if(!(this instanceof be))return new be(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(X)return X;X=this}}function _e(e,t){if(!e)throw new Error(t)}function we(e,t,n){if(!(this instanceof we))return new we(e,t,n);if(_e(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?q():U(e,o,n[t?r-o++:o++])}))},t(ne,K),ne.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},ne.prototype.has=function(e){return this._object.hasOwnProperty(e)},ne.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,a=0;a<=o;a++){var i=r[t?o-a:a];if(!1===e(n[i],i,this))return a+1}return a},ne.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,a=0;return new F((function(){var i=r[t?o-a:a];return a++>o?q():U(e,i,n[i])}))},ne.prototype[d]=!0,t(re,Y),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=W(this._iterable),r=0;if(V(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},re.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=W(this._iterable);if(!V(n))return new F(q);var r=0;return new F((function(){var t=n.next();return t.done?t:U(e,r++,t.value)}))},t(oe,Y),oe.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,a=0;a=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return U(e,o,r[o++])}))},t(be,Y),be.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},be.prototype.get=function(e,t){return this.has(e)?this._value:t},be.prototype.includes=function(e){return ge(this._value,e)},be.prototype.slice=function(e,t){var n=this.size;return j(e,t,n)?this:new be(this._value,I(t,n)-T(e,n))},be.prototype.reverse=function(){return this},be.prototype.indexOf=function(e){return ge(this._value,e)?0:-1},be.prototype.lastIndexOf=function(e){return ge(this._value,e)?this.size:-1},be.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?q():U(e,a++,i)}))},we.prototype.equals=function(e){return e instanceof we?this._start===e._start&&this._end===e._end&&this._step===e._step:ye(this,e)},t(xe,n),t(Ee,xe),t(Se,xe),t(Ce,xe),xe.Keyed=Ee,xe.Indexed=Se,xe.Set=Ce;var Ae="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function ke(e){return e>>>1&1073741824|3221225471&e}function Oe(e){if(!1===e||null==e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null==e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return ke(n)}if("string"===t)return e.length>Fe?je(e):Te(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return Ie(e);if("function"==typeof e.toString)return Te(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function je(e){var t=ze[e];return void 0===t&&(t=Te(e),qe===Ue&&(qe=0,ze={}),qe++,ze[e]=t),t}function Te(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}var Re,De="function"==typeof WeakMap;De&&(Re=new WeakMap);var Le=0,Be="__immutablehash__";"function"==typeof Symbol&&(Be=Symbol(Be));var Fe=16,Ue=255,qe=0,ze={};function Ve(e){_e(e!==1/0,"Cannot perform this action with an infinite size.")}function We(e){return null==e?ot():He(e)&&!l(e)?e:ot().withMutations((function(t){var n=r(e);Ve(n.size),n.forEach((function(e,n){return t.set(n,e)}))}))}function He(e){return!(!e||!e[Je])}t(We,Ee),We.of=function(){var t=e.call(arguments,0);return ot().withMutations((function(e){for(var n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}}))},We.prototype.toString=function(){return this.__toString("Map {","}")},We.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},We.prototype.set=function(e,t){return at(this,e,t)},We.prototype.setIn=function(e,t){return this.updateIn(e,b,(function(){return t}))},We.prototype.remove=function(e){return at(this,e,b)},We.prototype.deleteIn=function(e){return this.updateIn(e,(function(){return b}))},We.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},We.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=vt(this,xn(e),t,n);return r===b?void 0:r},We.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):ot()},We.prototype.merge=function(){return ft(this,void 0,arguments)},We.prototype.mergeWith=function(t){return ft(this,t,e.call(arguments,1))},We.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]}))},We.prototype.mergeDeep=function(){return ft(this,ht,arguments)},We.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return ft(this,dt(t),n)},We.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]}))},We.prototype.sort=function(e){return zt(pn(this,e))},We.prototype.sortBy=function(e,t){return zt(pn(this,t,e))},We.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},We.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new S)},We.prototype.asImmutable=function(){return this.__ensureOwner()},We.prototype.wasAltered=function(){return this.__altered},We.prototype.__iterator=function(e,t){return new et(this,e,t)},We.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate((function(t){return r++,e(t[1],t[0],n)}),t),r},We.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?rt(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},We.isMap=He;var $e,Je="@@__IMMUTABLE_MAP__@@",Ke=We.prototype;function Ye(e,t){this.ownerID=e,this.entries=t}function Ge(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function Ze(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Xe(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Qe(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function et(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&nt(e._root)}function tt(e,t){return U(e,t[0],t[1])}function nt(e,t){return{node:e,index:0,__prev:t}}function rt(e,t,n,r){var o=Object.create(Ke);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function ot(){return $e||($e=rt(0))}function at(e,t,n){var r,o;if(e._root){var a=x(_),i=x(w);if(r=it(e._root,e.__ownerID,0,void 0,t,n,a,i),!i.value)return e;o=e.size+(a.value?n===b?-1:1:0)}else{if(n===b)return e;o=1,r=new Ye(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?rt(o,r):ot()}function it(e,t,n,r,o,a,i,s){return e?e.update(t,n,r,o,a,i,s):a===b?e:(E(s),E(i),new Qe(t,r,[o,a]))}function st(e){return e.constructor===Qe||e.constructor===Xe}function ut(e,t,n,r,o){if(e.keyHash===r)return new Xe(t,r,[e.entry,o]);var a,i=(0===n?e.keyHash:e.keyHash>>>n)&y,s=(0===n?r:r>>>n)&y;return new Ge(t,1<>>=1)i[s]=1&n?t[a++]:void 0;return i[r]=o,new Ze(e,a+1,i)}function ft(e,t,n){for(var o=[],a=0;a>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function yt(e,t,n,r){var o=r?e:C(e);return o[t]=n,o}function bt(e,t,n,r){var o=e.length+1;if(r&&t+1===o)return e[t]=n,e;for(var a=new Array(o),i=0,s=0;s=wt)return ct(e,u,r,o);var f=e&&e===this.ownerID,h=f?u:C(u);return p?s?c===l-1?h.pop():h[c]=h.pop():h[c]=[r,o]:h.push([r,o]),f?(this.entries=h,this):new Ye(e,h)}},Ge.prototype.get=function(e,t,n,r){void 0===t&&(t=Oe(n));var o=1<<((0===e?t:t>>>e)&y),a=this.bitmap;return 0==(a&o)?r:this.nodes[gt(a&o-1)].get(e+v,t,n,r)},Ge.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=Oe(r));var s=(0===t?n:n>>>t)&y,u=1<=xt)return pt(e,f,c,s,d);if(l&&!d&&2===f.length&&st(f[1^p]))return f[1^p];if(l&&d&&1===f.length&&st(d))return d;var m=e&&e===this.ownerID,g=l?d?c:c^u:c|u,_=l?d?yt(f,p,d,m):_t(f,p,m):bt(f,p,d,m);return m?(this.bitmap=g,this.nodes=_,this):new Ge(e,g,_)},Ze.prototype.get=function(e,t,n,r){void 0===t&&(t=Oe(n));var o=(0===e?t:t>>>e)&y,a=this.nodes[o];return a?a.get(e+v,t,n,r):r},Ze.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=Oe(r));var s=(0===t?n:n>>>t)&y,u=o===b,c=this.nodes,l=c[s];if(u&&!l)return this;var p=it(l,e,t+v,n,r,o,a,i);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&r=0&&e>>t&y;if(r>=this.array.length)return new Ot([],e);var o,a=0===r;if(t>0){var i=this.array[r];if((o=i&&i.removeBefore(e,t-v,n))===i&&a)return this}if(a&&!o)return this;var s=Lt(this,e);if(!a)for(var u=0;u>>t&y;if(o>=this.array.length)return this;if(t>0){var a=this.array[o];if((r=a&&a.removeAfter(e,t-v,n))===a&&o===this.array.length-1)return this}var i=Lt(this,e);return i.array.splice(o+1),r&&(i.array[o]=r),i};var jt,Tt,It={};function Pt(e,t){var n=e._origin,r=e._capacity,o=qt(r),a=e._tail;return i(e._root,e._level,0);function i(e,t,n){return 0===t?s(e,n):u(e,t,n)}function s(e,i){var s=i===o?a&&a.array:e&&e.array,u=i>n?0:n-i,c=r-i;return c>g&&(c=g),function(){if(u===c)return It;var e=t?--c:u++;return s&&s[e]}}function u(e,o,a){var s,u=e&&e.array,c=a>n?0:n-a>>o,l=1+(r-a>>o);return l>g&&(l=g),function(){for(;;){if(s){var e=s();if(e!==It)return e;s=null}if(c===l)return It;var n=t?--l:c++;s=i(u&&u[n],o-v,a+(n<=e.size||t<0)return e.withMutations((function(e){t<0?Ft(e,t).set(0,n):Ft(e,0,t+1).set(t,n)}));t+=e._origin;var r=e._tail,o=e._root,a=x(w);return t>=qt(e._capacity)?r=Dt(r,e.__ownerID,0,t,n,a):o=Dt(o,e.__ownerID,e._level,t,n,a),a.value?e.__ownerID?(e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e):Nt(e._origin,e._capacity,e._level,o,r):e}function Dt(e,t,n,r,o,a){var i,s=r>>>n&y,u=e&&s0){var c=e&&e.array[s],l=Dt(c,t,n-v,r,o,a);return l===c?e:((i=Lt(e,t)).array[s]=l,i)}return u&&e.array[s]===o?e:(E(a),i=Lt(e,t),void 0===o&&s===i.array.length-1?i.array.pop():i.array[s]=o,i)}function Lt(e,t){return t&&e&&t===e.ownerID?e:new Ot(e?e.array.slice():[],t)}function Bt(e,t){if(t>=qt(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&y],r-=v;return n}}function Ft(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new S,o=e._origin,a=e._capacity,i=o+t,s=void 0===n?a:n<0?a+n:o+n;if(i===o&&s===a)return e;if(i>=s)return e.clear();for(var u=e._level,c=e._root,l=0;i+l<0;)c=new Ot(c&&c.array.length?[void 0,c]:[],r),l+=1<<(u+=v);l&&(i+=l,o+=l,s+=l,a+=l);for(var p=qt(a),f=qt(s);f>=1<p?new Ot([],r):h;if(h&&f>p&&iv;g-=v){var b=p>>>g&y;m=m.array[b]=Lt(m.array[b],r)}m.array[p>>>v&y]=h}if(s=f)i-=f,s-=f,u=v,c=null,d=d&&d.removeBefore(r,0,i);else if(i>o||f>>u&y;if(_!==f>>>u&y)break;_&&(l+=(1<o&&(c=c.removeBefore(r,u,i-l)),c&&fa&&(a=c.size),i(u)||(c=c.map((function(e){return he(e)}))),r.push(c)}return a>e.size&&(e=e.setSize(a)),mt(e,t,r)}function qt(e){return e>>v<=g&&i.size>=2*a.size?(r=(o=i.filter((function(e,t){return void 0!==e&&s!==t}))).toKeyedSeq().map((function(e){return e[0]})).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=a.remove(t),o=s===i.size-1?i.pop():i.set(s,void 0))}else if(u){if(n===i.get(s)[1])return e;r=a,o=i.set(s,[t,n])}else r=a.set(t,i.size),o=i.set(i.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Wt(r,o)}function Jt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Kt(e){this._iter=e,this.size=e.size}function Yt(e){this._iter=e,this.size=e.size}function Gt(e){this._iter=e,this.size=e.size}function Zt(e){var t=bn(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=_n,t.__iterateUncached=function(t,n){var r=this;return e.__iterate((function(e,n){return!1!==t(n,e,r)}),n)},t.__iteratorUncached=function(t,n){if(t===R){var r=e.__iterator(t,n);return new F((function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e}))}return e.__iterator(t===M?N:M,n)},t}function Xt(e,t,n){var r=bn(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var a=e.get(r,b);return a===b?o:t.call(n,a,r,e)},r.__iterateUncached=function(r,o){var a=this;return e.__iterate((function(e,o,i){return!1!==r(t.call(n,e,o,i),o,a)}),o)},r.__iteratorUncached=function(r,o){var a=e.__iterator(R,o);return new F((function(){var o=a.next();if(o.done)return o;var i=o.value,s=i[0];return U(r,s,t.call(n,i[1],s,e),o)}))},r}function Qt(e,t){var n=bn(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Zt(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=_n,n.__iterate=function(t,n){var r=this;return e.__iterate((function(e,n){return t(e,n,r)}),!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function en(e,t,n,r){var o=bn(e);return r&&(o.has=function(r){var o=e.get(r,b);return o!==b&&!!t.call(n,o,r,e)},o.get=function(r,o){var a=e.get(r,b);return a!==b&&t.call(n,a,r,e)?a:o}),o.__iterateUncached=function(o,a){var i=this,s=0;return e.__iterate((function(e,a,u){if(t.call(n,e,a,u))return s++,o(e,r?a:s-1,i)}),a),s},o.__iteratorUncached=function(o,a){var i=e.__iterator(R,a),s=0;return new F((function(){for(;;){var a=i.next();if(a.done)return a;var u=a.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return U(o,r?c:s++,l,a)}}))},o}function tn(e,t,n){var r=We().asMutable();return e.__iterate((function(o,a){r.update(t.call(n,o,a,e),0,(function(e){return e+1}))})),r.asImmutable()}function nn(e,t,n){var r=s(e),o=(l(e)?zt():We()).asMutable();e.__iterate((function(a,i){o.update(t.call(n,a,i,e),(function(e){return(e=e||[]).push(r?[i,a]:a),e}))}));var a=yn(e);return o.map((function(t){return mn(e,a(t))}))}function rn(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),j(t,n,o))return e;var a=T(t,o),i=I(n,o);if(a!=a||i!=i)return rn(e.toSeq().cacheResult(),t,n,r);var s,u=i-a;u==u&&(s=u<0?0:u);var c=bn(e);return c.size=0===s?s:e.size&&s||void 0,!r&&ae(e)&&s>=0&&(c.get=function(t,n){return(t=k(this,t))>=0&&ts)return q();var e=o.next();return r||t===M?e:U(t,u-1,t===N?void 0:e.value[1],e)}))},c}function on(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterate(r,o);var i=0;return e.__iterate((function(e,o,s){return t.call(n,e,o,s)&&++i&&r(e,o,a)})),i},r.__iteratorUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterator(r,o);var i=e.__iterator(R,o),s=!0;return new F((function(){if(!s)return q();var e=i.next();if(e.done)return e;var o=e.value,u=o[0],c=o[1];return t.call(n,c,u,a)?r===R?e:U(r,u,c,e):(s=!1,q())}))},r}function an(e,t,n,r){var o=bn(e);return o.__iterateUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterate(o,a);var s=!0,u=0;return e.__iterate((function(e,a,c){if(!s||!(s=t.call(n,e,a,c)))return u++,o(e,r?a:u-1,i)})),u},o.__iteratorUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterator(o,a);var s=e.__iterator(R,a),u=!0,c=0;return new F((function(){var e,a,l;do{if((e=s.next()).done)return r||o===M?e:U(o,c++,o===N?void 0:e.value[1],e);var p=e.value;a=p[0],l=p[1],u&&(u=t.call(n,l,a,i))}while(u);return o===R?e:U(o,a,l,e)}))},o}function sn(e,t){var n=s(e),o=[e].concat(t).map((function(e){return i(e)?n&&(e=r(e)):e=n?se(e):ue(Array.isArray(e)?e:[e]),e})).filter((function(e){return 0!==e.size}));if(0===o.length)return e;if(1===o.length){var a=o[0];if(a===e||n&&s(a)||u(e)&&u(a))return a}var c=new te(o);return n?c=c.toKeyedSeq():u(e)||(c=c.toSetSeq()),(c=c.flatten(!0)).size=o.reduce((function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}}),0),c}function un(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=0,s=!1;function u(e,c){var l=this;e.__iterate((function(e,o){return(!t||c0}function dn(e,t,r){var o=bn(e);return o.size=new te(r).map((function(e){return e.size})).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(M,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var a=r.map((function(e){return e=n(e),W(o?e.reverse():e)})),i=0,s=!1;return new F((function(){var n;return s||(n=a.map((function(e){return e.next()})),s=n.some((function(e){return e.done}))),s?q():U(e,i++,t.apply(null,n.map((function(e){return e.value}))))}))},o}function mn(e,t){return ae(e)?t:e.constructor(t)}function vn(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function gn(e){return Ve(e.size),A(e)}function yn(e){return s(e)?r:u(e)?o:a}function bn(e){return Object.create((s(e)?K:u(e)?Y:G).prototype)}function _n(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function wn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Kn(e,t)},Vn.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Ve(e.size);var t=this.size,n=this._head;return e.reverse().forEach((function(e){t++,n={value:e,next:n}})),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Kn(t,n)},Vn.prototype.pop=function(){return this.slice(1)},Vn.prototype.unshift=function(){return this.push.apply(this,arguments)},Vn.prototype.unshiftAll=function(e){return this.pushAll(e)},Vn.prototype.shift=function(){return this.pop.apply(this,arguments)},Vn.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Yn()},Vn.prototype.slice=function(e,t){if(j(e,t,this.size))return this;var n=T(e,this.size);if(I(t,this.size)!==this.size)return Se.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):Kn(r,o)},Vn.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Kn(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Vn.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Vn.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new F((function(){if(r){var t=r.value;return r=r.next,U(e,n++,t)}return q()}))},Vn.isStack=Wn;var Hn,$n="@@__IMMUTABLE_STACK__@@",Jn=Vn.prototype;function Kn(e,t,n,r){var o=Object.create(Jn);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Yn(){return Hn||(Hn=Kn(0))}function Gn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}Jn[$n]=!0,Jn.withMutations=Ke.withMutations,Jn.asMutable=Ke.asMutable,Jn.asImmutable=Ke.asImmutable,Jn.wasAltered=Ke.wasAltered,n.Iterator=F,Gn(n,{toArray:function(){Ve(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate((function(t,n){e[n]=t})),e},toIndexedSeq:function(){return new Kt(this)},toJS:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJS?e.toJS():e})).__toJS()},toJSON:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e})).__toJS()},toKeyedSeq:function(){return new Jt(this,!0)},toMap:function(){return We(this.toKeyedSeq())},toObject:function(){Ve(this.size);var e={};return this.__iterate((function(t,n){e[n]=t})),e},toOrderedMap:function(){return zt(this.toKeyedSeq())},toOrderedSet:function(){return Ln(s(this)?this.valueSeq():this)},toSet:function(){return jn(s(this)?this.valueSeq():this)},toSetSeq:function(){return new Yt(this)},toSeq:function(){return u(this)?this.toIndexedSeq():s(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Vn(s(this)?this.valueSeq():this)},toList:function(){return St(s(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return mn(this,sn(this,e.call(arguments,0)))},includes:function(e){return this.some((function(t){return ge(t,e)}))},entries:function(){return this.__iterator(R)},every:function(e,t){Ve(this.size);var n=!0;return this.__iterate((function(r,o,a){if(!e.call(t,r,o,a))return n=!1,!1})),n},filter:function(e,t){return mn(this,en(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Ve(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Ve(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate((function(r){n?n=!1:t+=e,t+=null!=r?r.toString():""})),t},keys:function(){return this.__iterator(N)},map:function(e,t){return mn(this,Xt(this,e,t))},reduce:function(e,t,n){var r,o;return Ve(this.size),arguments.length<2?o=!0:r=t,this.__iterate((function(t,a,i){o?(o=!1,r=t):r=e.call(n,r,t,a,i)})),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return mn(this,Qt(this,!0))},slice:function(e,t){return mn(this,rn(this,e,t,!0))},some:function(e,t){return!this.every(tr(e),t)},sort:function(e){return mn(this,pn(this,e))},values:function(){return this.__iterator(M)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some((function(){return!0}))},count:function(e,t){return A(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return tn(this,e,t)},equals:function(e){return ye(this,e)},entrySeq:function(){var e=this;if(e._cache)return new te(e._cache);var t=e.toSeq().map(er).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(tr(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate((function(n,o,a){if(e.call(t,n,o,a))return r=[o,n],!1})),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(O)},flatMap:function(e,t){return mn(this,cn(this,e,t))},flatten:function(e){return mn(this,un(this,e,!0))},fromEntrySeq:function(){return new Gt(this)},get:function(e,t){return this.find((function(t,n){return ge(n,e)}),void 0,t)},getIn:function(e,t){for(var n,r=this,o=xn(e);!(n=o.next()).done;){var a=n.value;if((r=r&&r.get?r.get(a,b):b)===b)return t}return r},groupBy:function(e,t){return nn(this,e,t)},has:function(e){return this.get(e,b)!==b},hasIn:function(e){return this.getIn(e,b)!==b},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every((function(t){return e.includes(t)}))},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey((function(t){return ge(t,e)}))},keySeq:function(){return this.toSeq().map(Qn).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return fn(this,e)},maxBy:function(e,t){return fn(this,t,e)},min:function(e){return fn(this,e?nr(e):ar)},minBy:function(e,t){return fn(this,t?nr(t):ar,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return mn(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return mn(this,an(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(tr(e),t)},sortBy:function(e,t){return mn(this,pn(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return mn(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return mn(this,on(this,e,t))},takeUntil:function(e,t){return this.takeWhile(tr(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=ir(this))}});var Zn=n.prototype;Zn[p]=!0,Zn[B]=Zn.values,Zn.__toJS=Zn.toArray,Zn.__toStringMapper=rr,Zn.inspect=Zn.toSource=function(){return this.toString()},Zn.chain=Zn.flatMap,Zn.contains=Zn.includes,Gn(r,{flip:function(){return mn(this,Zt(this))},mapEntries:function(e,t){var n=this,r=0;return mn(this,this.toSeq().map((function(o,a){return e.call(t,[a,o],r++,n)})).fromEntrySeq())},mapKeys:function(e,t){var n=this;return mn(this,this.toSeq().flip().map((function(r,o){return e.call(t,r,o,n)})).flip())}});var Xn=r.prototype;function Qn(e,t){return t}function er(e,t){return[t,e]}function tr(e){return function(){return!e.apply(this,arguments)}}function nr(e){return function(){return-e.apply(this,arguments)}}function rr(e){return"string"==typeof e?JSON.stringify(e):String(e)}function or(){return C(arguments)}function ar(e,t){return et?-1:0}function ir(e){if(e.size===1/0)return 0;var t=l(e),n=s(e),r=t?1:0;return sr(e.__iterate(n?t?function(e,t){r=31*r+ur(Oe(e),Oe(t))|0}:function(e,t){r=r+ur(Oe(e),Oe(t))|0}:t?function(e){r=31*r+Oe(e)|0}:function(e){r=r+Oe(e)|0}),r)}function sr(e,t){return t=Ae(t,3432918353),t=Ae(t<<15|t>>>-15,461845907),t=Ae(t<<13|t>>>-13,5),t=Ae((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=ke((t=Ae(t^t>>>13,3266489909))^t>>>16)}function ur(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return Xn[f]=!0,Xn[B]=Zn.entries,Xn.__toJS=Zn.toObject,Xn.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+rr(e)},Gn(o,{toKeyedSeq:function(){return new Jt(this,!1)},filter:function(e,t){return mn(this,en(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return mn(this,Qt(this,!1))},slice:function(e,t){return mn(this,rn(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=T(e,e<0?this.count():this.size);var r=this.slice(0,e);return mn(this,1===n?r:r.concat(C(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return mn(this,un(this,e,!1))},get:function(e,t){return(e=k(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find((function(t,n){return n===e}),void 0,t)},has:function(e){return(e=k(this,e))>=0&&(void 0!==this.size?this.size===1/0||e1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function Pe(e){return t=e.replace(/\.[^./]*$/,""),Y()(J()(t));var t}function Ne(e,t,n,r,a){if(!t)return[];var s=[],u=t.get("nullable"),c=t.get("required"),p=t.get("maximum"),h=t.get("minimum"),d=t.get("type"),m=t.get("format"),g=t.get("maxLength"),b=t.get("minLength"),w=t.get("uniqueItems"),x=t.get("maxItems"),E=t.get("minItems"),S=t.get("pattern"),C=n||!0===c,A=null!=e;if(u&&null===e||!d||!(C||A&&"array"===d||!(!C&&!A)))return[];var k="string"===d&&e,O="array"===d&&l()(e)&&e.length,j="array"===d&&W.a.List.isList(e)&&e.count(),T=[k,O,j,"array"===d&&"string"==typeof e&&e,"file"===d&&e instanceof se.a.File,"boolean"===d&&(e||!1===e),"number"===d&&(e||0===e),"integer"===d&&(e||0===e),"object"===d&&"object"===i()(e)&&null!==e,"object"===d&&"string"==typeof e&&e],I=P()(T).call(T,(function(e){return!!e}));if(C&&!I&&!r)return s.push("Required field is not provided"),s;if("object"===d&&(null===a||"application/json"===a)){var N,M=e;if("string"==typeof e)try{M=JSON.parse(e)}catch(e){return s.push("Parameter string value must be valid JSON"),s}if(t&&t.has("required")&&Ee(c.isList)&&c.isList()&&y()(c).call(c,(function(e){void 0===M[e]&&s.push({propKey:e,error:"Required property not found"})})),t&&t.has("properties"))y()(N=t.get("properties")).call(N,(function(e,t){var n=Ne(M[t],e,!1,r,a);s.push.apply(s,o()(f()(n).call(n,(function(e){return{propKey:t,error:e}}))))}))}if(S){var R=function(e,t){if(!new RegExp(t).test(e))return"Value must follow pattern "+t}(e,S);R&&s.push(R)}if(E&&"array"===d){var D=function(e,t){var n;if(!e&&t>=1||e&&e.lengtht)return v()(n="Array must not contain more then ".concat(t," item")).call(n,1===t?"":"s")}(e,x);L&&s.push({needRemove:!0,error:L})}if(w&&"array"===d){var B=function(e,t){if(e&&("true"===t||!0===t)){var n=Object(V.fromJS)(e),r=n.toSet();if(e.length>r.size){var o=Object(V.Set)();if(y()(n).call(n,(function(e,t){_()(n).call(n,(function(t){return Ee(t.equals)?t.equals(e):t===e})).size>1&&(o=o.add(t))})),0!==o.size)return f()(o).call(o,(function(e){return{index:e,error:"No duplicates allowed."}})).toArray()}}}(e,w);B&&s.push.apply(s,o()(B))}if(g||0===g){var F=function(e,t){var n;if(e.length>t)return v()(n="Value must be no longer than ".concat(t," character")).call(n,1!==t?"s":"")}(e,g);F&&s.push(F)}if(b){var U=function(e,t){var n;if(e.lengtht)return"Value must be less than ".concat(t)}(e,p);q&&s.push(q)}if(h||0===h){var z=function(e,t){if(e2&&void 0!==arguments[2]?arguments[2]:{},r=n.isOAS3,o=void 0!==r&&r,a=n.bypassRequiredCheck,i=void 0!==a&&a,s=e.get("required"),u=Object(le.a)(e,{isOAS3:o}),c=u.schema,l=u.parameterContentMediaType;return Ne(t,c,s,i,l)},Re=function(e,t,n){if(e&&(!e.xml||!e.xml.name)){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return Object(ie.memoizedCreateXMLExample)(e,t,n)},De=[{when:/json/,shouldStringifyTypes:["string"]}],Le=["object"],Be=function(e,t,n,r){var a=Object(ie.memoizedSampleFromSchema)(e,t,r),s=i()(a),u=S()(De).call(De,(function(e,t){var r;return t.when.test(n)?v()(r=[]).call(r,o()(e),o()(t.shouldStringifyTypes)):e}),Le);return te()(u,(function(e){return e===s}))?M()(a,null,2):a},Fe=function(e,t,n,r){var o,a=Be(e,t,n,r);try{"\n"===(o=me.a.dump(me.a.load(a),{lineWidth:-1}))[o.length-1]&&(o=T()(o).call(o,0,o.length-1))}catch(e){return console.error(e),"error: could not generate yaml example"}return o.replace(/\t/g," ")},Ue=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:void 0;return e&&Ee(e.toJS)&&(e=e.toJS()),r&&Ee(r.toJS)&&(r=r.toJS()),/xml/.test(t)?Re(e,n,r):/(yaml|yml)/.test(t)?Fe(e,n,t,r):Be(e,n,t,r)},qe=function(){var e={},t=se.a.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},ze=function(t){return(t instanceof e?t:e.from(t.toString(),"utf-8")).toString("base64")},Ve={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},We=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},He=function(e,t,n){return!!Q()(n,(function(n){return re()(e[n],t[n])}))};function $e(e){return"string"!=typeof e||""===e?"":Object(H.sanitizeUrl)(e)}function Je(e){return!(!e||D()(e).call(e,"localhost")>=0||D()(e).call(e,"127.0.0.1")>=0||"none"===e)}function Ke(e){if(!W.a.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=B()(e).call(e,(function(e,t){return U()(t).call(t,"2")&&x()(e.get("content")||{}).length>0})),n=e.get("default")||W.a.OrderedMap(),r=(n.get("content")||W.a.OrderedMap()).keySeq().toJS().length?n:null;return t||r}var Ye=function(e){return"string"==typeof e||e instanceof String?z()(e).call(e).replace(/\s/g,"%20"):""},Ge=function(e){return ce()(Ye(e).replace(/%20/g,"_"))},Ze=function(e){return _()(e).call(e,(function(e,t){return/^x-/.test(t)}))},Xe=function(e){return _()(e).call(e,(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)}))};function Qe(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==i()(e)||l()(e)||null===e||!t)return e;var o=A()({},e);return y()(n=x()(o)).call(n,(function(e){e===t&&r(o[e],e)?delete o[e]:o[e]=Qe(o[e],t,r)})),o}function et(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"===i()(e)&&null!==e)try{return M()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function tt(e){return"number"==typeof e?e.toString():e}function nt(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.returnAll,r=void 0!==n&&n,o=t.allowHashes,a=void 0===o||o;if(!W.a.Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");var i,s,u,c=e.get("name"),l=e.get("in"),p=[];e&&e.hashCode&&l&&c&&a&&p.push(v()(i=v()(s="".concat(l,".")).call(s,c,".hash-")).call(i,e.hashCode()));l&&c&&p.push(v()(u="".concat(l,".")).call(u,c));return p.push(c),r?p:p[0]||""}function rt(e,t){var n,r=nt(e,{returnAll:!0});return _()(n=f()(r).call(r,(function(e){return t[e]}))).call(n,(function(e){return void 0!==e}))[0]}function ot(){return it(fe()(32).toString("base64"))}function at(e){return it(de()("sha256").update(e).digest("base64"))}function it(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var st=function(e){return!e||!(!ge(e)||!e.isEmpty())}}).call(this,n(73).Buffer)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r=n(240);function o(e,t){for(var n=0;n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:r,n=null,a=null;return function(){return o(t,n,arguments)||(a=e.apply(null,arguments)),n=arguments,a}}))},function(e,t,n){e.exports=n(668)},function(e,t,n){var r=n(175),o=n(572);function a(t){return"function"==typeof r&&"symbol"==typeof o?(e.exports=a=function(e){return typeof e},e.exports.default=e.exports,e.exports.__esModule=!0):(e.exports=a=function(e){return e&&"function"==typeof r&&e.constructor===r&&e!==r.prototype?"symbol":typeof e},e.exports.default=e.exports,e.exports.__esModule=!0),a(t)}e.exports=a,e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){e.exports=n(598)},function(e,t,n){e.exports=n(596)},function(e,t,n){"use strict";var r=n(40),o=n(127).f,a=n(362),i=n(34),s=n(107),u=n(67),c=n(55),l=function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t};e.exports=function(e,t){var n,p,f,h,d,m,v,g,y=e.target,b=e.global,_=e.stat,w=e.proto,x=b?r:_?r[y]:(r[y]||{}).prototype,E=b?i:i[y]||(i[y]={}),S=E.prototype;for(f in t)n=!a(b?f:y+(_?".":"#")+f,e.forced)&&x&&c(x,f),d=E[f],n&&(m=e.noTargetGet?(g=o(x,f))&&g.value:x[f]),h=n&&m?m:t[f],n&&typeof d==typeof h||(v=e.bind&&n?s(h,r):e.wrap&&n?l(h):w&&"function"==typeof h?s(Function.call,h):h,(e.sham||h&&h.sham||d&&d.sham)&&u(v,"sham",!0),E[f]=v,w&&(c(i,p=y+"Prototype")||u(i,p,{}),i[p][f]=h,e.real&&S&&!S[f]&&u(S,f,h)))}},function(e,t,n){e.exports=n(601)},function(e,t,n){e.exports=n(401)},function(e,t,n){var r=n(448),o=n(449),a=n(854),i=n(856),s=n(860),u=n(862),c=n(867),l=n(240),p=n(3);function f(e,t){var n=r(e);if(o){var s=o(e);t&&(s=a(s).call(s,(function(t){return i(e,t).enumerable}))),n.push.apply(n,s)}return n}e.exports=function(e){for(var t=1;t>",i=function(){invariant(!1,"ImmutablePropTypes type checking code is stripped in production.")};i.isRequired=i;var s=function(){return i};function u(e){var t=typeof e;return Array.isArray(e)?"array":e instanceof RegExp?"object":e instanceof o.Iterable?"Immutable."+e.toSource().split(" ")[0]:t}function c(e){function t(t,n,r,o,i,s){for(var u=arguments.length,c=Array(u>6?u-6:0),l=6;l4)}function l(e){var t=e.get("swagger");return"string"==typeof t&&i()(t).call(t,"2.0")}function p(e){return function(t,n){return function(r){return n&&n.specSelectors&&n.specSelectors.specJson?c(n.specSelectors.specJson())?u.a.createElement(e,o()({},r,n,{Ori:t})):u.a.createElement(t,r):(console.warn("OAS3 wrapper: couldn't get spec"),null)}}}},function(e,t,n){e.exports=n(592)},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,n){"use strict";var r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=i(e),c=1;c0){var o=v()(n).call(n,(function(e){return console.error(e),e.line=e.fullPath?_(w,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e}));a.newThrownErrBatch(o)}return r.updateResolved(t)}))}},Se=[],Ce=Y()(u()(f.a.mark((function e(){var t,n,r,o,a,i,s,c,l,p,h,m,g,b,w,E,C,k;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t=Se.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,a=o.resolveSubtree,i=o.fetch,s=o.AST,c=void 0===s?{}:s,l=t.specSelectors,p=t.specActions,a){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return h=c.getLineNumberForPath?c.getLineNumberForPath:function(){},m=l.specStr(),g=t.getConfigs(),b=g.modelPropertyMacro,w=g.parameterMacro,E=g.requestInterceptor,C=g.responseInterceptor,e.prev=11,e.next=14,_()(Se).call(Se,function(){var e=u()(f.a.mark((function e(t,o){var s,c,p,g,_,k,j,T,I;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return s=e.sent,c=s.resultMap,p=s.specWithCurrentSubtrees,e.next=7,a(p,o,{baseDoc:l.url(),modelPropertyMacro:b,parameterMacro:w,requestInterceptor:E,responseInterceptor:C});case 7:if(g=e.sent,_=g.errors,k=g.spec,r.allErrors().size&&n.clearBy((function(e){var t;return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!x()(t=e.get("fullPath")).call(t,(function(e,t){return e===o[t]||void 0===o[t]}))})),d()(_)&&_.length>0&&(j=v()(_).call(_,(function(e){return e.line=e.fullPath?h(m,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e})),n.newThrownErrBatch(j)),!k||!l.isOAS3()||"components"!==o[0]||"securitySchemes"!==o[1]){e.next=15;break}return e.next=15,S.a.all(v()(T=A()(I=O()(k)).call(I,(function(e){return"openIdConnect"===e.type}))).call(T,function(){var e=u()(f.a.mark((function e(t){var n,r;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n={url:t.openIdConnectUrl,requestInterceptor:E,responseInterceptor:C},e.prev=1,e.next=4,i(n);case 4:(r=e.sent)instanceof Error||r.status>=400?console.error(r.statusText+" "+n.url):t.openIdConnectData=JSON.parse(r.text),e.next=11;break;case 8:e.prev=8,e.t0=e.catch(1),console.error(e.t0);case 11:case"end":return e.stop()}}),e,null,[[1,8]])})));return function(t){return e.apply(this,arguments)}}()));case 15:return Z()(c,o,k),Z()(p,o,k),e.abrupt("return",{resultMap:c,specWithCurrentSubtrees:p});case 18:case"end":return e.stop()}}),e)})));return function(t,n){return e.apply(this,arguments)}}(),S.a.resolve({resultMap:(l.specResolvedSubtree([])||Object(z.Map)()).toJS(),specWithCurrentSubtrees:l.specJson().toJS()}));case 14:k=e.sent,delete Se.system,Se=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:p.updateResolvedSubtree([],k.resultMap);case 23:case"end":return e.stop()}}),e,null,[[11,19]])}))),35),Ae=function(e){return function(t){var n;T()(n=v()(Se).call(Se,(function(e){return e.join("@@")}))).call(n,e.join("@@"))>-1||(Se.push(e),Se.system=t,Ce())}};function ke(e,t,n,r,o){return{type:re,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}}function Oe(e,t,n,r){return{type:re,payload:{path:e,param:t,value:n,isXml:r}}}var je=function(e,t){return{type:me,payload:{path:e,value:t}}},Te=function(){return{type:me,payload:{path:[],value:Object(z.Map)()}}},Ie=function(e,t){return{type:ae,payload:{pathMethod:e,isOAS3:t}}},Pe=function(e,t,n,r){return{type:oe,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};function Ne(e){return{type:fe,payload:{pathMethod:e}}}function Me(e,t){return{type:he,payload:{path:e,value:t,key:"consumes_value"}}}function Re(e,t){return{type:he,payload:{path:e,value:t,key:"produces_value"}}}var De=function(e,t,n){return{payload:{path:e,method:t,res:n},type:ie}},Le=function(e,t,n){return{payload:{path:e,method:t,req:n},type:se}},Be=function(e,t,n){return{payload:{path:e,method:t,req:n},type:ue}},Fe=function(e){return{payload:e,type:ce}},Ue=function(e){return function(t){var n,r,o=t.fn,a=t.specActions,i=t.specSelectors,s=t.getConfigs,c=t.oas3Selectors,l=e.pathName,p=e.method,h=e.operation,m=s(),g=m.requestInterceptor,y=m.responseInterceptor,b=h.toJS();h&&h.get("parameters")&&P()(n=A()(r=h.get("parameters")).call(r,(function(e){return e&&!0===e.get("allowEmptyValue")}))).call(n,(function(t){if(i.parameterInclusionSettingFor([l,p],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};var n=Object(X.B)(t,e.parameters);(!n||n&&0===n.size)&&(e.parameters[t.get("name")]="")}}));if(e.contextUrl=W()(i.url()).toString(),b&&b.operationId?e.operationId=b.operationId:b&&l&&p&&(e.operationId=o.opId(b,l,p)),i.isOAS3()){var _,w=M()(_="".concat(l,":")).call(_,p);e.server=c.selectedServer(w)||c.selectedServer();var x=c.serverVariables({server:e.server,namespace:w}).toJS(),E=c.serverVariables({server:e.server}).toJS();e.serverVariables=D()(x).length?x:E,e.requestContentType=c.requestContentType(l,p),e.responseContentType=c.responseContentType(l,p)||"*/*";var S,C=c.requestBodyValue(l,p),k=c.requestBodyInclusionSetting(l,p);if(C&&C.toJS)e.requestBody=A()(S=v()(C).call(C,(function(e){return z.Map.isMap(e)?e.get("value"):e}))).call(S,(function(e,t){return(d()(e)?0!==e.length:!Object(X.q)(e))||k.get(t)})).toJS();else e.requestBody=C}var O=B()({},e);O=o.buildRequest(O),a.setRequest(e.pathName,e.method,O);var j=function(){var t=u()(f.a.mark((function t(n){var r,o;return f.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,g.apply(undefined,[n]);case 2:return r=t.sent,o=B()({},r),a.setMutatedRequest(e.pathName,e.method,o),t.abrupt("return",r);case 6:case"end":return t.stop()}}),t)})));return function(e){return t.apply(this,arguments)}}();e.requestInterceptor=j,e.responseInterceptor=y;var T=U()();return o.execute(e).then((function(t){t.duration=U()()-T,a.setResponse(e.pathName,e.method,t)})).catch((function(t){"Failed to fetch"===t.message&&(t.name="",t.message='**Failed to fetch.** \n**Possible Reasons:** \n - CORS \n - Network Failure \n - URL scheme must be "http" or "https" for CORS request.'),a.setResponse(e.pathName,e.method,{error:!0,err:Object(H.serializeError)(t)})}))}},qe=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=i()(e,Q);return function(e){var a=e.fn.fetch,i=e.specSelectors,s=e.specActions,u=i.specJsonWithResolvedSubtrees().toJS(),c=i.operationScheme(t,n),l=i.contentTypeValues([t,n]).toJS(),p=l.requestContentType,f=l.responseContentType,h=/xml/i.test(p),d=i.parameterValues([t,n],h).toJS();return s.executeRequest(o()(o()({},r),{},{fetch:a,spec:u,pathName:t,method:n,parameters:d,requestContentType:p,scheme:c,responseContentType:f}))}};function ze(e,t){return{type:le,payload:{path:e,method:t}}}function Ve(e,t){return{type:pe,payload:{path:e,method:t}}}function We(e,t,n){return{type:ve,payload:{scheme:e,path:t,method:n}}}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(37);e.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(e,t,n){var r=n(175),o=n(243),a=n(242),i=n(185);e.exports=function(e,t){var n=void 0!==r&&o(e)||e["@@iterator"];if(!n){if(a(e)||(n=i(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var s=0,u=function(){};return{s:u,n:function(){return s>=e.length?{done:!0}:{done:!1,value:e[s++]}},e:function(e){throw e},f:u}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var c,l=!0,p=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){p=!0,c=e},f:function(){try{l||null==n.return||n.return()}finally{if(p)throw c}}}},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t){var n=Array.isArray;e.exports=n},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){var r=n(47);e.exports=function(e){if(!r(e))throw TypeError(String(e)+" is not an object");return e}},function(e,t,n){var r=n(449),o=n(450),a=n(872);e.exports=function(e,t){if(null==e)return{};var n,i,s=a(e,t);if(r){var u=r(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_SELECTED_SERVER",(function(){return r})),n.d(t,"UPDATE_REQUEST_BODY_VALUE",(function(){return o})),n.d(t,"UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG",(function(){return a})),n.d(t,"UPDATE_REQUEST_BODY_INCLUSION",(function(){return i})),n.d(t,"UPDATE_ACTIVE_EXAMPLES_MEMBER",(function(){return s})),n.d(t,"UPDATE_REQUEST_CONTENT_TYPE",(function(){return u})),n.d(t,"UPDATE_RESPONSE_CONTENT_TYPE",(function(){return c})),n.d(t,"UPDATE_SERVER_VARIABLE_VALUE",(function(){return l})),n.d(t,"SET_REQUEST_BODY_VALIDATE_ERROR",(function(){return p})),n.d(t,"CLEAR_REQUEST_BODY_VALIDATE_ERROR",(function(){return f})),n.d(t,"CLEAR_REQUEST_BODY_VALUE",(function(){return h})),n.d(t,"setSelectedServer",(function(){return d})),n.d(t,"setRequestBodyValue",(function(){return m})),n.d(t,"setRetainRequestBodyValueFlag",(function(){return v})),n.d(t,"setRequestBodyInclusion",(function(){return g})),n.d(t,"setActiveExamplesMember",(function(){return y})),n.d(t,"setRequestContentType",(function(){return b})),n.d(t,"setResponseContentType",(function(){return _})),n.d(t,"setServerVariableValue",(function(){return w})),n.d(t,"setRequestBodyValidateError",(function(){return x})),n.d(t,"clearRequestBodyValidateError",(function(){return E})),n.d(t,"initRequestBodyValidateError",(function(){return S})),n.d(t,"clearRequestBodyValue",(function(){return C}));var r="oas3_set_servers",o="oas3_set_request_body_value",a="oas3_set_request_body_retain_flag",i="oas3_set_request_body_inclusion",s="oas3_set_active_examples_member",u="oas3_set_request_content_type",c="oas3_set_response_content_type",l="oas3_set_server_variable_value",p="oas3_set_request_body_validate_error",f="oas3_clear_request_body_validate_error",h="oas3_clear_request_body_value";function d(e,t){return{type:r,payload:{selectedServerUrl:e,namespace:t}}}function m(e){var t=e.value,n=e.pathMethod;return{type:o,payload:{value:t,pathMethod:n}}}var v=function(e){var t=e.value,n=e.pathMethod;return{type:a,payload:{value:t,pathMethod:n}}};function g(e){var t=e.value,n=e.pathMethod,r=e.name;return{type:i,payload:{value:t,pathMethod:n,name:r}}}function y(e){var t=e.name,n=e.pathMethod,r=e.contextType,o=e.contextName;return{type:s,payload:{name:t,pathMethod:n,contextType:r,contextName:o}}}function b(e){var t=e.value,n=e.pathMethod;return{type:u,payload:{value:t,pathMethod:n}}}function _(e){var t=e.value,n=e.path,r=e.method;return{type:c,payload:{value:t,path:n,method:r}}}function w(e){var t=e.server,n=e.namespace,r=e.key,o=e.val;return{type:l,payload:{server:t,namespace:n,key:r,val:o}}}var x=function(e){var t=e.path,n=e.method,r=e.validationErrors;return{type:p,payload:{path:t,method:n,validationErrors:r}}},E=function(e){var t=e.path,n=e.method;return{type:f,payload:{path:t,method:n}}},S=function(e){var t=e.pathMethod;return{type:f,payload:{path:t[0],method:t[1]}}},C=function(e){var t=e.pathMethod;return{type:h,payload:{pathMethod:t}}}},function(e,t,n){var r=n(60),o={}.hasOwnProperty;e.exports=Object.hasOwn||function(e,t){return o.call(r(e),t)}},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=o},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";n.d(t,"b",(function(){return m})),n.d(t,"e",(function(){return v})),n.d(t,"c",(function(){return y})),n.d(t,"a",(function(){return b})),n.d(t,"d",(function(){return _}));var r=n(49),o=n.n(r),a=n(18),i=n.n(a),s=n(2),u=n.n(s),c=n(57),l=n.n(c),p=n(356),f=n.n(p),h=function(e){return String.prototype.toLowerCase.call(e)},d=function(e){return e.replace(/[^\w]/gi,"_")};function m(e){var t=e.openapi;return!!t&&f()(t,"3")}function v(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=r.v2OperationIdCompatibilityMode;if(!e||"object"!==i()(e))return null;var a=(e.operationId||"").replace(/\s/g,"");return a.length?d(e.operationId):g(t,n,{v2OperationIdCompatibilityMode:o})}function g(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=r.v2OperationIdCompatibilityMode;if(o){var a,i,s=u()(a="".concat(t.toLowerCase(),"_")).call(a,e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g,"_");return(s=s||u()(i="".concat(e.substring(1),"_")).call(i,t)).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return u()(n="".concat(h(t))).call(n,d(e))}function y(e,t){var n;return u()(n="".concat(h(t),"-")).call(n,e)}function b(e,t){return e&&e.paths?function(e,t){return function(e,t,n){if(!e||"object"!==i()(e)||!e.paths||"object"!==i()(e.paths))return null;var r=e.paths;for(var o in r)for(var a in r[o])if("PARAMETERS"!==a.toUpperCase()){var s=r[o][a];if(s&&"object"===i()(s)){var u={spec:e,pathName:o,method:a.toUpperCase(),operation:s},c=t(u);if(n&&c)return u}}return}(e,t,!0)||null}(e,(function(e){var n=e.pathName,r=e.method,o=e.operation;if(!o||"object"!==i()(o))return!1;var a=o.operationId;return[v(o,n,r),y(n,r),a].some((function(e){return e&&e===t}))})):null}function _(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var a in n){var i=n[a];if(l()(i)){var s=i.parameters,c=function(e){var n=i[e];if(!l()(n))return"continue";var c=v(n,a,e);if(c){r[c]?r[c].push(n):r[c]=[n];var p=r[c];if(p.length>1)p.forEach((function(e,t){var n;e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId=u()(n="".concat(c)).call(n,t+1)}));else if(void 0!==n.operationId){var f=p[0];f.__originalOperationId=f.__originalOperationId||n.operationId,f.operationId=c}}if("parameters"!==e){var h=[],d={};for(var m in t)"produces"!==m&&"consumes"!==m&&"security"!==m||(d[m]=t[m],h.push(d));if(s&&(d.parameters=s,h.push(d)),h.length){var g,y=o()(h);try{for(y.s();!(g=y.n()).done;){var b=g.value;for(var _ in b)if(n[_]){if("parameters"===_){var w,x=o()(b[_]);try{var E=function(){var e=w.value;n[_].some((function(t){return t.name&&t.name===e.name||t.$ref&&t.$ref===e.$ref||t.$$ref&&t.$$ref===e.$$ref||t===e}))||n[_].push(e)};for(x.s();!(w=x.n()).done;)E()}catch(e){x.e(e)}finally{x.f()}}}else n[_]=b[_]}}catch(e){y.e(e)}finally{y.f()}}}};for(var p in i)c(p)}}return t.$$normalized=!0,e}},function(e,t,n){"use strict";n.r(t),n.d(t,"NEW_THROWN_ERR",(function(){return o})),n.d(t,"NEW_THROWN_ERR_BATCH",(function(){return a})),n.d(t,"NEW_SPEC_ERR",(function(){return i})),n.d(t,"NEW_SPEC_ERR_BATCH",(function(){return s})),n.d(t,"NEW_AUTH_ERR",(function(){return u})),n.d(t,"CLEAR",(function(){return c})),n.d(t,"CLEAR_BY",(function(){return l})),n.d(t,"newThrownErr",(function(){return p})),n.d(t,"newThrownErrBatch",(function(){return f})),n.d(t,"newSpecErr",(function(){return h})),n.d(t,"newSpecErrBatch",(function(){return d})),n.d(t,"newAuthErr",(function(){return m})),n.d(t,"clear",(function(){return v})),n.d(t,"clearBy",(function(){return g}));var r=n(145),o="err_new_thrown_err",a="err_new_thrown_err_batch",i="err_new_spec_err",s="err_new_spec_err_batch",u="err_new_auth_err",c="err_clear",l="err_clear_by";function p(e){return{type:o,payload:Object(r.serializeError)(e)}}function f(e){return{type:a,payload:e}}function h(e){return{type:i,payload:e}}function d(e){return{type:s,payload:e}}function m(e){return{type:u,payload:e}}function v(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:c,payload:e}}function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:l,payload:e}}},function(e,t,n){var r=n(106);e.exports=function(e){return Object(r(e))}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){var r=n(73),o=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}function i(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(a(r,t),t.Buffer=i),a(o,i),i.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},i.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},i.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},i.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t0?o(r(e),9007199254740991):0}},function(e,t,n){var r=n(34),o=n(40),a=function(e){return"function"==typeof e?e:void 0};e.exports=function(e,t){return arguments.length<2?a(r[e])||a(o[e]):r[e]&&r[e][t]||o[e]&&o[e][t]}},function(e,t,n){var r=n(407),o="object"==typeof self&&self&&self.Object===Object&&self,a=r||o||Function("return this")();e.exports=a},function(e,t,n){"use strict";e.exports={debugTool:null}},function(e,t,n){"use strict";(function(e){var r=n(588),o=n(589),a=n(376);function i(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(i()=i())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i().toString(16)+" bytes");return 0|e}function d(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return q(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return q(e).length;t=(""+t).toLowerCase(),r=!0}}function m(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return T(this,t,n);case"utf8":case"utf-8":return A(this,t,n);case"ascii":return O(this,t,n);case"latin1":case"binary":return j(this,t,n);case"base64":return C(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=u.from(t,r)),u.isBuffer(t))return 0===t.length?-1:y(e,t,n,r,o);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):y(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,n,r,o){var a,i=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;i=2,s/=2,u/=2,n/=2}function c(e,t){return 1===i?e[t]:e.readUInt16BE(t*i)}if(o){var l=-1;for(a=n;as&&(n=s-u),a=n;a>=0;a--){for(var p=!0,f=0;fo&&(r=o):r=o;var a=t.length;if(a%2!=0)throw new TypeError("Invalid hex string");r>a/2&&(r=a/2);for(var i=0;i>8,o=n%256,a.push(o),a.push(r);return a}(t,e.length-n),e,n,r)}function C(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function A(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:c>223?3:c>191?2:1;if(o+p<=n)switch(p){case 1:c<128&&(l=c);break;case 2:128==(192&(a=e[o+1]))&&(u=(31&c)<<6|63&a)>127&&(l=u);break;case 3:a=e[o+1],i=e[o+2],128==(192&a)&&128==(192&i)&&(u=(15&c)<<12|(63&a)<<6|63&i)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:a=e[o+1],i=e[o+2],s=e[o+3],128==(192&a)&&128==(192&i)&&128==(192&s)&&(u=(15&c)<<18|(63&a)<<12|(63&i)<<6|63&s)>65535&&u<1114112&&(l=u)}null===l?(l=65533,p=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=p}return function(e){var t=e.length;if(t<=k)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},u.prototype.compare=function(e,t,n,r,o){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var a=(o>>>=0)-(r>>>=0),i=(n>>>=0)-(t>>>=0),s=Math.min(a,i),c=this.slice(r,o),l=e.slice(t,n),p=0;po)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var a=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return _(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return x(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,n);default:if(a)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),a=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var k=4096;function O(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",a=t;an)throw new RangeError("Trying to access beyond buffer length")}function N(e,t,n,r,o,a){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function M(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,a=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function R(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,a=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function D(e,t,n,r,o,a){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,a){return a||D(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function B(e,t,n,r,a){return a||D(e,0,n,8),o.write(e,t,n,r,52,8),n+8}u.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},u.prototype.readUInt8=function(e,t){return t||P(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||P(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||P(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||P(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||P(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||P(e,t,this.length);for(var r=this[e],o=1,a=0;++a=(o*=128)&&(r-=Math.pow(2,8*t)),r},u.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||P(e,t,this.length);for(var r=t,o=1,a=this[e+--r];r>0&&(o*=256);)a+=this[e+--r]*o;return a>=(o*=128)&&(a-=Math.pow(2,8*t)),a},u.prototype.readInt8=function(e,t){return t||P(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||P(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt16BE=function(e,t){t||P(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt32LE=function(e,t){return t||P(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||P(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||P(e,4,this.length),o.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||P(e,4,this.length),o.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||P(e,8,this.length),o.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||P(e,8,this.length),o.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||N(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,a=0;for(this[t]=255&e;++a=0&&(a*=256);)this[t+o]=e/a&255;return t+n},u.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):R(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);N(this,e,t,n,o-1,-o)}var a=0,i=1,s=0;for(this[t]=255&e;++a>0)-s&255;return t+n},u.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);N(this,e,t,n,o-1,-o)}var a=n-1,i=1,s=0;for(this[t+a]=255&e;--a>=0&&(i*=256);)e<0&&0===s&&0!==this[t+a+1]&&(s=1),this[t+a]=(e/i>>0)-s&255;return t+n},u.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):R(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},u.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},u.prototype.writeDoubleLE=function(e,t,n){return B(this,e,t,!0,n)},u.prototype.writeDoubleBE=function(e,t,n){return B(this,e,t,!1,n)},u.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(a<1e3||!u.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(a=t;a55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&a.push(239,191,189);continue}if(i+1===r){(t-=3)>-1&&a.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&a.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&a.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;a.push(n)}else if(n<2048){if((t-=2)<0)break;a.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return a}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(F,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function V(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(51))},function(e,t,n){"use strict";function r(e){return null==e}var o={isNothing:r,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:r(e)?[]:[e]},repeat:function(e,t){var n,r="";for(n=0;ns&&(t=r-s+(a=" ... ").length),n-r>s&&(n=r+s-(i=" ...").length),{str:a+e.slice(t,n).replace(/\t/g,"→")+i,pos:r-t+a.length}}function c(e,t){return o.repeat(" ",t-e.length)+e}var l=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var n,r=/\r?\n|\r|\0/g,a=[0],i=[],s=-1;n=r.exec(e.buffer);)i.push(n.index),a.push(n.index+n[0].length),e.position<=n.index&&s<0&&(s=a.length-2);s<0&&(s=a.length-1);var l,p,f="",h=Math.min(e.line+t.linesAfter,i.length).toString().length,d=t.maxLength-(t.indent+h+3);for(l=1;l<=t.linesBefore&&!(s-l<0);l++)p=u(e.buffer,a[s-l],i[s-l],e.position-(a[s]-a[s-l]),d),f=o.repeat(" ",t.indent)+c((e.line-l+1).toString(),h)+" | "+p.str+"\n"+f;for(p=u(e.buffer,a[s],i[s],e.position,d),f+=o.repeat(" ",t.indent)+c((e.line+1).toString(),h)+" | "+p.str+"\n",f+=o.repeat("-",t.indent+h+3+p.pos)+"^\n",l=1;l<=t.linesAfter&&!(s+l>=i.length);l++)p=u(e.buffer,a[s+l],i[s+l],e.position-(a[s]-a[s+l]),d),f+=o.repeat(" ",t.indent)+c((e.line+l+1).toString(),h)+" | "+p.str+"\n";return f.replace(/\n$/,"")},p=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],f=["scalar","sequence","mapping"];var h=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===p.indexOf(t))throw new s('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===f.indexOf(this.kind))throw new s('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function d(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,r){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=r)})),n[t]=e})),n}function m(e){return this.extend(e)}m.prototype.extend=function(e){var t=[],n=[];if(e instanceof h)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new s("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof h))throw new s("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new s("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new s("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof h))throw new s("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var r=Object.create(m.prototype);return r.implicit=(this.implicit||[]).concat(t),r.explicit=(this.explicit||[]).concat(n),r.compiledImplicit=d(r,"implicit"),r.compiledExplicit=d(r,"explicit"),r.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function r(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kind][e.tag]=n.fallback[e.tag]=e}for(e=0,t=arguments.length;e=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),A=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");var k=/^[-+]?[0-9]+e/;var O=new h("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!A.test(e)||"_"===e[e.length-1])},construct:function(e){var t,n;return n="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:n*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||o.isNegativeZero(e))},represent:function(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(o.isNegativeZero(e))return"-0.0";return n=e.toString(10),k.test(n)?n.replace("e",".e"):n},defaultStyle:"lowercase"}),j=_.extend({implicit:[w,x,C,O]}),T=j,I=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),P=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");var N=new h("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==I.exec(e)||null!==P.exec(e))},construct:function(e){var t,n,r,o,a,i,s,u,c=0,l=null;if(null===(t=I.exec(e))&&(t=P.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],r=+t[2]-1,o=+t[3],!t[4])return new Date(Date.UTC(n,r,o));if(a=+t[4],i=+t[5],s=+t[6],t[7]){for(c=t[7].slice(0,3);c.length<3;)c+="0";c=+c}return t[9]&&(l=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(l=-l)),u=new Date(Date.UTC(n,r,o,a,i,s,c)),l&&u.setTime(u.getTime()-l),u},instanceOf:Date,represent:function(e){return e.toISOString()}});var M=new h("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}}),R="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";var D=new h("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,n,r=0,o=e.length,a=R;for(n=0;n64)){if(t<0)return!1;r+=6}return r%8==0},construct:function(e){var t,n,r=e.replace(/[\r\n=]/g,""),o=r.length,a=R,i=0,s=[];for(t=0;t>16&255),s.push(i>>8&255),s.push(255&i)),i=i<<6|a.indexOf(r.charAt(t));return 0===(n=o%4*6)?(s.push(i>>16&255),s.push(i>>8&255),s.push(255&i)):18===n?(s.push(i>>10&255),s.push(i>>2&255)):12===n&&s.push(i>>4&255),new Uint8Array(s)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){var t,n,r="",o=0,a=e.length,i=R;for(t=0;t>18&63],r+=i[o>>12&63],r+=i[o>>6&63],r+=i[63&o]),o=(o<<8)+e[t];return 0===(n=a%3)?(r+=i[o>>18&63],r+=i[o>>12&63],r+=i[o>>6&63],r+=i[63&o]):2===n?(r+=i[o>>10&63],r+=i[o>>4&63],r+=i[o<<2&63],r+=i[64]):1===n&&(r+=i[o>>2&63],r+=i[o<<4&63],r+=i[64],r+=i[64]),r}}),L=Object.prototype.hasOwnProperty,B=Object.prototype.toString;var F=new h("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,n,r,o,a,i=[],s=e;for(t=0,n=s.length;t>10),56320+(e-65536&1023))}for(var ae=new Array(256),ie=new Array(256),se=0;se<256;se++)ae[se]=re(se)?1:0,ie[se]=re(se);function ue(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||W,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function ce(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=l(n),new s(t,n)}function le(e,t){throw ce(e,t)}function pe(e,t){e.onWarning&&e.onWarning.call(null,ce(e,t))}var fe={YAML:function(e,t,n){var r,o,a;null!==e.version&&le(e,"duplication of %YAML directive"),1!==n.length&&le(e,"YAML directive accepts exactly one argument"),null===(r=/^([0-9]+)\.([0-9]+)$/.exec(n[0]))&&le(e,"ill-formed argument of the YAML directive"),o=parseInt(r[1],10),a=parseInt(r[2],10),1!==o&&le(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=a<2,1!==a&&2!==a&&pe(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var r,o;2!==n.length&&le(e,"TAG directive accepts exactly two arguments"),r=n[0],o=n[1],Y.test(r)||le(e,"ill-formed tag handle (first argument) of the TAG directive"),H.call(e.tagMap,r)&&le(e,'there is a previously declared suffix for "'+r+'" tag handle'),G.test(o)||le(e,"ill-formed tag prefix (second argument) of the TAG directive");try{o=decodeURIComponent(o)}catch(t){le(e,"tag prefix is malformed: "+o)}e.tagMap[r]=o}};function he(e,t,n,r){var o,a,i,s;if(t1&&(e.result+=o.repeat("\n",t-1))}function _e(e,t){var n,r,o=e.tag,a=e.anchor,i=[],s=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),r=e.input.charCodeAt(e.position);0!==r&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,le(e,"tab characters must not be used in indentation")),45===r)&&ee(e.input.charCodeAt(e.position+1));)if(s=!0,e.position++,ge(e,!0,-1)&&e.lineIndent<=t)i.push(null),r=e.input.charCodeAt(e.position);else if(n=e.line,Ee(e,t,3,!1,!0),i.push(e.result),ge(e,!0,-1),r=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==r)le(e,"bad indentation of a sequence entry");else if(e.lineIndentt?m=1:e.lineIndent===t?m=0:e.lineIndentt?m=1:e.lineIndent===t?m=0:e.lineIndentt)&&(g&&(i=e.line,s=e.lineStart,u=e.position),Ee(e,t,4,!0,o)&&(g?m=e.result:v=e.result),g||(me(e,f,h,d,m,v,i,s,u),d=m=v=null),ge(e,!0,-1),c=e.input.charCodeAt(e.position)),(e.line===a||e.lineIndent>t)&&0!==c)le(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===a?le(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):l?le(e,"repeat of an indentation width identifier"):(p=t+a-1,l=!0)}if(Q(i)){do{i=e.input.charCodeAt(++e.position)}while(Q(i));if(35===i)do{i=e.input.charCodeAt(++e.position)}while(!X(i)&&0!==i)}for(;0!==i;){for(ve(e),e.lineIndent=0,i=e.input.charCodeAt(e.position);(!l||e.lineIndentp&&(p=e.lineIndent),X(i))f++;else{if(e.lineIndent0){for(o=i,a=0;o>0;o--)(i=ne(s=e.input.charCodeAt(++e.position)))>=0?a=(a<<4)+i:le(e,"expected hexadecimal character");e.result+=oe(a),e.position++}else le(e,"unknown escape sequence");n=r=e.position}else X(s)?(he(e,n,r,!0),be(e,ge(e,!1,t)),n=r=e.position):e.position===e.lineStart&&ye(e)?le(e,"unexpected end of the document within a double quoted scalar"):(e.position++,r=e.position)}le(e,"unexpected end of the stream within a double quoted scalar")}(e,h)?g=!0:!function(e){var t,n,r;if(42!==(r=e.input.charCodeAt(e.position)))return!1;for(r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!ee(r)&&!te(r);)r=e.input.charCodeAt(++e.position);return e.position===t&&le(e,"name of an alias node must contain at least one character"),n=e.input.slice(t,e.position),H.call(e.anchorMap,n)||le(e,'unidentified alias "'+n+'"'),e.result=e.anchorMap[n],ge(e,!0,-1),!0}(e)?function(e,t,n){var r,o,a,i,s,u,c,l,p=e.kind,f=e.result;if(ee(l=e.input.charCodeAt(e.position))||te(l)||35===l||38===l||42===l||33===l||124===l||62===l||39===l||34===l||37===l||64===l||96===l)return!1;if((63===l||45===l)&&(ee(r=e.input.charCodeAt(e.position+1))||n&&te(r)))return!1;for(e.kind="scalar",e.result="",o=a=e.position,i=!1;0!==l;){if(58===l){if(ee(r=e.input.charCodeAt(e.position+1))||n&&te(r))break}else if(35===l){if(ee(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&ye(e)||n&&te(l))break;if(X(l)){if(s=e.line,u=e.lineStart,c=e.lineIndent,ge(e,!1,-1),e.lineIndent>=t){i=!0,l=e.input.charCodeAt(e.position);continue}e.position=a,e.line=s,e.lineStart=u,e.lineIndent=c;break}}i&&(he(e,o,a,!1),be(e,e.line-s),o=a=e.position,i=!1),Q(l)||(a=e.position+1),l=e.input.charCodeAt(++e.position)}return he(e,o,a,!1),!!e.result||(e.kind=p,e.result=f,!1)}(e,h,1===n)&&(g=!0,null===e.tag&&(e.tag="?")):(g=!0,null===e.tag&&null===e.anchor||le(e,"alias node should not have any properties")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===m&&(g=u&&_e(e,d))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&le(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),c=0,l=e.implicitTypes.length;c"),null!==e.result&&f.kind!==e.kind&&le(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+f.kind+'", not "'+e.kind+'"'),f.resolve(e.result,e.tag)?(e.result=f.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):le(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function Se(e){var t,n,r,o,a=e.position,i=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(o=e.input.charCodeAt(e.position))&&(ge(e,!0,-1),o=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==o));){for(i=!0,o=e.input.charCodeAt(++e.position),t=e.position;0!==o&&!ee(o);)o=e.input.charCodeAt(++e.position);for(r=[],(n=e.input.slice(t,e.position)).length<1&&le(e,"directive name must not be less than one character in length");0!==o;){for(;Q(o);)o=e.input.charCodeAt(++e.position);if(35===o){do{o=e.input.charCodeAt(++e.position)}while(0!==o&&!X(o));break}if(X(o))break;for(t=e.position;0!==o&&!ee(o);)o=e.input.charCodeAt(++e.position);r.push(e.input.slice(t,e.position))}0!==o&&ve(e),H.call(fe,n)?fe[n](e,n,r):pe(e,'unknown document directive "'+n+'"')}ge(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,ge(e,!0,-1)):i&&le(e,"directives end mark is expected"),Ee(e,e.lineIndent-1,4,!1,!0),ge(e,!0,-1),e.checkLineBreaks&&J.test(e.input.slice(a,e.position))&&pe(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&ye(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,ge(e,!0,-1)):e.position=55296&&r<=56319&&t+1=56320&&n<=57343?1024*(r-55296)+n-56320+65536:r}function ze(e){return/^\n* /.test(e)}function Ve(e,t,n,r,o,a,i,s){var u,c,l=0,p=null,f=!1,h=!1,d=-1!==r,m=-1,v=Be(c=qe(e,0))&&c!==je&&!Le(c)&&45!==c&&63!==c&&58!==c&&44!==c&&91!==c&&93!==c&&123!==c&&125!==c&&35!==c&&38!==c&&42!==c&&33!==c&&124!==c&&61!==c&&62!==c&&39!==c&&34!==c&&37!==c&&64!==c&&96!==c&&function(e){return!Le(e)&&58!==e}(qe(e,e.length-1));if(t||i)for(u=0;u=65536?u+=2:u++){if(!Be(l=qe(e,u)))return 5;v=v&&Ue(l,p,s),p=l}else{for(u=0;u=65536?u+=2:u++){if(10===(l=qe(e,u)))f=!0,d&&(h=h||u-m-1>r&&" "!==e[m+1],m=u);else if(!Be(l))return 5;v=v&&Ue(l,p,s),p=l}h=h||d&&u-m-1>r&&" "!==e[m+1]}return f||h?n>9&&ze(e)?5:i?2===a?5:2:h?4:3:!v||i||o(e)?2===a?5:2:1}function We(e,t,n,r,o){e.dump=function(){if(0===t.length)return 2===e.quotingType?'""':"''";if(!e.noCompatMode&&(-1!==Ie.indexOf(t)||Pe.test(t)))return 2===e.quotingType?'"'+t+'"':"'"+t+"'";var a=e.indent*Math.max(1,n),i=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-a),u=r||e.flowLevel>-1&&n>=e.flowLevel;switch(Ve(t,u,e.indent,i,(function(t){return function(e,t){var n,r;for(n=0,r=e.implicitTypes.length;n"+He(t,e.indent)+$e(Re(function(e,t){var n,r,o=/(\n+)([^\n]*)/g,a=(s=e.indexOf("\n"),s=-1!==s?s:e.length,o.lastIndex=s,Je(e.slice(0,s),t)),i="\n"===e[0]||" "===e[0];var s;for(;r=o.exec(e);){var u=r[1],c=r[2];n=" "===c[0],a+=u+(i||n||""===c?"":"\n")+Je(c,t),i=n}return a}(t,i),a));case 5:return'"'+function(e){for(var t,n="",r=0,o=0;o=65536?o+=2:o++)r=qe(e,o),!(t=Te[r])&&Be(r)?(n+=e[o],r>=65536&&(n+=e[o+1])):n+=t||Ne(r);return n}(t)+'"';default:throw new s("impossible error: invalid scalar style")}}()}function He(e,t){var n=ze(e)?String(t):"",r="\n"===e[e.length-1];return n+(r&&("\n"===e[e.length-2]||"\n"===e)?"+":r?"":"-")+"\n"}function $e(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function Je(e,t){if(""===e||" "===e[0])return e;for(var n,r,o=/ [^ ]/g,a=0,i=0,s=0,u="";n=o.exec(e);)(s=n.index)-a>t&&(r=i>a?i:s,u+="\n"+e.slice(a,r),a=r+1),i=s;return u+="\n",e.length-a>t&&i>a?u+=e.slice(a,i)+"\n"+e.slice(i+1):u+=e.slice(a),u.slice(1)}function Ke(e,t,n,r){var o,a,i,s="",u=e.tag;for(o=0,a=n.length;o tag resolver accepts not "'+c+'" style');r=u.represent[c](t,c)}e.dump=r}return!0}return!1}function Ge(e,t,n,r,o,a,i){e.tag=null,e.dump=n,Ye(e,n,!1)||Ye(e,n,!0);var u,c=ke.call(e.dump),l=r;r&&(r=e.flowLevel<0||e.flowLevel>t);var p,f,h="[object Object]"===c||"[object Array]"===c;if(h&&(f=-1!==(p=e.duplicates.indexOf(n))),(null!==e.tag&&"?"!==e.tag||f||2!==e.indent&&t>0)&&(o=!1),f&&e.usedDuplicates[p])e.dump="*ref_"+p;else{if(h&&f&&!e.usedDuplicates[p]&&(e.usedDuplicates[p]=!0),"[object Object]"===c)r&&0!==Object.keys(e.dump).length?(!function(e,t,n,r){var o,a,i,u,c,l,p="",f=e.tag,h=Object.keys(n);if(!0===e.sortKeys)h.sort();else if("function"==typeof e.sortKeys)h.sort(e.sortKeys);else if(e.sortKeys)throw new s("sortKeys must be a boolean or a function");for(o=0,a=h.length;o1024)&&(e.dump&&10===e.dump.charCodeAt(0)?l+="?":l+="? "),l+=e.dump,c&&(l+=De(e,t)),Ge(e,t+1,u,!0,c)&&(e.dump&&10===e.dump.charCodeAt(0)?l+=":":l+=": ",p+=l+=e.dump));e.tag=f,e.dump=p||"{}"}(e,t,e.dump,o),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var r,o,a,i,s,u="",c=e.tag,l=Object.keys(n);for(r=0,o=l.length;r1024&&(s+="? "),s+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Ge(e,t,i,!1,!1)&&(u+=s+=e.dump));e.tag=c,e.dump="{"+u+"}"}(e,t,e.dump),f&&(e.dump="&ref_"+p+" "+e.dump));else if("[object Array]"===c)r&&0!==e.dump.length?(e.noArrayIndent&&!i&&t>0?Ke(e,t-1,e.dump,o):Ke(e,t,e.dump,o),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var r,o,a,i="",s=e.tag;for(r=0,o=n.length;r",e.dump=u+" "+e.dump)}return!0}function Ze(e,t){var n,r,o=[],a=[];for(Xe(e,o,a),n=0,r=a.length;n",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(c),p=["%","/","?",";","#"].concat(l),f=["/","?","#"],h=/^[+a-z0-9A-Z_-]{0,63}$/,d=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},v={javascript:!0,"javascript:":!0},g={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},y=n(1077);function b(e,t,n){if(e&&o.isObject(e)&&e instanceof a)return e;var r=new a;return r.parse(e,t,n),r}a.prototype.parse=function(e,t,n){if(!o.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var a=e.indexOf("?"),s=-1!==a&&a127?N+="x":N+=P[M];if(!N.match(h)){var D=T.slice(0,k),L=T.slice(k+1),B=P.match(d);B&&(D.push(B[1]),L.unshift(B[2])),L.length&&(b="/"+L.join(".")+b),this.hostname=D.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),j||(this.hostname=r.toASCII(this.hostname));var F=this.port?":"+this.port:"",U=this.hostname||"";this.host=U+F,this.href+=this.host,j&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==b[0]&&(b="/"+b))}if(!m[x])for(k=0,I=l.length;k0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift());return n.search=e.search,n.query=e.query,o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!E.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var C=E.slice(-1)[0],A=(n.host||e.host||E.length>1)&&("."===C||".."===C)||""===C,k=0,O=E.length;O>=0;O--)"."===(C=E[O])?E.splice(O,1):".."===C?(E.splice(O,1),k++):k&&(E.splice(O,1),k--);if(!w&&!x)for(;k--;k)E.unshift("..");!w||""===E[0]||E[0]&&"/"===E[0].charAt(0)||E.unshift(""),A&&"/"!==E.join("/").substr(-1)&&E.push("");var j,T=""===E[0]||E[0]&&"/"===E[0].charAt(0);S&&(n.hostname=n.host=T?"":E.length?E.shift():"",(j=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift()));return(w=w||n.host&&E.length)&&!T&&E.unshift(""),E.length?n.pathname=E.join("/"):(n.pathname=null,n.path=null),o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},a.prototype.parseHost=function(){var e=this.host,t=s.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,n){"use strict";n.r(t),n.d(t,"SHOW_AUTH_POPUP",(function(){return h})),n.d(t,"AUTHORIZE",(function(){return d})),n.d(t,"LOGOUT",(function(){return m})),n.d(t,"PRE_AUTHORIZE_OAUTH2",(function(){return v})),n.d(t,"AUTHORIZE_OAUTH2",(function(){return g})),n.d(t,"VALIDATE",(function(){return y})),n.d(t,"CONFIGURE_AUTH",(function(){return b})),n.d(t,"RESTORE_AUTHORIZATION",(function(){return _})),n.d(t,"showDefinitions",(function(){return w})),n.d(t,"authorize",(function(){return x})),n.d(t,"authorizeWithPersistOption",(function(){return E})),n.d(t,"logout",(function(){return S})),n.d(t,"logoutWithPersistOption",(function(){return C})),n.d(t,"preAuthorizeImplicit",(function(){return A})),n.d(t,"authorizeOauth2",(function(){return k})),n.d(t,"authorizeOauth2WithPersistOption",(function(){return O})),n.d(t,"authorizePassword",(function(){return j})),n.d(t,"authorizeApplication",(function(){return T})),n.d(t,"authorizeAccessCodeWithFormParams",(function(){return I})),n.d(t,"authorizeAccessCodeWithBasicAuthentication",(function(){return P})),n.d(t,"authorizeRequest",(function(){return N})),n.d(t,"configureAuth",(function(){return M})),n.d(t,"restoreAuthorization",(function(){return R})),n.d(t,"persistAuthorizationIfNeeded",(function(){return D}));var r=n(18),o=n.n(r),a=n(32),i=n.n(a),s=n(20),u=n.n(s),c=n(94),l=n.n(c),p=n(26),f=n(5),h="show_popup",d="authorize",m="logout",v="pre_authorize_oauth2",g="authorize_oauth2",y="validate",b="configure_auth",_="restore_authorization";function w(e){return{type:h,payload:e}}function x(e){return{type:d,payload:e}}var E=function(e){return function(t){var n=t.authActions;n.authorize(e),n.persistAuthorizationIfNeeded()}};function S(e){return{type:m,payload:e}}var C=function(e){return function(t){var n=t.authActions;n.logout(e),n.persistAuthorizationIfNeeded()}},A=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,a=e.token,s=e.isValid,u=o.schema,c=o.name,l=u.get("flow");delete p.a.swaggerUIRedirectOauth2,"accessCode"===l||s||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),a.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:i()(a)}):n.authorizeOauth2WithPersistOption({auth:o,token:a})}};function k(e){return{type:g,payload:e}}var O=function(e){return function(t){var n=t.authActions;n.authorizeOauth2(e),n.persistAuthorizationIfNeeded()}},j=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.name,a=e.username,i=e.password,s=e.passwordType,c=e.clientId,l=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" "),username:a,password:i},h={};switch(s){case"request-body":!function(e,t,n){t&&u()(e,{client_id:t});n&&u()(e,{client_secret:n})}(p,c,l);break;case"basic":h.Authorization="Basic "+Object(f.a)(c+":"+l);break;default:console.warn("Warning: invalid passwordType ".concat(s," was passed, not including client id and secret"))}return n.authorizeRequest({body:Object(f.b)(p),url:r.get("tokenUrl"),name:o,headers:h,query:{},auth:e})}};var T=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,a=e.name,i=e.clientId,s=e.clientSecret,u={Authorization:"Basic "+Object(f.a)(i+":"+s)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:Object(f.b)(c),name:a,url:r.get("tokenUrl"),auth:e,headers:u})}},I=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={grant_type:"authorization_code",code:t.code,client_id:i,client_secret:s,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(f.b)(c),name:a,url:o.get("tokenUrl"),auth:t})}},P=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={Authorization:"Basic "+Object(f.a)(i+":"+s)},l={grant_type:"authorization_code",code:t.code,client_id:i,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(f.b)(l),name:a,url:o.get("tokenUrl"),auth:t,headers:c})}},N=function(e){return function(t){var n,r=t.fn,a=t.getConfigs,s=t.authActions,c=t.errActions,p=t.oas3Selectors,f=t.specSelectors,h=t.authSelectors,d=e.body,m=e.query,v=void 0===m?{}:m,g=e.headers,y=void 0===g?{}:g,b=e.name,_=e.url,w=e.auth,x=(h.getConfigs()||{}).additionalQueryStringParams;if(f.isOAS3()){var E=p.serverEffectiveValue(p.selectedServer());n=l()(_,E,!0)}else n=l()(_,f.url(),!0);"object"===o()(x)&&(n.query=u()({},n.query,x));var S=n.toString(),C=u()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},y);r.fetch({url:S,method:"post",headers:C,query:v,body:d,requestInterceptor:a().requestInterceptor,responseInterceptor:a().responseInterceptor}).then((function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?c.newAuthErr({authId:b,level:"error",source:"auth",message:i()(t)}):s.authorizeOauth2WithPersistOption({auth:w,token:t}):c.newAuthErr({authId:b,level:"error",source:"auth",message:e.statusText})})).catch((function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: ".concat(r.error)),r.error_description&&(t+=", description: ".concat(r.error_description))}catch(e){}}c.newAuthErr({authId:b,level:"error",source:"auth",message:t})}))}};function M(e){return{type:b,payload:e}}function R(e){return{type:_,payload:e}}var D=function(){return function(e){var t=e.authSelectors;if((0,e.getConfigs)().persistAuthorization){var n=t.authorized();localStorage.setItem("authorized",i()(n.toJS()))}}}},function(e,t,n){var r=n(1048);e.exports=function(e){for(var t=1;tS;S++)if((h||S in w)&&(b=x(y=w[S],S,_),e))if(t)A[S]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return S;case 2:u.call(A,y)}else switch(e){case 4:return!1;case 7:u.call(A,y)}return p?-1:c||l?l:A}};e.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterOut:c(7)}},function(e,t,n){n(157);var r=n(576),o=n(40),a=n(99),i=n(67),s=n(131),u=n(41)("toStringTag");for(var c in r){var l=o[c],p=l&&l.prototype;p&&a(p)!==u&&i(p,u,c),s[c]=s.Array}},function(e,t,n){"use strict";e.exports={current:null}},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t){var n,r,o=e.exports={};function a(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===a||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:a}catch(e){n=a}try{r="function"==typeof clearTimeout?clearTimeout:i}catch(e){r=i}}();var u,c=[],l=!1,p=-1;function f(){l&&u&&(l=!1,u.length?c=u.concat(c):p=-1,c.length&&h())}function h(){if(!l){var e=s(f);l=!0;for(var t=c.length;t;){for(u=c,c=[];++p1)for(var n=1;n0&&"/"!==t[0]}));function Se(e,t,n){var r;t=t||[];var o=we.apply(void 0,u()(r=[e]).call(r,i()(t))).get("parameters",Object(I.List)());return x()(o).call(o,(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(Object(T.A)(t,{allowHashes:!1}),r)}),Object(I.fromJS)({}))}function Ce(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("in")===t}))}function Ae(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("type")===t}))}function ke(e,t){var n,r;t=t||[];var o=z(e).getIn(u()(n=["paths"]).call(n,i()(t)),Object(I.fromJS)({})),a=e.getIn(u()(r=["meta","paths"]).call(r,i()(t)),Object(I.fromJS)({})),s=Oe(e,t),c=o.get("parameters")||new I.List,l=a.get("consumes_value")?a.get("consumes_value"):Ae(c,"file")?"multipart/form-data":Ae(c,"formData")?"application/x-www-form-urlencoded":void 0;return Object(I.fromJS)({requestContentType:l,responseContentType:s})}function Oe(e,t){var n,r;t=t||[];var o=z(e).getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==o){var a=e.getIn(u()(r=["meta","paths"]).call(r,i()(t),["produces_value"]),null),s=o.getIn(["produces",0],null);return a||s||"application/json"}}function je(e,t){var n;t=t||[];var r=z(e),a=r.getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var s=t,c=o()(s,1)[0],l=a.get("produces",null),p=r.getIn(["paths",c,"produces"],null),f=r.getIn(["produces"],null);return l||p||f}}function Te(e,t){var n;t=t||[];var r=z(e),a=r.getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var s=t,c=o()(s,1)[0],l=a.get("consumes",null),p=r.getIn(["paths",c,"consumes"],null),f=r.getIn(["consumes"],null);return l||p||f}}var Ie=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=O()(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""},Pe=function(e,t,n){var r;return d()(r=["http","https"]).call(r,Ie(e,t,n))>-1},Ne=function(e,t){var n;t=t||[];var r=e.getIn(u()(n=["meta","paths"]).call(n,i()(t),["parameters"]),Object(I.fromJS)([])),o=!0;return f()(r).call(r,(function(e){var t=e.get("errors");t&&t.count()&&(o=!1)})),o},Me=function(e,t){var n,r,o={requestBody:!1,requestContentType:{}},a=e.getIn(u()(n=["resolvedSubtrees","paths"]).call(n,i()(t),["requestBody"]),Object(I.fromJS)([]));return a.size<1||(a.getIn(["required"])&&(o.requestBody=a.getIn(["required"])),f()(r=a.getIn(["content"]).entrySeq()).call(r,(function(e){var t=e[0];if(e[1].getIn(["schema","required"])){var n=e[1].getIn(["schema","required"]).toJS();o.requestContentType[t]=n}}))),o},Re=function(e,t,n,r){var o;if((n||r)&&n===r)return!0;var a=e.getIn(u()(o=["resolvedSubtrees","paths"]).call(o,i()(t),["requestBody","content"]),Object(I.fromJS)([]));if(a.size<2||!n||!r)return!1;var s=a.getIn([n,"schema","properties"],Object(I.fromJS)([])),c=a.getIn([r,"schema","properties"],Object(I.fromJS)([]));return!!s.equals(c)};function De(e){return I.Map.isMap(e)?e:new I.Map}},function(e,t,n){"use strict";(function(t){var r=n(894),o=n(895),a=/^[A-Za-z][A-Za-z0-9+-.]*:[\\/]+/,i=/^([a-z][a-z0-9.+-]*:)?([\\/]{1,})?([\S\s]*)/i,s=new RegExp("^[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]+");function u(e){return(e||"").toString().replace(s,"")}var c=[["#","hash"],["?","query"],function(e){return e.replace("\\","/")},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],l={hash:1,query:1};function p(e){var n,r=("undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{}).location||{},o={},i=typeof(e=e||r);if("blob:"===e.protocol)o=new h(unescape(e.pathname),{});else if("string"===i)for(n in o=new h(e,{}),l)delete o[n];else if("object"===i){for(n in e)n in l||(o[n]=e[n]);void 0===o.slashes&&(o.slashes=a.test(e.href))}return o}function f(e){e=u(e);var t=i.exec(e);return{protocol:t[1]?t[1].toLowerCase():"",slashes:!!(t[2]&&t[2].length>=2),rest:t[2]&&1===t[2].length?"/"+t[3]:t[3]}}function h(e,t,n){if(e=u(e),!(this instanceof h))return new h(e,t,n);var a,i,s,l,d,m,v=c.slice(),g=typeof t,y=this,b=0;for("object"!==g&&"string"!==g&&(n=t,t=null),n&&"function"!=typeof n&&(n=o.parse),t=p(t),a=!(i=f(e||"")).protocol&&!i.slashes,y.slashes=i.slashes||a&&t.slashes,y.protocol=i.protocol||t.protocol||"",e=i.rest,i.slashes||(v[3]=[/(.*)/,"pathname"]);b=4?[t[0],t[1],t[2],t[3],"".concat(t[0],".").concat(t[1]),"".concat(t[0],".").concat(t[2]),"".concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[0]),"".concat(t[1],".").concat(t[2]),"".concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[1]),"".concat(t[2],".").concat(t[3]),"".concat(t[3],".").concat(t[0]),"".concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[0]),"".concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[1],".").concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[2],".").concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[3],".").concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[2],".").concat(t[1],".").concat(t[0])]:void 0),g[r]}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=e.filter((function(e){return"token"!==e})),o=y(r);return o.reduce((function(e,t){return f()({},e,n[t])}),t)}function _(e){return e.join(" ")}function w(e){var t=e.node,n=e.stylesheet,r=e.style,o=void 0===r?{}:r,a=e.useInlineStyles,i=e.key,s=t.properties,u=t.type,c=t.tagName,l=t.value;if("text"===u)return l;if(c){var p,h=function(e,t){var n=0;return function(r){return n+=1,r.map((function(r,o){return w({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(o)})}))}}(n,a);if(a){var m=Object.keys(n).reduce((function(e,t){return t.split(".").forEach((function(t){e.includes(t)||e.push(t)})),e}),[]),g=s.className&&s.className.includes("token")?["token"]:[],y=s.className&&g.concat(s.className.filter((function(e){return!m.includes(e)})));p=f()({},s,{className:_(y)||void 0,style:b(s.className,Object.assign({},s.style,o),n)})}else p=f()({},s,{className:_(s.className)});var x=h(t.children);return d.a.createElement(c,v()({key:i},p),x)}}var x=/\n/g;function E(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,o=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,i=void 0===a?{}:a,s=e.startingLineNumber;return d.a.createElement("code",{style:Object.assign({},n,o)},function(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map((function(e,t){var o=t+n;return d.a.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(o):r},"".concat(o,"\n"))}))}({lines:t.replace(/\n$/,"").split("\n"),style:i,startingLineNumber:s}))}function S(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function C(e,t,n){var r,o={display:"inline-block",minWidth:(r=n,"".concat(r.toString().length,".25em")),paddingRight:"1em",textAlign:"right",userSelect:"none"},a="function"==typeof e?e(t):e;return f()({},o,a)}function A(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,o=e.largestLineNumber,a=e.showInlineLineNumbers,i=e.lineProps,s=void 0===i?{}:i,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,p=e.wrapLongLines,h="function"==typeof s?s(n):s;if(h.className=c,n&&a){var d=C(r,n,o);t.unshift(S(n,d))}return p&l&&(h.style=f()({},h.style,{display:"flex"})),{type:"element",tagName:"span",properties:h,children:t}}function k(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return A({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:i,showInlineLineNumbers:o,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function m(e,t){if(r&&t&&o){var n=C(s,t,i);e.unshift(S(t,n))}return e}function v(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?d(e,n,r):m(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(t.match(x)){var n=t.split("\n");n.forEach((function(t,o){var i=r&&p.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===o){var u=v(l.slice(f+1,h).concat(A({children:[s],className:e.properties.className})),i);p.push(u)}else if(o===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var c=A({children:[{type:"text",value:"".concat(t)}],className:e.properties.className});l.splice(h+1,0,c)}else{var d=v([s],i,e.properties.className);p.push(d)}}else{var m=v([s],i,e.properties.className);p.push(m)}})),f=h}h++};h .hljs-title":{color:"#88C0D0"},"hljs-keyword":{color:"#81A1C1"},"hljs-literal":{color:"#81A1C1"},"hljs-symbol":{color:"#81A1C1"},"hljs-number":{color:"#B48EAD"},"hljs-regexp":{color:"#EBCB8B"},"hljs-string":{color:"#A3BE8C"},"hljs-title":{color:"#8FBCBB"},"hljs-params":{color:"#D8DEE9"},"hljs-bullet":{color:"#81A1C1"},"hljs-code":{color:"#8FBCBB"},"hljs-emphasis":{fontStyle:"italic"},"hljs-formula":{color:"#8FBCBB"},"hljs-strong":{fontWeight:"bold"},"hljs-link:hover":{textDecoration:"underline"},"hljs-quote":{color:"#4C566A"},"hljs-comment":{color:"#4C566A"},"hljs-doctag":{color:"#8FBCBB"},"hljs-meta":{color:"#5E81AC"},"hljs-meta-keyword":{color:"#5E81AC"},"hljs-meta-string":{color:"#A3BE8C"},"hljs-attr":{color:"#8FBCBB"},"hljs-attribute":{color:"#D8DEE9"},"hljs-builtin-name":{color:"#81A1C1"},"hljs-name":{color:"#81A1C1"},"hljs-section":{color:"#88C0D0"},"hljs-tag":{color:"#81A1C1"},"hljs-variable":{color:"#D8DEE9"},"hljs-template-variable":{color:"#D8DEE9"},"hljs-template-tag":{color:"#5E81AC"},"abnf .hljs-attribute":{color:"#88C0D0"},"abnf .hljs-symbol":{color:"#EBCB8B"},"apache .hljs-attribute":{color:"#88C0D0"},"apache .hljs-section":{color:"#81A1C1"},"arduino .hljs-built_in":{color:"#88C0D0"},"aspectj .hljs-meta":{color:"#D08770"},"aspectj > .hljs-title":{color:"#88C0D0"},"bnf .hljs-attribute":{color:"#8FBCBB"},"clojure .hljs-name":{color:"#88C0D0"},"clojure .hljs-symbol":{color:"#EBCB8B"},"coq .hljs-built_in":{color:"#88C0D0"},"cpp .hljs-meta-string":{color:"#8FBCBB"},"css .hljs-built_in":{color:"#88C0D0"},"css .hljs-keyword":{color:"#D08770"},"diff .hljs-meta":{color:"#8FBCBB"},"ebnf .hljs-attribute":{color:"#8FBCBB"},"glsl .hljs-built_in":{color:"#88C0D0"},"groovy .hljs-meta:not(:first-child)":{color:"#D08770"},"haxe .hljs-meta":{color:"#D08770"},"java .hljs-meta":{color:"#D08770"},"ldif .hljs-attribute":{color:"#8FBCBB"},"lisp .hljs-name":{color:"#88C0D0"},"lua .hljs-built_in":{color:"#88C0D0"},"moonscript .hljs-built_in":{color:"#88C0D0"},"nginx .hljs-attribute":{color:"#88C0D0"},"nginx .hljs-section":{color:"#5E81AC"},"pf .hljs-built_in":{color:"#88C0D0"},"processing .hljs-built_in":{color:"#88C0D0"},"scss .hljs-keyword":{color:"#81A1C1"},"stylus .hljs-keyword":{color:"#81A1C1"},"swift .hljs-meta":{color:"#D08770"},"vim .hljs-built_in":{color:"#88C0D0",fontStyle:"italic"},"yaml .hljs-meta":{color:"#D08770"}},obsidian:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#282b2e",color:"#e0e2e4"},"hljs-keyword":{color:"#93c763",fontWeight:"bold"},"hljs-selector-tag":{color:"#93c763",fontWeight:"bold"},"hljs-literal":{color:"#93c763",fontWeight:"bold"},"hljs-selector-id":{color:"#93c763"},"hljs-number":{color:"#ffcd22"},"hljs-attribute":{color:"#668bb0"},"hljs-code":{color:"white"},"hljs-class .hljs-title":{color:"white"},"hljs-section":{color:"white",fontWeight:"bold"},"hljs-regexp":{color:"#d39745"},"hljs-link":{color:"#d39745"},"hljs-meta":{color:"#557182"},"hljs-tag":{color:"#8cbbad"},"hljs-name":{color:"#8cbbad",fontWeight:"bold"},"hljs-bullet":{color:"#8cbbad"},"hljs-subst":{color:"#8cbbad"},"hljs-emphasis":{color:"#8cbbad"},"hljs-type":{color:"#8cbbad",fontWeight:"bold"},"hljs-built_in":{color:"#8cbbad"},"hljs-selector-attr":{color:"#8cbbad"},"hljs-selector-pseudo":{color:"#8cbbad"},"hljs-addition":{color:"#8cbbad"},"hljs-variable":{color:"#8cbbad"},"hljs-template-tag":{color:"#8cbbad"},"hljs-template-variable":{color:"#8cbbad"},"hljs-string":{color:"#ec7600"},"hljs-symbol":{color:"#ec7600"},"hljs-comment":{color:"#818e96"},"hljs-quote":{color:"#818e96"},"hljs-deletion":{color:"#818e96"},"hljs-selector-class":{color:"#A082BD"},"hljs-doctag":{fontWeight:"bold"},"hljs-title":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"}},"tomorrow-night":{"hljs-comment":{color:"#969896"},"hljs-quote":{color:"#969896"},"hljs-variable":{color:"#cc6666"},"hljs-template-variable":{color:"#cc6666"},"hljs-tag":{color:"#cc6666"},"hljs-name":{color:"#cc6666"},"hljs-selector-id":{color:"#cc6666"},"hljs-selector-class":{color:"#cc6666"},"hljs-regexp":{color:"#cc6666"},"hljs-deletion":{color:"#cc6666"},"hljs-number":{color:"#de935f"},"hljs-built_in":{color:"#de935f"},"hljs-builtin-name":{color:"#de935f"},"hljs-literal":{color:"#de935f"},"hljs-type":{color:"#de935f"},"hljs-params":{color:"#de935f"},"hljs-meta":{color:"#de935f"},"hljs-link":{color:"#de935f"},"hljs-attribute":{color:"#f0c674"},"hljs-string":{color:"#b5bd68"},"hljs-symbol":{color:"#b5bd68"},"hljs-bullet":{color:"#b5bd68"},"hljs-addition":{color:"#b5bd68"},"hljs-title":{color:"#81a2be"},"hljs-section":{color:"#81a2be"},"hljs-keyword":{color:"#b294bb"},"hljs-selector-tag":{color:"#b294bb"},hljs:{display:"block",overflowX:"auto",background:"#1d1f21",color:"#c5c8c6",padding:"0.5em"},"hljs-emphasis":{fontStyle:"italic"},"hljs-strong":{fontWeight:"bold"}}},Q=o()(X),ee=function(e){return i()(Q).call(Q,e)?X[e]:(console.warn("Request style '".concat(e,"' is not available, returning default instead")),Z)}},function(e,t){e.exports=!0},function(e,t,n){var r=n(237),o=n(68).f,a=n(67),i=n(55),s=n(548),u=n(41)("toStringTag");e.exports=function(e,t,n,c){if(e){var l=n?e:e.prototype;i(l,u)||o(l,u,{configurable:!0,value:t}),c&&!r&&a(l,"toString",s)}}},function(e,t,n){var r=n(237),o=n(151),a=n(41)("toStringTag"),i="Arguments"==o(function(){return arguments}());e.exports=r?o:function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),a))?n:i?o(t):"Object"==(r=o(t))&&"function"==typeof t.callee?"Arguments":r}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return e}},function(e,t,n){e.exports=n(679)},function(e,t,n){"use strict";function r(e){return function(e){try{return!!JSON.parse(e)}catch(e){return null}}(e)?"json":null}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_LAYOUT",(function(){return o})),n.d(t,"UPDATE_FILTER",(function(){return a})),n.d(t,"UPDATE_MODE",(function(){return i})),n.d(t,"SHOW",(function(){return s})),n.d(t,"updateLayout",(function(){return u})),n.d(t,"updateFilter",(function(){return c})),n.d(t,"show",(function(){return l})),n.d(t,"changeMode",(function(){return p}));var r=n(5),o="layout_update_layout",a="layout_update_filter",i="layout_update_mode",s="layout_show";function u(e){return{type:o,payload:e}}function c(e){return{type:a,payload:e}}function l(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e=Object(r.v)(e),{type:s,payload:{thing:e,shown:t}}}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=Object(r.v)(e),{type:i,payload:{thing:e,mode:t}}}},function(e,t,n){var r=n(421),o=n(161),a=n(192),i=n(50),s=n(115),u=n(193),c=n(160),l=n(249),p=Object.prototype.hasOwnProperty;e.exports=function(e){if(null==e)return!0;if(s(e)&&(i(e)||"string"==typeof e||"function"==typeof e.splice||u(e)||l(e)||a(e)))return!e.length;var t=o(e);if("[object Map]"==t||"[object Set]"==t)return!e.size;if(c(e))return!r(e).length;for(var n in e)if(p.call(e,n))return!1;return!0}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(77);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){var r=n(70);e.exports=r("navigator","userAgent")||""},function(e,t,n){var r,o=n(52),a=n(230),i=n(233),s=n(156),u=n(366),c=n(225),l=n(181),p=l("IE_PROTO"),f=function(){},h=function(e){return"