Skip to content

Commit

Permalink
Several fixes and improvements (#9)
Browse files Browse the repository at this point in the history
* Several fixes

* Fix lint lint errors

* go fmt
  • Loading branch information
raynaudoe authored Nov 19, 2024
1 parent 1dd410a commit e283557
Show file tree
Hide file tree
Showing 25 changed files with 292 additions and 95 deletions.
15 changes: 10 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
WALLET_BIN := build/wallet
GOLANGCI_VERSION := v1.60.3
golangci_version=v1.61.0
golangci_installed_version=$(shell golangci-lint version --format short 2>/dev/null)

.PHONY: demo run clean

Expand All @@ -18,11 +19,13 @@ demo:
clean:
rm -f $(WALLET_BIN)


# Install golangci-lint
lint-install:
@echo "--> Installing golangci-lint $(GOLANGCI_VERSION)"
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_VERSION)
@echo "--> Checking golangci-lint installation"
@if [ "$(golangci_installed_version)" != "$(golangci_version)" ]; then \
echo "--> Installing golangci-lint $(golangci_version)"; \
go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version); \
fi

# Run golangci-lint
lint:
Expand All @@ -34,4 +37,6 @@ lint:
lint-fix:
@echo "--> Running linter with fix"
$(MAKE) lint-install
@golangci-lint run --fix
@golangci-lint run --fix

.PHONY: lint lint-fix lint-install
10 changes: 5 additions & 5 deletions cmd/register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package register

import (
// Import all provider packages here
"crypto-provider/pkg/factory"
_ "crypto-provider/pkg/provider/file"
_ "crypto-provider/pkg/provider/file/cmd"
"github.com/cosmos/crypto-provider/pkg/factory"
_ "github.com/cosmos/crypto-provider/pkg/impl/file"
_ "github.com/cosmos/crypto-provider/pkg/impl/file/cmd"
// Add other providers as needed
// _ "crypto-provider/pkg/provider/someprovider"
// _ "github.com/cosmos/crypto-provider/pkg/impl/someprovider"
)

// Init is a dummy function to ensure this package is imported
func Init() {
_ = factory.GetFactory()
_ = factory.GetGlobalFactory()
}
6 changes: 3 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package main

import (
"crypto-provider/pkg/cli"
"crypto-provider/pkg/keyring"
"crypto-provider/pkg/wallet"
"fmt"
"github.com/cosmos/crypto-provider/pkg/cli"
"github.com/cosmos/crypto-provider/pkg/keyring"
"github.com/cosmos/crypto-provider/pkg/wallet"
"os"

"github.com/spf13/cobra"
Expand Down
9 changes: 5 additions & 4 deletions demo/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package main

import (
"crypto-provider/pkg/components"
"crypto-provider/pkg/keyring"
"crypto-provider/pkg/provider/file"
"crypto-provider/pkg/wallet"
"crypto/rand"
"fmt"
"log"
"os"
"path/filepath"

"github.com/cosmos/crypto-provider/pkg/components"
"github.com/cosmos/crypto-provider/pkg/impl/file"
"github.com/cosmos/crypto-provider/pkg/keyring"
"github.com/cosmos/crypto-provider/pkg/wallet"
)

const TestFile = "testdata/file_1.json"
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module crypto-provider
module github.com/cosmos/crypto-provider

go 1.23

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ Key components:
- Implements a GetRootCmd() function using the singleton pattern and sync.Once for thread-safety.
- Initializes the root command and its flags.
2. Provider Commands (e.g., pkg/provider/file/cmd/command.go):
2. Provider Commands (e.g., pkg/impl/file/cmd/command.go):
- Each provider package implements its own set of subcommands.
- Uses an init() function to register its commands with the root command.
How to add a new provider cli:
1. Create a new package for your provider (e.g., pkg/provider/newprovider/cmd/).
1. Create a new package for your provider (e.g., pkg/impl/newprovider/cmd/).
2. In this package, create a file (e.g., command.go) with the following structure:
- Implement an init() function that calls GetRootCmd() and adds your provider's command.
- Create a NewCommand() function that returns a cobra.Command for your provider.
Expand Down
56 changes: 56 additions & 0 deletions pkg/components/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,33 @@ package components

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)

// CryptoProviderFactory is a factory interface for creating CryptoProviders.
// Must be implemented by each CryptoProvider.
type CryptoProviderFactory interface {
// Create creates a new CryptoProvider instance using the given source
Create(source BuildSource) (CryptoProvider, error)

// Save saves the CryptoProvider to the underlying storage
Save(provider CryptoProvider) error

// Type returns the type of the CryptoProvider that this factory creates
Type() string

// SupportedSources returns the sources that this factory supports building CryptoProviders from
SupportedSources() []string
}

// CryptoProviderConfig defines the configuration structure for CryptoProvider.
type CryptoProviderConfig struct {
ProviderType string `json:"provider_type"`
Options map[string]interface{} `json:"options"`
}

type BuildSource interface {
Type() string
Validate() error
Expand Down Expand Up @@ -72,3 +86,45 @@ func (m BuildSourceJson) Validate() error {
// Additional validation can be added here if needed
return nil
}

// BuildSourceConfig //////////////////////////////////////////////////////////////
// is a BuildSource implementation that uses CryptoProviderConfig as source
// /////////////////////////////////////////////////////////////////////////////////
type BuildSourceConfig struct {
Config CryptoProviderConfig
}

func (m BuildSourceConfig) Type() string { return "config" }
func (m BuildSourceConfig) Validate() error {
// Validate the Config field
if m.Config.ProviderType == "" {
return fmt.Errorf("provider_type is required in the configuration")
}
// Additional validation can be added here if needed
return nil
}

// BaseCryptoProviderFactory //////////////////////////////////////////////////////

type BaseFactory struct {
BaseDir string
}

func (f *BaseFactory) Save(provider CryptoProvider) error {
metadata := provider.Metadata()
filename := fmt.Sprintf("%s.json", metadata.Name)

path := filepath.Join(f.BaseDir, filename)

// Create the directory if it doesn't exist
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}

data, err := metadata.Serialize()
if err != nil {
return fmt.Errorf("failed to marshal metadata: %w", err)
}

return os.WriteFile(path, data, 0600)
}
5 changes: 5 additions & 0 deletions pkg/components/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ type PrivKey[T PubKey] interface {
Equals(other PrivKey[T]) bool
Type() string
}

// KeyFactory defines how a CryptoProvider creates and manages its keys
type KeyFactory interface {
GenPubKeyFromString(string) (PubKey, error)
}
13 changes: 11 additions & 2 deletions pkg/components/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

"github.com/Masterminds/semver/v3"

"crypto-provider/pkg/keyring"
"github.com/cosmos/crypto-provider/pkg/keyring"
)

type ProviderConfig = map[string]any
Expand Down Expand Up @@ -34,7 +34,7 @@ func FromRecord(record *keyring.Record) (*ProviderMetadata, error) {
}

// Validate checks if the ProviderMetadata is valid
func (pm *ProviderMetadata) Validate() error {
func (pm ProviderMetadata) Validate() error {
_, err := semver.NewVersion(pm.Version)
if err != nil {
return fmt.Errorf("invalid version: %w", err)
Expand All @@ -53,3 +53,12 @@ func (pm *ProviderMetadata) Validate() error {

return nil
}

// Serialize returns a JSON serialized string of the ProviderMetadata
func (pm ProviderMetadata) Serialize() ([]byte, error) {
data, err := json.MarshalIndent(pm, "", " ")
if err != nil {
return nil, fmt.Errorf("failed to marshal metadata: %w", err)
}
return data, nil
}
11 changes: 11 additions & 0 deletions pkg/components/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,15 @@ type CryptoProvider interface {

// Metadata returns metadata for the crypto provider.
Metadata() ProviderMetadata

// GetPubKey returns the public key of the provider
GetPubKey() PubKey

// ProviderInitializer is an internal interface for keys initialization
ProviderInitializer
}

type ProviderInitializer interface {
// InitializeKeys initializes the keys for the provider.
InitializeKeys() error
}
49 changes: 45 additions & 4 deletions pkg/factory/factory.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package factory

import (
"crypto-provider/pkg/components"
"encoding/json"
"fmt"
"sync"

"github.com/cosmos/crypto-provider/pkg/components"
)

var (
Expand All @@ -15,7 +17,7 @@ type Factory struct {
registry map[string]components.CryptoProviderFactory
}

func GetFactory() *Factory {
func GetGlobalFactory() *Factory {
once.Do(func() {
factoryInstance = newFactory()
})
Expand All @@ -39,8 +41,10 @@ func (f *Factory) RegisterFactory(factory components.CryptoProviderFactory) erro
}

if _, exists := f.registry[providerType]; exists {
return fmt.Errorf("provider type %s is already registered", providerType)
fmt.Printf("warning: factory for provider type '%s' already registered\n", providerType)
return nil
}

f.registry[providerType] = factory
return nil
}
Expand All @@ -52,7 +56,44 @@ func (f *Factory) CreateCryptoProvider(providerType string, source components.Bu
return nil, fmt.Errorf("no factory registered for provider type: '%s'", providerType)
}

return factory.Create(source)
provider, err := factory.Create(source)
if err != nil {
return nil, err
}

// Type assert to internal interface
initializer, ok := provider.(components.ProviderInitializer)
if !ok {
return nil, fmt.Errorf("provider does not implement initializer interface")
}

// Initialize keys using internal interface
if err := initializer.InitializeKeys(); err != nil {
return nil, fmt.Errorf("failed to initialize keys: %w. Check the implementation if InitializeKeys()", err)
}

// Try get pubkey to check if it was initialized
pubKey := provider.GetPubKey()
if pubKey == nil {
return nil, fmt.Errorf("public key not available from provider")
}

return provider, nil
}

// LoadCryptoProvider loads a CryptoProvider from a raw JSON string.
func (f *Factory) LoadCryptoProvider(rawJSON string) (components.CryptoProvider, error) {
var config components.CryptoProviderConfig
if err := json.Unmarshal([]byte(rawJSON), &config); err != nil {
return nil, fmt.Errorf("failed to decode JSON: %w", err)
}

if config.ProviderType == "" {
return nil, fmt.Errorf("provider_type is required in the configuration")
}

source := components.BuildSourceConfig{Config: config}
return f.CreateCryptoProvider(config.ProviderType, source)
}

// newFactory creates a new Factory instance and initializes the registry map.
Expand Down
2 changes: 1 addition & 1 deletion pkg/provider/file/cmd/cli.go → pkg/impl/file/cmd/cli.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cmd

import (
"crypto-provider/pkg/cli"
"fmt"
"github.com/cosmos/crypto-provider/pkg/cli"
"github.com/spf13/cobra"
)

Expand Down
3 changes: 2 additions & 1 deletion pkg/provider/file/config.go → pkg/impl/file/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package file

import (
"crypto-provider/pkg/components"
"encoding/json"
"fmt"

"github.com/cosmos/crypto-provider/pkg/components"
)

// FileProviderConfig holds the configuration for the File Provider
Expand Down
Loading

0 comments on commit e283557

Please sign in to comment.