diff --git a/pkg/plugin/controllx/builder.go b/pkg/plugin/controllx/builder.go index 7f92e71e..b0d61917 100644 --- a/pkg/plugin/controllx/builder.go +++ b/pkg/plugin/controllx/builder.go @@ -5,6 +5,7 @@ import ( "github.com/siyul-park/uniflow/pkg/scheme" ) +// AddToScheme returns a function that adds types and codecs to the provided scheme. func AddToScheme() func(*scheme.Scheme) error { return func(s *scheme.Scheme) error { s.AddKnownType(KindSnippet, &SnippetSpec{}) diff --git a/pkg/plugin/controllx/snippet.go b/pkg/plugin/controllx/snippet.go index de93a671..899ad470 100644 --- a/pkg/plugin/controllx/snippet.go +++ b/pkg/plugin/controllx/snippet.go @@ -19,31 +19,30 @@ import ( "github.com/xiatechs/jsonata-go" ) -type ( - SnippetNodeConfig struct { - ID ulid.ULID - Lang string - Code string - } - - SnippetNode struct { - *node.OneToOneNode - run func(any) (any, error) - } +// SnippetNodeConfig holds the configuration for creating a SnippetNode. +type SnippetNodeConfig struct { + ID ulid.ULID + Lang string + Code string +} - SnippetSpec struct { - scheme.SpecMeta `map:",inline"` - Lang string `map:"lang"` - Code string `map:"code"` - } +// SnippetNode represents a node that runs a snippet of code. +type SnippetNode struct { + *node.OneToOneNode + run func(any) (any, error) +} - fieldNameMapper struct{} -) +// SnippetSpec represents the specification for the SnippetNode. +type SnippetSpec struct { + scheme.SpecMeta `map:",inline"` + Lang string `map:"lang"` + Code string `map:"code"` +} -const ( - KindSnippet = "snippet" -) +// KindSnippet is the kind identifier for SnippetNode. +const KindSnippet = "snippet" +// Supported programming languages for snippets. const ( LangTypescript = "typescript" LangJavascript = "javascript" @@ -51,13 +50,16 @@ const ( LangJSONata = "jsonata" ) -var _ node.Node = &SnippetNode{} - +// Errors related to snippet execution. var ( ErrEntryPointNotUndeclared = errors.New("entry point is undeclared") ErrNotSupportedLanguage = errors.New("language is not supported") ) +var _ node.Node = (*SnippetNode)(nil) +var _ scheme.Spec = (*SnippetSpec)(nil) + +// NewSnippetNode creates a new SnippetNode with the given configuration. func NewSnippetNode(config SnippetNodeConfig) (*SnippetNode, error) { defer func() { _ = recover() }() @@ -178,6 +180,8 @@ func compile(lang, code string) (func(any) (any, error), error) { } } +type fieldNameMapper struct{} + func (*fieldNameMapper) FieldName(t reflect.Type, f reflect.StructField) string { return strcase.ToLowerCamel(f.Name) } diff --git a/pkg/plugin/controllx/switch.go b/pkg/plugin/controllx/switch.go index ed602009..89b0f855 100644 --- a/pkg/plugin/controllx/switch.go +++ b/pkg/plugin/controllx/switch.go @@ -13,39 +13,42 @@ import ( "github.com/xiatechs/jsonata-go" ) -type ( - SwitchNodeConfig struct { - ID ulid.ULID - } +// SwitchNodeConfig holds the configuration for creating a SwitchNode. +type SwitchNodeConfig struct { + ID ulid.ULID +} - SwitchNode struct { - *node.OneToManyNode - conditions []condition - mu sync.RWMutex - } +// SwitchNode represents a node that switches packets based on conditions. +type SwitchNode struct { + *node.OneToManyNode + conditions []condition + mu sync.RWMutex +} - SwitchSpec struct { - scheme.SpecMeta `map:",inline"` - Match []Condition `map:"match"` - } +// SwitchSpec represents the specification for the SwitchNode. +type SwitchSpec struct { + scheme.SpecMeta `map:",inline"` + Match []Condition `map:"match"` +} - Condition struct { - When string `map:"when"` - Port string `map:"port"` - } +// Condition represents a condition for the SwitchNode. +type Condition struct { + When string `map:"when"` + Port string `map:"port"` +} - condition struct { - when *jsonata.Expr - port string - } -) +type condition struct { + when *jsonata.Expr + port string +} -const ( - KindSwitch = "switch" -) +// KindSwitch is the kind identifier for SwitchNode. +const KindSwitch = "switch" -var _ node.Node = &SwitchNode{} +var _ node.Node = (*SwitchNode)(nil) +var _ scheme.Spec = (*SwitchSpec)(nil) +// NewSwitchNode creates a new SwitchNode with the given configuration. func NewSwitchNode(config SwitchNodeConfig) *SwitchNode { id := config.ID @@ -58,6 +61,7 @@ func NewSwitchNode(config SwitchNodeConfig) *SwitchNode { return n } +// Add adds a new condition to the SwitchNode. func (n *SwitchNode) Add(when string, port string) error { n.mu.Lock() defer n.mu.Unlock() @@ -71,6 +75,7 @@ func (n *SwitchNode) Add(when string, port string) error { return nil } +// Close closes the SwitchNode and clears its conditions. func (n *SwitchNode) Close() error { n.mu.Lock() defer n.mu.Unlock() diff --git a/pkg/plugin/networkx/builder.go b/pkg/plugin/networkx/builder.go index df052c3c..0143f948 100644 --- a/pkg/plugin/networkx/builder.go +++ b/pkg/plugin/networkx/builder.go @@ -10,6 +10,7 @@ import ( "github.com/siyul-park/uniflow/pkg/symbol" ) +// AddToHooks returns a function that adds hooks to the given hook.Hook. func AddToHooks() func(*hook.Hook) error { return func(h *hook.Hook) error { h.AddLoadHook(symbol.LoadHookFunc(func(n node.Node) error { @@ -26,6 +27,7 @@ func AddToHooks() func(*hook.Hook) error { } return nil })) + h.AddUnloadHook(symbol.UnloadHookFunc(func(n node.Node) error { if n, ok := n.(*HTTPNode); ok { ctx, cancel := context.WithTimeout(context.Background(), time.Second) @@ -35,10 +37,12 @@ func AddToHooks() func(*hook.Hook) error { } return nil })) + return nil } } +// AddToScheme returns a function that adds types and codecs to the provided scheme. func AddToScheme() func(*scheme.Scheme) error { return func(s *scheme.Scheme) error { s.AddKnownType(KindHTTP, &HTTPSpec{}) @@ -54,9 +58,11 @@ func AddToScheme() func(*scheme.Scheme) error { n := NewRouterNode(RouterNodeConfig{ ID: spec.ID, }) + for _, r := range spec.Routes { n.Add(r.Method, r.Path, r.Port) } + return n, nil })) diff --git a/pkg/plugin/networkx/http.go b/pkg/plugin/networkx/http.go index e7d7c455..fe3ccaeb 100644 --- a/pkg/plugin/networkx/http.go +++ b/pkg/plugin/networkx/http.go @@ -23,53 +23,46 @@ import ( "github.com/siyul-park/uniflow/pkg/scheme" ) -type ( - // HTTPNodeConfig represents the configuration of an HTTP node. - HTTPNodeConfig struct { - ID ulid.ULID - Address string - } - - // HTTPNode represents a node based on the HTTP protocol. - HTTPNode struct { - id ulid.ULID - address string - server *http.Server - listener net.Listener - listenerNetwork string - ioPort *port.Port - inPort *port.Port - outPort *port.Port - errPort *port.Port - mu sync.RWMutex - } - - // HTTPSpec represents the specification of an HTTP node. - HTTPSpec struct { - scheme.SpecMeta `map:",inline"` - Address string `map:"address"` - } - - // HTTPPayload represents the payload for HTTP requests and responses. - HTTPPayload struct { - Proto string `map:"proto,omitempty"` - Path string `map:"path,omitempty"` - Method string `map:"method,omitempty"` - Header http.Header `map:"header,omitempty"` - Query url.Values `map:"query,omitempty"` - Cookies []*http.Cookie `map:"cookies,omitempty"` - Body primitive.Value `map:"body,omitempty"` - Status int `map:"status"` - } - - tcpKeepAliveListener struct { - *net.TCPListener - } -) +// HTTPNodeConfig represents the configuration of an HTTP node. +type HTTPNodeConfig struct { + ID ulid.ULID + Address string +} -const ( - KindHTTP = "http" -) +// HTTPNode represents a node based on the HTTP protocol. +type HTTPNode struct { + id ulid.ULID + address string + server *http.Server + listener net.Listener + listenerNetwork string + ioPort *port.Port + inPort *port.Port + outPort *port.Port + errPort *port.Port + mu sync.RWMutex +} + +// HTTPSpec represents the specification of an HTTP node. +type HTTPSpec struct { + scheme.SpecMeta `map:",inline"` + Address string `map:"address"` +} + +// HTTPPayload represents the payload for HTTP requests and responses. +type HTTPPayload struct { + Proto string `map:"proto,omitempty"` + Path string `map:"path,omitempty"` + Method string `map:"method,omitempty"` + Header http.Header `map:"header,omitempty"` + Query url.Values `map:"query,omitempty"` + Cookies []*http.Cookie `map:"cookies,omitempty"` + Body primitive.Value `map:"body,omitempty"` + Status int `map:"status"` +} + +// KindHTTP is the kind identifier for HTTPNode. +const KindHTTP = "http" // Commonly used HTTP header constants. const ( @@ -205,16 +198,11 @@ var ( NetworkAuthenticationRequired = NewHTTPPayload(http.StatusNetworkAuthenticationRequired) // HTTP 511 Network Authentication Required ) -var ( - ErrInvalidListenerNetwork = errors.New("invalid listener network") -) - -var _ node.Node = &HTTPNode{} +var _ node.Node = (*HTTPNode)(nil) var _ http.Handler = &HTTPNode{} +var _ scheme.Spec = (*HTTPSpec)(nil) -var ( - forbiddenResponseHeaderRegexps []*regexp.Regexp -) +var forbiddenResponseHeaderRegexps []*regexp.Regexp func init() { // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers @@ -604,9 +592,13 @@ func isForbiddenResponseHeader(header string) bool { return forbidden } +type tcpKeepAliveListener struct { + *net.TCPListener +} + func newListener(address, network string) (*tcpKeepAliveListener, error) { if network != "tcp" && network != "tcp4" && network != "tcp6" { - return nil, ErrInvalidListenerNetwork + return nil, errors.New("invalid listener network") } l, err := net.Listen(network, address) if err != nil { diff --git a/pkg/plugin/networkx/mime.go b/pkg/plugin/networkx/mime.go index f73287c9..d67ec73c 100644 --- a/pkg/plugin/networkx/mime.go +++ b/pkg/plugin/networkx/mime.go @@ -17,6 +17,7 @@ import ( "github.com/siyul-park/uniflow/pkg/primitive" ) +// MIME content types const ( ApplicationJSON = "application/json" ApplicationJSONCharsetUTF8 = ApplicationJSON + "; " + charsetUTF8 @@ -37,10 +38,9 @@ const ( OctetStream = "application/octet-stream" ) -const ( - charsetUTF8 = "charset=utf-8" -) +const charsetUTF8 = "charset=utf-8" +// MarshalMIME marshals a primitive.Value to MIME format. func MarshalMIME(value primitive.Value, typ *string) ([]byte, error) { if typ == nil { content := "" @@ -202,6 +202,7 @@ func MarshalMIME(value primitive.Value, typ *string) ([]byte, error) { return nil, errors.WithStack(encoding.ErrUnsupportedValue) } +// UnmarshalMIME unmarshals MIME data to a primitive.Value. func UnmarshalMIME(data []byte, typ *string) (primitive.Value, error) { if len(data) == 0 { return nil, nil diff --git a/pkg/plugin/networkx/router.go b/pkg/plugin/networkx/router.go index b3f95642..940c126d 100644 --- a/pkg/plugin/networkx/router.go +++ b/pkg/plugin/networkx/router.go @@ -14,43 +14,51 @@ import ( "github.com/siyul-park/uniflow/pkg/scheme" ) -type ( - RouterNodeConfig struct { - ID ulid.ULID - } +// RouterNodeConfig holds the configuration for RouterNode. +type RouterNodeConfig struct { + ID ulid.ULID +} - RouterNode struct { - *node.OneToManyNode - tree *route - mu sync.RWMutex - } +// RouterNode represents a router node that handles routing based on HTTP methods, paths, and ports. +type RouterNode struct { + *node.OneToManyNode + tree *route + mu sync.RWMutex +} - RouterSpec struct { - scheme.SpecMeta `map:",inline"` - Routes []RouteInfo `map:"routes"` - } +// RouterSpec defines the specification for the router node. +type RouterSpec struct { + scheme.SpecMeta `map:",inline"` + Routes []RouteInfo `map:"routes"` +} - RouteInfo struct { - Method string `map:"method"` - Path string `map:"path"` - Port string `map:"port"` - } +// RouteInfo holds information about an individual route. +type RouteInfo struct { + Method string `map:"method"` + Path string `map:"path"` + Port string `map:"port"` +} - route struct { - kind routeKind - prefix string - parent *route - staticChildren []*route - paramChild *route - anyChild *route - paramNames []string - methods map[string]string - } - routeKind uint8 -) +type route struct { + kind routeKind + prefix string + parent *route + staticChildren []*route + paramChild *route + anyChild *route + paramNames []string + methods map[string]string +} + +type routeKind uint8 + +// KindRouter is the kind identifier for RouterNode. +const KindRouter = "router" const ( - KindRouter = "router" + KeyMethod = "method" + KeyPath = "path" + KeyParams = "params" ) const ( @@ -62,14 +70,10 @@ const ( anyLabel = byte('*') ) -const ( - KeyMethod = "method" - KeyPath = "path" - KeyParams = "params" -) - -var _ node.Node = &RouterNode{} +var _ node.Node = (*RouterNode)(nil) +var _ scheme.Spec = (*RouterSpec)(nil) +// NewRouterNode creates a new instance of RouterNode with the given configuration. func NewRouterNode(config RouterNodeConfig) *RouterNode { id := config.ID @@ -86,6 +90,7 @@ func NewRouterNode(config RouterNodeConfig) *RouterNode { return n } +// Add adds a new route to the router based on the provided HTTP method, path, and port. func (n *RouterNode) Add(method, path, port string) { n.mu.Lock() defer n.mu.Unlock() @@ -100,7 +105,7 @@ func (n *RouterNode) Add(method, path, port string) { var paramNames []string for i, lcpIndex := 0, len(path); i < lcpIndex; i++ { - if path[i] == ':' { + if path[i] == paramLabel { if i > 0 && path[i-1] == '\\' { path = path[:i-1] + path[i:] i-- @@ -122,7 +127,7 @@ func (n *RouterNode) Add(method, path, port string) { } else { n.insert(method, path[:i], paramKind, nil, "") } - } else if path[i] == '*' { + } else if path[i] == anyLabel { n.insert(method, path[:i], staticKind, nil, "") paramNames = append(paramNames, "*") n.insert(method, path[:i+1], anyKind, paramNames, port) @@ -132,6 +137,7 @@ func (n *RouterNode) Add(method, path, port string) { n.insert(method, path, staticKind, paramNames, port) } +// Close resets the router's tree when closing the node. func (n *RouterNode) Close() error { n.tree = &route{ methods: map[string]string{}, diff --git a/pkg/plugin/systemx/builder.go b/pkg/plugin/systemx/builder.go index e10adf44..7afca868 100644 --- a/pkg/plugin/systemx/builder.go +++ b/pkg/plugin/systemx/builder.go @@ -6,6 +6,7 @@ import ( "github.com/siyul-park/uniflow/pkg/storage" ) +// AddToScheme returns a function that adds types and codecs to the provided scheme. func AddToScheme(storage *storage.Storage) func(*scheme.Scheme) error { return func(s *scheme.Scheme) error { s.AddKnownType(KindReflect, &ReflectSpec{}) diff --git a/pkg/plugin/systemx/reflect.go b/pkg/plugin/systemx/reflect.go index 06ac4ca4..2bc25582 100644 --- a/pkg/plugin/systemx/reflect.go +++ b/pkg/plugin/systemx/reflect.go @@ -14,29 +14,30 @@ import ( "github.com/siyul-park/uniflow/pkg/storage" ) -type ( - ReflectNodeConfig struct { - ID ulid.ULID - OP string - Storage *storage.Storage - } +// ReflectNodeConfig holds the configuration for ReflectNode. +type ReflectNodeConfig struct { + ID ulid.ULID // ID is the unique identifier for ReflectNode. + OP string // OP is the operation to be performed by ReflectNode. + Storage *storage.Storage // Storage is the storage instance associated with ReflectNode. +} - ReflectNode struct { - *node.OneToOneNode - op string - storage *storage.Storage - } +// ReflectNode represents a node that reflects operations like delete, insert, select, or update. +type ReflectNode struct { + *node.OneToOneNode // Embedded OneToOneNode to support the node structure. + op string // op is the operation to be performed. + storage *storage.Storage // storage is the storage instance associated with ReflectNode. +} - ReflectSpec struct { - scheme.SpecMeta `map:",inline"` - OP string `map:"op"` - } -) +// ReflectSpec defines the specification for the ReflectNode. +type ReflectSpec struct { + scheme.SpecMeta `map:",inline"` + OP string `map:"op"` // OP is the operation to be performed by ReflectNode. +} -const ( - KindReflect = "reflect" -) +// KindReflect is the kind identifier for ReflectNode. +const KindReflect = "reflect" +// Operation constants for ReflectNode. const ( OPDelete = "delete" OPInsert = "insert" @@ -44,6 +45,10 @@ const ( OPUpdate = "update" ) +var _ node.Node = (*ReflectNode)(nil) +var _ scheme.Spec = (*ReflectSpec)(nil) + +// NewReflectNode creates a new instance of ReflectNode with the given configuration. func NewReflectNode(config ReflectNodeConfig) *ReflectNode { id := config.ID op := config.OP diff --git a/pkg/storage/filter.go b/pkg/storage/filter.go index cfadf569..3b80ae61 100644 --- a/pkg/storage/filter.go +++ b/pkg/storage/filter.go @@ -40,6 +40,7 @@ func (fh *filterHelper[T]) NE(value T) *Filter { } } +// LT creates a less-than filter. func (fh *filterHelper[T]) LT(value T) *Filter { return &Filter{ OP: database.LT,