Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions pkg/lumera/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package lumera

import "github.com/cosmos/cosmos-sdk/crypto/keyring"
import (
"time"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
)

// Config holds all the configuration needed for the client
type Config struct {
Expand All @@ -10,8 +14,8 @@ type Config struct {
// ChainID is the ID of the chain
ChainID string

// Timeout is the default request timeout in seconds
Timeout int
// Timeout is the default request timeout
Timeout time.Duration

// keyring is the keyring conf for the node sign & verify
keyring keyring.Keyring
Expand Down
10 changes: 7 additions & 3 deletions pkg/lumera/options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package lumera

import "github.com/cosmos/cosmos-sdk/crypto/keyring"
import (
"time"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
)

// Option is a function that applies a change to Config
type Option func(*Config)
Expand All @@ -20,9 +24,9 @@ func WithChainID(chainID string) Option {
}

// WithTimeout sets the default timeout
func WithTimeout(seconds int) Option {
func WithTimeout(duration time.Duration) Option {
return func(c *Config) {
c.Timeout = seconds
c.Timeout = duration
}
}

Expand Down
72 changes: 37 additions & 35 deletions sdk/action/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package action
import (
"context"
"fmt"
"os"

"github.com/LumeraProtocol/supernode/sdk/config"
"github.com/LumeraProtocol/supernode/sdk/event"
Expand All @@ -17,8 +18,8 @@ type Client interface {
StartCascade(ctx context.Context, fileHash string, actionID string, filePath string, signedData string) (string, error)
DeleteTask(ctx context.Context, taskID string) error
GetTask(ctx context.Context, taskID string) (*task.TaskEntry, bool)
SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler)
SubscribeToAllEvents(ctx context.Context, handler event.Handler)
SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler) error
SubscribeToAllEvents(ctx context.Context, handler event.Handler) error
}

// ClientImpl implements the Client interface
Expand All @@ -33,12 +34,7 @@ type ClientImpl struct {
var _ Client = (*ClientImpl)(nil)

// NewClient creates a new action client
func NewClient(
ctx context.Context,
config config.Config,
logger log.Logger,
keyring keyring.Keyring,
) (Client, error) {
func NewClient(ctx context.Context, config config.Config, logger log.Logger, keyring keyring.Keyring) (Client, error) {
if logger == nil {
logger = log.NewNoopLogger()
}
Expand All @@ -57,12 +53,11 @@ func NewClient(
}

// StartCascade initiates a cascade operation
func (c *ClientImpl) StartCascade(
ctx context.Context,
fileHash string, // Hash of the file to process
actionID string, // ID of the action to perform
filePath string, // Path to the file on disk
signedData string, // Optional signed authorization data
func (c *ClientImpl) StartCascade(ctx context.Context,
fileHash string,
actionID string,
filePath string,
signedData string,
) (string, error) {
c.logger.Debug(ctx, "Starting cascade operation",
"fileHash", fileHash,
Expand All @@ -82,6 +77,11 @@ func (c *ClientImpl) StartCascade(
c.logger.Error(ctx, "Empty file path provided")
return "", ErrEmptyFilePath
}
_, err := os.Stat(filePath)
if err != nil {
c.logger.Error(ctx, "File not found", "filePath", filePath)
return "", ErrEmptyFileNotFound
}

taskID, err := c.taskManager.CreateCascadeTask(ctx, fileHash, actionID, filePath, signedData)
if err != nil {
Expand All @@ -95,14 +95,13 @@ func (c *ClientImpl) StartCascade(

// GetTask retrieves a task by its ID
func (c *ClientImpl) GetTask(ctx context.Context, taskID string) (*task.TaskEntry, bool) {
c.logger.Debug(ctx, "Getting task", "taskID", taskID)
task, found := c.taskManager.GetTask(ctx, taskID)
if !found {
c.logger.Debug(ctx, "Task not found", "taskID", taskID)
} else {
c.logger.Debug(ctx, "Task found", "taskID", taskID, "status", task.Status)
if found {
return task, true
}
return task, found
c.logger.Debug(ctx, "Task not found", "taskID", taskID)

return nil, false
}

// DeleteTask removes a task by its ID
Expand All @@ -113,32 +112,35 @@ func (c *ClientImpl) DeleteTask(ctx context.Context, taskID string) error {
return fmt.Errorf("task ID cannot be empty")
}

err := c.taskManager.DeleteTask(ctx, taskID)
if err != nil {
if err := c.taskManager.DeleteTask(ctx, taskID); err != nil {
c.logger.Error(ctx, "Failed to delete task", "taskID", taskID, "error", err)
return fmt.Errorf("failed to delete task: %w", err)
}

c.logger.Info(ctx, "Task deleted successfully", "taskID", taskID)

return nil
}

// SubscribeToEvents registers a handler for specific event types
func (c *ClientImpl) SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler) {
c.logger.Debug(ctx, "Subscribing to events via task manager", "eventType", eventType)
if c.taskManager != nil {
c.taskManager.SubscribeToEvents(ctx, eventType, handler)
} else {
c.logger.Warn(ctx, "TaskManager is nil, cannot subscribe to events")
func (c *ClientImpl) SubscribeToEvents(ctx context.Context, eventType event.EventType, handler event.Handler) error {
if c.taskManager == nil {
return fmt.Errorf("TaskManager is nil, cannot subscribe to events")
}

c.logger.Debug(ctx, "Subscribing to events via task manager", "eventType", eventType)
c.taskManager.SubscribeToEvents(ctx, eventType, handler)

return nil
}

// SubscribeToAllEvents registers a handler for all events
func (c *ClientImpl) SubscribeToAllEvents(ctx context.Context, handler event.Handler) {
c.logger.Debug(ctx, "Subscribing to all events via task manager")
if c.taskManager != nil {
c.taskManager.SubscribeToAllEvents(ctx, handler)
} else {
c.logger.Warn(ctx, "TaskManager is nil, cannot subscribe to all events")
func (c *ClientImpl) SubscribeToAllEvents(ctx context.Context, handler event.Handler) error {
if c.taskManager == nil {
return fmt.Errorf("TaskManager is nil, cannot subscribe to events")
}

c.logger.Debug(ctx, "Subscribing to all events via task manager")
c.taskManager.SubscribeToAllEvents(ctx, handler)

return nil
}
17 changes: 9 additions & 8 deletions sdk/action/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import (
)

var (
ErrEmptyFileHash = errors.New("file hash cannot be empty")
ErrEmptyActionID = errors.New("action ID cannot be empty")
ErrEmptyFilePath = errors.New("file path cannot be empty")
ErrNoValidAction = errors.New("no action found with the specified ID")
ErrInvalidAction = errors.New("action is not in a valid state")
ErrNoSupernodes = errors.New("no valid supernodes available")
ErrTaskCreation = errors.New("failed to create task")
ErrCommunication = errors.New("communication with supernode failed")
ErrEmptyFileHash = errors.New("file hash cannot be empty")
ErrEmptyActionID = errors.New("action ID cannot be empty")
ErrEmptyFilePath = errors.New("file path cannot be empty")
ErrEmptyFileNotFound = errors.New("file not found at the specified path")
ErrNoValidAction = errors.New("no action found with the specified ID")
ErrInvalidAction = errors.New("action is not in a valid state")
ErrNoSupernodes = errors.New("no valid supernodes available")
ErrTaskCreation = errors.New("failed to create task")
ErrCommunication = errors.New("communication with supernode failed")
)

// SupernodeError represents an error related to supernode operations
Expand Down
3 changes: 2 additions & 1 deletion sdk/adapters/lumera/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strconv"
"time"

"github.com/LumeraProtocol/supernode/sdk/log"

Expand All @@ -23,7 +24,7 @@ type Client interface {
type ConfigParams struct {
GRPCAddr string
ChainID string
Timeout int
Timeout time.Duration
}

type Adapter struct {
Expand Down
2 changes: 2 additions & 0 deletions sdk/adapters/lumera/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type Action struct {
ExpirationTime string
}

type Supernodes []Supernode

// Supernode represents information about a supernode in the network
type Supernode struct {
CosmosAddress string // Blockchain identity of the supernode
Expand Down
86 changes: 79 additions & 7 deletions sdk/config/config.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,86 @@
package config

import (
"errors"
"time"
)

const (
DefaultLocalCosmosAddress = "lumera1qv3" // Example address - replace with actual
DefaultChainID = "lumera-testnet" // Example chain ID - replace with actual
DefaultGRPCAddr = "127.0.0.1:9090"
DefaultTimeout = 10 * time.Second
)

// AccountConfig holds peer-to-peer addresses, ports, etc.
type AccountConfig struct {
LocalCosmosAddress string // REQUIRED - cosmos account address used for signing tx
}

// LumeraConfig wraps all chain-specific dials.
type LumeraConfig struct {
GRPCAddr string // REQUIRED – e.g. "127.0.0.1:9090"
ChainID string // REQUIRED – e.g. "lumera-mainnet"
Timeout time.Duration // OPTIONAL – defaults to DefaultTimeout
}

type Config struct {
Network struct {
DefaultSupernodePort int
LocalCosmosAddress string
Account AccountConfig
Lumera LumeraConfig
}

// Option is a functional option for configuring the Config.
type Option func(*Config)

// New builds a Config, applying the supplied functional options.
func New(opts ...Option) (*Config, error) {
cfg := &Config{
Account: AccountConfig{LocalCosmosAddress: DefaultLocalCosmosAddress},
Lumera: LumeraConfig{
GRPCAddr: DefaultGRPCAddr,
Timeout: DefaultTimeout,
ChainID: DefaultChainID,
},
}

for _, opt := range opts {
opt(cfg)
}

Lumera struct {
GRPCAddr string
ChainID string
Timeout int
if err := cfg.Validate(); err != nil {
return nil, err
}
return cfg, nil
}

func WithLocalCosmosAddress(addr string) Option {
return func(c *Config) { c.Account.LocalCosmosAddress = addr }
}

func WithGRPCAddr(addr string) Option {
return func(c *Config) { c.Lumera.GRPCAddr = addr }
}

func WithChainID(id string) Option {
return func(c *Config) { c.Lumera.ChainID = id }
}

func WithTimeout(d time.Duration) Option {
return func(c *Config) { c.Lumera.Timeout = d }
}

// Validate checks the configuration for required fields and valid values.
func (c *Config) Validate() error {
switch {
case c.Account.LocalCosmosAddress == "":
return errors.New("config: Network.LocalCosmosAddress is required")
case c.Lumera.GRPCAddr == "":
return errors.New("config: Lumera.GRPCAddr is required")
case c.Lumera.ChainID == "":
return errors.New("config: Lumera.ChainID is required")
case c.Lumera.Timeout <= 0:
return errors.New("config: Lumera.Timeout must be > 0")
default:
return nil
}
}
Loading