updated code.
1. Resolved merge conflicts. 2. Resolved go linting issues.
This commit is contained in:
@@ -25,12 +25,12 @@ type Config struct {
|
||||
Log log.Config `yaml:"log"`
|
||||
PluginManager *plugin.ManagerConfig `yaml:"pluginManager"`
|
||||
Modules []module.Config `yaml:"modules"`
|
||||
HTTP timeouts `yaml:"http"` // Nest http config
|
||||
HTTP timeouts `yaml:"http"`
|
||||
}
|
||||
|
||||
type timeouts struct {
|
||||
Port string `yaml:"port"`
|
||||
Timeout timeoutConfig `yaml:"timeout"`
|
||||
Port string `yaml:"port"`
|
||||
Timeouts timeoutConfig `yaml:"timeout"`
|
||||
}
|
||||
|
||||
type timeoutConfig struct {
|
||||
@@ -138,9 +138,9 @@ func run(ctx context.Context, configPath string) error {
|
||||
httpServer := &http.Server{
|
||||
Addr: net.JoinHostPort("", cfg.HTTP.Port),
|
||||
Handler: srv,
|
||||
ReadTimeout: cfg.HTTP.Timeout.Read * time.Second, // Use timeouts from config
|
||||
WriteTimeout: cfg.HTTP.Timeout.Write * time.Second,
|
||||
IdleTimeout: cfg.HTTP.Timeout.Idle * time.Second,
|
||||
ReadTimeout: cfg.HTTP.Timeouts.Read * time.Second,
|
||||
WriteTimeout: cfg.HTTP.Timeouts.Write * time.Second,
|
||||
IdleTimeout: cfg.HTTP.Timeouts.Idle * time.Second,
|
||||
}
|
||||
|
||||
// Start HTTP server.
|
||||
|
||||
@@ -366,7 +366,7 @@ func TestNewServerSuccess(t *testing.T) {
|
||||
Modules: tt.modules,
|
||||
HTTP: timeouts{
|
||||
Port: "8080",
|
||||
Timeout: timeoutConfig{
|
||||
Timeouts: timeoutConfig{
|
||||
Read: 5,
|
||||
Write: 5,
|
||||
Idle: 10,
|
||||
@@ -411,7 +411,7 @@ func TestNewServerFailure(t *testing.T) {
|
||||
Modules: tt.modules,
|
||||
HTTP: timeouts{
|
||||
Port: "8080",
|
||||
Timeout: timeoutConfig{
|
||||
Timeouts: timeoutConfig{
|
||||
Read: 5,
|
||||
Write: 5,
|
||||
Idle: 10,
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
appName: "bapAdapter"
|
||||
log:
|
||||
level: debug
|
||||
destinations:
|
||||
- type: stdout
|
||||
context_keys:
|
||||
- transaction_id
|
||||
- message_id
|
||||
http:
|
||||
port: 8080
|
||||
timeout:
|
||||
read: 30
|
||||
write: 30
|
||||
idle: 30
|
||||
plugin:
|
||||
root: /app/plugins
|
||||
pluginZipPath: /mnt/gcs/plugins/plugins_bundle.zip
|
||||
plugins:
|
||||
- publisher Src version raw comp zip
|
||||
- nopschemavalidator
|
||||
- router
|
||||
- nopsigner
|
||||
- nopsignvalidator
|
||||
- reqpreprocessor
|
||||
- gcpAuthMdw
|
||||
modules:
|
||||
- name: reciever
|
||||
type: transaction
|
||||
path: /reciever
|
||||
targetType: msgQ
|
||||
plugin:
|
||||
schemaValidator:
|
||||
id: nopschemavalidator
|
||||
signValidator:
|
||||
id: nopsignvalidator
|
||||
publisher:
|
||||
id: publisher
|
||||
config:
|
||||
project: ondc-seller-dev
|
||||
topic: bapNetworkReciever
|
||||
router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: /mnt/gcs/configs/bapRecieverRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
steps:
|
||||
steps:
|
||||
- addRoute
|
||||
signValidate
|
||||
-addRout
|
||||
customValidate
|
||||
- name: transactionCaller
|
||||
path: /caller
|
||||
targetType: "http"
|
||||
plugin:
|
||||
signer:
|
||||
id: nopsigner
|
||||
router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: /mnt/gcs/configs/bapCallerRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
# postProcessors:
|
||||
# - id: gcpAuthMdw
|
||||
# config:
|
||||
# audience: https://bpp-adapter-903496459467.asia-southeast1.run.app
|
||||
# serviceAccount: 903496459467-compute@developer.gserviceaccount.com
|
||||
@@ -1,3 +0,0 @@
|
||||
routes:
|
||||
- action: search
|
||||
target: https://bpp-adapter-903496459467.asia-southeast1.run.app/reciever
|
||||
@@ -1,63 +0,0 @@
|
||||
appName: "bppClientService"
|
||||
log:
|
||||
level: debug
|
||||
destinations:
|
||||
- type: stdout
|
||||
context_keys:
|
||||
- transaction_id
|
||||
- message_id
|
||||
http:
|
||||
port: 8080
|
||||
timeout:
|
||||
read: 30
|
||||
write: 30
|
||||
idle: 30
|
||||
plugin:
|
||||
root: extracted/plugins
|
||||
pluginZipPath: plugins_bundle.zip
|
||||
plugins:
|
||||
- publisher
|
||||
- nopschemavalidator
|
||||
- router
|
||||
- nopsigner
|
||||
- nopsignvalidator
|
||||
- reqpreprocessor
|
||||
- gcpAuthMdw
|
||||
module:
|
||||
modules:
|
||||
- name: transactionReciever
|
||||
path: /reciever
|
||||
targetType: msgQ
|
||||
plugin:
|
||||
schemaValidator:
|
||||
id: nopschemavalidator
|
||||
signValidator:
|
||||
id: nopsignValidator
|
||||
publisher:
|
||||
id: publisher
|
||||
config:
|
||||
project: ondc-seller-dev
|
||||
topic: clientSideTopic
|
||||
Router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: configs/bppRecieverRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
- name: transactionCaller
|
||||
path: /caller
|
||||
targetType: "http"
|
||||
plugin:
|
||||
signer:
|
||||
id: nopsigner
|
||||
Router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: configs/bppCallerRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
postProcessors:
|
||||
- id: gcpAuthMdw
|
||||
config:
|
||||
audience: "target"
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
appName: "bppClientService"
|
||||
log:
|
||||
level: debug
|
||||
destinations:
|
||||
- type: stdout
|
||||
context_keys:
|
||||
- transaction_id
|
||||
- message_id
|
||||
http:
|
||||
port: 8080
|
||||
timeout:
|
||||
read: 30
|
||||
write: 30
|
||||
idle: 30
|
||||
plugin:
|
||||
root: /app/plugins
|
||||
pluginZipPath: /mnt/gcs/plugins/plugins_bundle.zip
|
||||
plugins:
|
||||
- publisher
|
||||
- nopschemavalidator
|
||||
- router
|
||||
- nopsigner
|
||||
- nopsignvalidator
|
||||
- reqpreprocessor
|
||||
- gcpAuthMdw
|
||||
module:
|
||||
modules:
|
||||
- name: transactionReciever
|
||||
path: /reciever
|
||||
targetType: msgQ
|
||||
plugin:
|
||||
schemaValidator:
|
||||
id: nopschemavalidator
|
||||
signValidator:
|
||||
id: nopsignvalidator
|
||||
publisher:
|
||||
id: publisher
|
||||
config:
|
||||
project: ondc-seller-dev
|
||||
topic: bppNetworkReciever
|
||||
router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: /mnt/gcs/configs/bppRecieverRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
- name: transactionCaller
|
||||
path: /caller
|
||||
targetType: "http"
|
||||
plugin:
|
||||
signer:
|
||||
id: nopsigner
|
||||
router:
|
||||
id: router
|
||||
config:
|
||||
routingConfigPath: /mnt/gcs/configs/bppCallerRouting-config.yaml
|
||||
preProcessors:
|
||||
- id: reqpreprocessor
|
||||
# postProcessors:
|
||||
# - id: gcpAuthMdw
|
||||
# config:
|
||||
# audience: https://bap-adapter-903496459467.asia-southeast1.run.app
|
||||
# serviceAccount: 903496459467-compute@developer.gserviceaccount.com
|
||||
@@ -1,3 +0,0 @@
|
||||
routes:
|
||||
- action: on_search
|
||||
target: targeturl
|
||||
@@ -1,3 +0,0 @@
|
||||
routes:
|
||||
- action: search
|
||||
target: https://sellerapp-903496459467.asia-southeast1.run.app
|
||||
@@ -1,2 +0,0 @@
|
||||
bap_url: "https://bap-csr-903496459467.asia-southeast1.run.app" # Replace with actual Beckn API endpoint
|
||||
port: "8080" # The port on which the server will run
|
||||
@@ -1,69 +0,0 @@
|
||||
- id: pooja-stores
|
||||
descriptor:
|
||||
name: Pooja Stores
|
||||
locations:
|
||||
- id: koramangala-4th-block-location
|
||||
gps: "12.9349377,77.6055586"
|
||||
categories:
|
||||
- id: fresh_fruits
|
||||
descriptor:
|
||||
name: Fresh Fruits
|
||||
- id: beverages
|
||||
descriptor:
|
||||
name: Beverages
|
||||
items:
|
||||
- id: item_2
|
||||
descriptor:
|
||||
name: Green Apples Organic
|
||||
images:
|
||||
- url: "https://mock_bpp.com/images/item_2.jpg"
|
||||
category_id: fresh_fruits
|
||||
location_id: koramangala-4th-block-location
|
||||
price:
|
||||
currency: INR
|
||||
value: "170"
|
||||
matched: true
|
||||
- id: item_1
|
||||
descriptor:
|
||||
name: Red Apples
|
||||
images:
|
||||
- url: "https://mock_bpp.com/images/item_1.jpg"
|
||||
category_id: fresh_fruits
|
||||
location_id: koramangala-4th-block-location
|
||||
price:
|
||||
currency: INR
|
||||
value: "90"
|
||||
related: true
|
||||
- id: item_7
|
||||
descriptor:
|
||||
name: Green Apple Juice
|
||||
images:
|
||||
- url: "https://mock_bpp.com/images/item_7.jpg"
|
||||
category_id: beverages
|
||||
location_id: koramangala-4th-block-location
|
||||
price:
|
||||
currency: INR
|
||||
value: "70"
|
||||
matched: true
|
||||
- id: food-mall
|
||||
descriptor:
|
||||
name: Food Mall
|
||||
locations:
|
||||
- id: food-mall-location
|
||||
gps: "12.9349377,77.6055586"
|
||||
categories:
|
||||
- id: fresh-food
|
||||
descriptor:
|
||||
name: Fresh food
|
||||
items:
|
||||
- id: item_1_1
|
||||
descriptor:
|
||||
name: Green Apple Salad
|
||||
images:
|
||||
- url: "https://mock_bpp.com/images/item_1_1.jpg"
|
||||
category_id: fresh-food
|
||||
location_id: food-mall-location
|
||||
price:
|
||||
currency: INR
|
||||
value: "200"
|
||||
matched: true
|
||||
@@ -24,7 +24,7 @@ type Config struct {
|
||||
// RegisteryClient encapsulates the logic for calling the subscribe and lookup endpoints.
|
||||
type RegisteryClient struct {
|
||||
Config *Config
|
||||
Client *retryablehttp.Client // Retryable HTTP Client
|
||||
Client *retryablehttp.Client
|
||||
}
|
||||
|
||||
// NewRegisteryClient creates a new instance of Client.
|
||||
|
||||
@@ -2,7 +2,6 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/beckn/beckn-onix/pkg/model"
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
"github.com/beckn/beckn-onix/pkg/plugin/definition"
|
||||
)
|
||||
|
||||
// PluginManager defines the methods required for managing plugins in stdHandler.
|
||||
// PluginManager defines an interface for managing plugins dynamically.
|
||||
type PluginManager interface {
|
||||
Middleware(ctx context.Context, cfg *plugin.Config) (func(http.Handler) http.Handler, error)
|
||||
SignValidator(ctx context.Context, cfg *plugin.Config) (definition.Verifier, error)
|
||||
@@ -53,45 +52,4 @@ type Config struct {
|
||||
RegistryURL string `yaml:"registryUrl"`
|
||||
Role model.Role
|
||||
SubscriberID string `yaml:"subscriberId"`
|
||||
Trace map[string]bool
|
||||
}
|
||||
|
||||
// Step represents a named processing step.
|
||||
type Step string
|
||||
|
||||
const (
|
||||
// StepInitialize represents the initialization phase of the request processing pipeline.
|
||||
StepInitialize Step = "initialize"
|
||||
|
||||
// StepValidate represents the validation phase, where input data is checked for correctness.
|
||||
StepValidate Step = "validate"
|
||||
|
||||
// StepProcess represents the core processing phase of the request.
|
||||
StepProcess Step = "process"
|
||||
|
||||
// StepFinalize represents the finalization phase, where the response is prepared and sent.
|
||||
StepFinalize Step = "finalize"
|
||||
)
|
||||
|
||||
// validSteps ensures only allowed step values are used.
|
||||
var validSteps = map[Step]bool{
|
||||
StepInitialize: true,
|
||||
StepValidate: true,
|
||||
StepProcess: true,
|
||||
StepFinalize: true,
|
||||
}
|
||||
|
||||
// UnmarshalYAML customizes YAML unmarshalling for Step to enforce valid values.
|
||||
func (s *Step) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var stepName string
|
||||
if err := unmarshal(&stepName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
step := Step(stepName)
|
||||
if !validSteps[step] {
|
||||
return fmt.Errorf("invalid step: %s", stepName)
|
||||
}
|
||||
*s = step
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ func NewStdHandler(ctx context.Context, mgr PluginManager, cfg *Config) (http.Ha
|
||||
SubscriberID: cfg.SubscriberID,
|
||||
role: cfg.Role,
|
||||
}
|
||||
// Initialize plugins
|
||||
// Initialize plugins.
|
||||
if err := h.initPlugins(ctx, mgr, &cfg.Plugins, cfg.RegistryURL); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize plugins: %w", err)
|
||||
}
|
||||
// Initialize steps
|
||||
// Initialize steps.
|
||||
if err := h.initSteps(ctx, mgr, cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize steps: %w", err)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func (h *stdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
log.Request(r.Context(), r, ctx.Body)
|
||||
|
||||
// Execute processing steps
|
||||
// Execute processing steps.
|
||||
for _, step := range h.steps {
|
||||
if err := step.Run(ctx); err != nil {
|
||||
log.Errorf(ctx, err, "%T.run(%v):%v", step, ctx, err)
|
||||
@@ -67,14 +67,14 @@ func (h *stdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Restore request body before forwarding or publishing
|
||||
// Restore request body before forwarding or publishing.
|
||||
r.Body = io.NopCloser(bytes.NewReader(ctx.Body))
|
||||
if ctx.Route == nil {
|
||||
response.SendAck(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle routing based on the defined route type
|
||||
// Handle routing based on the defined route type.
|
||||
route(ctx, r, w, h.publisher)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -74,17 +73,17 @@ func (s *validateSignStep) Run(ctx *model.StepContext) error {
|
||||
if len(headerValue) != 0 {
|
||||
if err := s.validate(ctx, headerValue); err != nil {
|
||||
ctx.RespHeader.Set(model.UnaAuthorizedHeaderGateway, unauthHeader)
|
||||
return model.NewSignValidationErrf("failed to validate %s: %w", model.AuthHeaderGateway, err)
|
||||
return model.NewSignValidationErr(fmt.Errorf("failed to validate %s: %w", model.AuthHeaderGateway, err))
|
||||
}
|
||||
}
|
||||
headerValue = ctx.Request.Header.Get(model.AuthHeaderSubscriber)
|
||||
if len(headerValue) == 0 {
|
||||
ctx.RespHeader.Set(model.UnaAuthorizedHeaderSubscriber, unauthHeader)
|
||||
return model.NewSignValidationErrf("%s missing", model.UnaAuthorizedHeaderSubscriber)
|
||||
return model.NewSignValidationErr(fmt.Errorf("%s missing", model.UnaAuthorizedHeaderSubscriber))
|
||||
}
|
||||
if err := s.validate(ctx, headerValue); err != nil {
|
||||
ctx.RespHeader.Set(model.UnaAuthorizedHeaderSubscriber, unauthHeader)
|
||||
return model.NewSignValidationErrf("failed to validate %s: %w", model.AuthHeaderSubscriber, err)
|
||||
return model.NewSignValidationErr(fmt.Errorf("failed to validate %s: %w", model.AuthHeaderSubscriber, err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -113,15 +112,6 @@ type validateSchemaStep struct {
|
||||
validator definition.SchemaValidator
|
||||
}
|
||||
|
||||
// newValidateSchemaStep creates and returns the validateSchema step after validation
|
||||
func newValidateSchemaStep(schemaValidator definition.SchemaValidator) (definition.Step, error) {
|
||||
if schemaValidator == nil {
|
||||
return nil, fmt.Errorf("invalid config: SchemaValidator plugin not configured")
|
||||
}
|
||||
log.Debug(context.Background(), "adding schema validator")
|
||||
return &validateSchemaStep{validator: schemaValidator}, nil
|
||||
}
|
||||
|
||||
// Run executes the schema validation step.
|
||||
func (s *validateSchemaStep) Run(ctx *model.StepContext) error {
|
||||
if err := s.validator.Validate(ctx, ctx.Request.URL, ctx.Body); err != nil {
|
||||
@@ -135,14 +125,6 @@ type addRouteStep struct {
|
||||
router definition.Router
|
||||
}
|
||||
|
||||
// newRouteStep initializes and returns a new routing step.
|
||||
func newRouteStep(router definition.Router) (definition.Step, error) {
|
||||
if router == nil {
|
||||
return nil, fmt.Errorf("invalid config: Router plugin not configured")
|
||||
}
|
||||
return &addRouteStep{router: router}, nil
|
||||
}
|
||||
|
||||
// Run executes the routing step.
|
||||
func (s *addRouteStep) Run(ctx *model.StepContext) error {
|
||||
route, err := s.router.Route(ctx, ctx.Request.URL, ctx.Body)
|
||||
@@ -150,8 +132,5 @@ func (s *addRouteStep) Run(ctx *model.StepContext) error {
|
||||
return fmt.Errorf("failed to determine route: %w", err)
|
||||
}
|
||||
log.Debugf(ctx, "Routing to %#v", route)
|
||||
ctx.Route = route
|
||||
|
||||
log.Debugf(ctx, "ctx.Route to %#v", ctx.Route)
|
||||
return nil
|
||||
}
|
||||
|
||||
8
go.mod
8
go.mod
@@ -27,9 +27,15 @@ require (
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.31.0 // indirect
|
||||
require (
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7
|
||||
github.com/rs/zerolog v1.34.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
13
go.sum
13
go.sum
@@ -1,3 +1,4 @@
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -5,6 +6,7 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
@@ -22,14 +24,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
@@ -40,6 +48,9 @@ github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03 h1:m1h+vudopHsI67F
|
||||
github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03/go.mod h1:8sheVFH84v3PCyFY/O02mIgSQY9I6wMYPWsq7mDnEZY=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
@@ -47,6 +58,8 @@ golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
@@ -25,11 +25,13 @@ type destination struct {
|
||||
Config map[string]string `yaml:"config"`
|
||||
}
|
||||
|
||||
// Destination types for logging output.
|
||||
const (
|
||||
Stdout destinationType = "stdout"
|
||||
File destinationType = "file"
|
||||
)
|
||||
|
||||
// Log levels define the severity of log messages.
|
||||
const (
|
||||
DebugLevel level = "debug"
|
||||
InfoLevel level = "info"
|
||||
@@ -48,6 +50,7 @@ var logLevels = map[level]zerolog.Level{
|
||||
PanicLevel: zerolog.PanicLevel,
|
||||
}
|
||||
|
||||
// Config represents the configuration for logging.
|
||||
type Config struct {
|
||||
Level level `yaml:"level"`
|
||||
Destinations []destination `yaml:"destinations"`
|
||||
@@ -60,6 +63,7 @@ var (
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// Logger instance and configuration.
|
||||
var (
|
||||
ErrInvalidLogLevel = errors.New("invalid log level")
|
||||
ErrLogDestinationNil = errors.New("log Destinations cant be empty")
|
||||
@@ -163,6 +167,8 @@ func getLogger(config Config) (zerolog.Logger, error) {
|
||||
return newLogger, nil
|
||||
}
|
||||
|
||||
// InitLogger initializes the logger with the given configuration.
|
||||
// It ensures that the logger is initialized only once using sync.Once.
|
||||
func InitLogger(c Config) error {
|
||||
var initErr error
|
||||
once.Do(func() {
|
||||
@@ -175,60 +181,74 @@ func InitLogger(c Config) error {
|
||||
return initErr
|
||||
}
|
||||
|
||||
// Debug logs a debug-level message with the provided context.
|
||||
func Debug(ctx context.Context, msg string) {
|
||||
logEvent(ctx, zerolog.DebugLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Debugf logs a formatted debug-level message with the provided context.
|
||||
func Debugf(ctx context.Context, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.DebugLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Info logs an info-level message with the provided context.
|
||||
func Info(ctx context.Context, msg string) {
|
||||
logEvent(ctx, zerolog.InfoLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Infof logs a formatted info-level message with the provided context.
|
||||
func Infof(ctx context.Context, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.InfoLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Warn logs a warning-level message with the provided context.
|
||||
func Warn(ctx context.Context, msg string) {
|
||||
logEvent(ctx, zerolog.WarnLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Warnf logs a formatted warning-level message with the provided context.
|
||||
func Warnf(ctx context.Context, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.WarnLevel, msg, nil)
|
||||
}
|
||||
|
||||
// Error logs an error-level message along with an error object.
|
||||
func Error(ctx context.Context, err error, msg string) {
|
||||
logEvent(ctx, zerolog.ErrorLevel, msg, err)
|
||||
}
|
||||
|
||||
// Errorf logs a formatted error-level message along with an error object.
|
||||
func Errorf(ctx context.Context, err error, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.ErrorLevel, msg, err)
|
||||
}
|
||||
|
||||
// Fatal logs a fatal-level message along with an error object and exits the application.
|
||||
func Fatal(ctx context.Context, err error, msg string) {
|
||||
logEvent(ctx, zerolog.FatalLevel, msg, err)
|
||||
}
|
||||
|
||||
// Fatalf logs a formatted fatal-level message along with an error object and exits the application.
|
||||
func Fatalf(ctx context.Context, err error, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.FatalLevel, msg, err)
|
||||
}
|
||||
|
||||
// Panic logs a panic-level message along with an error object and panics.
|
||||
func Panic(ctx context.Context, err error, msg string) {
|
||||
logEvent(ctx, zerolog.PanicLevel, msg, err)
|
||||
}
|
||||
|
||||
// Panicf logs a formatted panic-level message along with an error object and panics.
|
||||
func Panicf(ctx context.Context, err error, format string, v ...any) {
|
||||
msg := fmt.Sprintf(format, v...)
|
||||
logEvent(ctx, zerolog.PanicLevel, msg, err)
|
||||
}
|
||||
|
||||
// logEvent logs an event at the specified log level with an optional error message.
|
||||
// It adds contextual information before logging the message.
|
||||
func logEvent(ctx context.Context, level zerolog.Level, msg string, err error) {
|
||||
event := logger.WithLevel(level)
|
||||
|
||||
@@ -239,6 +259,7 @@ func logEvent(ctx context.Context, level zerolog.Level, msg string, err error) {
|
||||
event.Msg(msg)
|
||||
}
|
||||
|
||||
// Request logs details of an incoming HTTP request, including method, URL, body, and remote address.
|
||||
func Request(ctx context.Context, r *http.Request, body []byte) {
|
||||
event := logger.Info()
|
||||
addCtx(ctx, event)
|
||||
@@ -249,6 +270,7 @@ func Request(ctx context.Context, r *http.Request, body []byte) {
|
||||
Msg("HTTP Request")
|
||||
}
|
||||
|
||||
// addCtx adds context values to the log event based on configured context keys.
|
||||
func addCtx(ctx context.Context, event *zerolog.Event) {
|
||||
for _, key := range cfg.ContextKeys {
|
||||
val, ok := ctx.Value(key).(string)
|
||||
@@ -260,6 +282,7 @@ func addCtx(ctx context.Context, event *zerolog.Event) {
|
||||
}
|
||||
}
|
||||
|
||||
// Response logs details of an outgoing HTTP response, including method, URL, status code, and response time.
|
||||
func Response(ctx context.Context, r *http.Request, statusCode int, responseTime time.Duration) {
|
||||
event := logger.Info()
|
||||
addCtx(ctx, event)
|
||||
|
||||
@@ -40,14 +40,20 @@ const (
|
||||
|
||||
type contextKey string
|
||||
|
||||
// MsgIDKey is the context key used to store and retrieve the message ID in a request context.
|
||||
const MsgIDKey = contextKey("message_id")
|
||||
|
||||
// Role defines the type of participant in the network.
|
||||
type Role string
|
||||
|
||||
const (
|
||||
RoleBAP Role = "bap"
|
||||
RoleBPP Role = "bpp"
|
||||
RoleGateway Role = "gateway"
|
||||
// RoleBAP represents a Buyer App Participant (BAP) in the network.
|
||||
RoleBAP Role = "bap"
|
||||
// RoleBPP represents a Buyer Platform Participant (BPP) in the network.
|
||||
RoleBPP Role = "bpp"
|
||||
// RoleGateway represents a Gateway that facilitates communication in the network.
|
||||
RoleGateway Role = "gateway"
|
||||
// RoleRegistery represents the Registry that maintains network participant details.
|
||||
RoleRegistery Role = "registery"
|
||||
)
|
||||
|
||||
@@ -91,22 +97,32 @@ type StepContext struct {
|
||||
RespHeader http.Header
|
||||
}
|
||||
|
||||
// WithContext updates the existing StepContext with a new context.
|
||||
func (ctx *StepContext) WithContext(newCtx context.Context) {
|
||||
ctx.Context = newCtx
|
||||
}
|
||||
|
||||
// Status represents the acknowledgment status in a response.
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusACK Status = "ACK"
|
||||
// StatusACK indicates a successful acknowledgment.
|
||||
StatusACK Status = "ACK"
|
||||
// StatusNACK indicates a negative acknowledgment or failure.
|
||||
StatusNACK Status = "NACK"
|
||||
)
|
||||
|
||||
// Ack represents an acknowledgment response.
|
||||
type Ack struct {
|
||||
// Status holds the acknowledgment status (ACK/NACK).
|
||||
Status Status `json:"status"`
|
||||
}
|
||||
|
||||
// Message represents the structure of a response message.
|
||||
type Message struct {
|
||||
Ack Ack `json:"ack"`
|
||||
// Ack contains the acknowledgment status.
|
||||
Ack Ack `json:"ack"`
|
||||
// Error holds error details, if any, in the response.
|
||||
Error *Error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
|
||||
definition "github.com/beckn/beckn-onix/pkg/plugin/definition"
|
||||
schemaValidator "github.com/beckn/beckn-onix/pkg/plugin/implementation/schemaValidator"
|
||||
schemaValidator "github.com/beckn/beckn-onix/pkg/plugin/implementation/schemavalidator"
|
||||
)
|
||||
|
||||
// schemaValidatorProvider provides instances of schemaValidator.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package schemaValidator
|
||||
package schemavalidator
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package schemaValidator
|
||||
package schemavalidator
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
@@ -149,8 +149,15 @@ func (m *Manager) Router(ctx context.Context, cfg *Config) (definition.Router, e
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load provider for %s: %w", cfg.ID, err)
|
||||
}
|
||||
return rp.New(ctx, cfg.Config)
|
||||
|
||||
router, closer, err := rp.New(ctx, cfg.Config)
|
||||
if closer != nil {
|
||||
m.addCloser(func() {
|
||||
if err := closer(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
return router, nil
|
||||
}
|
||||
|
||||
func (m *Manager) Middleware(ctx context.Context, cfg *Config) (func(http.Handler) http.Handler, error) {
|
||||
|
||||
@@ -12,10 +12,16 @@ import (
|
||||
"github.com/beckn/beckn-onix/pkg/model"
|
||||
)
|
||||
|
||||
// Error represents a standardized error response used across the system.
|
||||
type Error struct {
|
||||
Code string `json:"code,omitempty"`
|
||||
// Code is a short, machine-readable error code.
|
||||
Code string `json:"code,omitempty"`
|
||||
|
||||
// Message provides a human-readable description of the error.
|
||||
Message string `json:"message,omitempty"`
|
||||
Paths string `json:"paths,omitempty"`
|
||||
|
||||
// Paths indicates the specific field(s) or endpoint(s) related to the error.
|
||||
Paths string `json:"paths,omitempty"`
|
||||
}
|
||||
|
||||
// SchemaValidationErr represents a collection of schema validation failures.
|
||||
@@ -32,13 +38,18 @@ func (e *SchemaValidationErr) Error() string {
|
||||
return strings.Join(errorMessages, "; ")
|
||||
}
|
||||
|
||||
// Message represents a standard message structure with acknowledgment and error information.
|
||||
type Message struct {
|
||||
// Ack contains the acknowledgment status of the response.
|
||||
Ack struct {
|
||||
Status string `json:"status,omitempty"`
|
||||
} `json:"ack,omitempty"`
|
||||
|
||||
// Error holds error details if any occurred during processing.
|
||||
Error *Error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SendAck sends an acknowledgment response (ACK) to the client.
|
||||
func SendAck(w http.ResponseWriter) {
|
||||
resp := &model.Response{
|
||||
Message: model.Message{
|
||||
@@ -59,7 +70,8 @@ func SendAck(w http.ResponseWriter) {
|
||||
}
|
||||
}
|
||||
|
||||
func nack(w http.ResponseWriter, err *model.Error, status int, ctx context.Context) {
|
||||
// nack sends a negative acknowledgment (NACK) response with an error message.
|
||||
func nack(ctx context.Context, w http.ResponseWriter, err *model.Error, status int) {
|
||||
resp := &model.Response{
|
||||
Message: model.Message{
|
||||
Ack: model.Ack{
|
||||
@@ -80,6 +92,7 @@ func nack(w http.ResponseWriter, err *model.Error, status int, ctx context.Conte
|
||||
}
|
||||
}
|
||||
|
||||
// internalServerError generates an internal server error response.
|
||||
func internalServerError(ctx context.Context) *model.Error {
|
||||
return &model.Error{
|
||||
Code: http.StatusText(http.StatusInternalServerError),
|
||||
@@ -87,6 +100,7 @@ func internalServerError(ctx context.Context) *model.Error {
|
||||
}
|
||||
}
|
||||
|
||||
// SendNack processes different types of errors and sends an appropriate NACK response.
|
||||
func SendNack(ctx context.Context, w http.ResponseWriter, err error) {
|
||||
var schemaErr *model.SchemaValidationErr
|
||||
var signErr *model.SignValidationErr
|
||||
@@ -95,19 +109,19 @@ func SendNack(ctx context.Context, w http.ResponseWriter, err error) {
|
||||
|
||||
switch {
|
||||
case errors.As(err, &schemaErr):
|
||||
nack(w, schemaErr.BecknError(), http.StatusBadRequest, ctx)
|
||||
nack(ctx, w, schemaErr.BecknError(), http.StatusBadRequest)
|
||||
return
|
||||
case errors.As(err, &signErr):
|
||||
nack(w, signErr.BecknError(), http.StatusUnauthorized, ctx)
|
||||
nack(ctx, w, signErr.BecknError(), http.StatusUnauthorized)
|
||||
return
|
||||
case errors.As(err, &badReqErr):
|
||||
nack(w, badReqErr.BecknError(), http.StatusBadRequest, ctx)
|
||||
nack(ctx, w, badReqErr.BecknError(), http.StatusBadRequest)
|
||||
return
|
||||
case errors.As(err, ¬FoundErr):
|
||||
nack(w, notFoundErr.BecknError(), http.StatusNotFound, ctx)
|
||||
nack(ctx, w, notFoundErr.BecknError(), http.StatusNotFound)
|
||||
return
|
||||
default:
|
||||
nack(w, internalServerError(ctx), http.StatusInternalServerError, ctx)
|
||||
nack(ctx, w, internalServerError(ctx), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ func TestNack_1(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
nack(w, tt.err, tt.status, ctx)
|
||||
nack(ctx, w, tt.err, tt.status)
|
||||
if !tt.useBadWrite {
|
||||
recorder, ok := w.(*httptest.ResponseRecorder)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user