mirror of
https://github.com/hanzo-fi/payments.git
synced 2026-10-30 20:31:20 +00:00
193 lines
5.3 KiB
Go
193 lines
5.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/observe/log"
|
|
"github.com/hanzo-fi/payments/internal/connectors/plugins/registry"
|
|
"github.com/hanzo-fi/payments/tools/workbench"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
const (
|
|
workbenchProviderFlag = "provider"
|
|
workbenchConfigFlag = "config"
|
|
workbenchConfigFileFlag = "config-file"
|
|
workbenchListenFlag = "listen"
|
|
workbenchPageSizeFlag = "page-size"
|
|
)
|
|
|
|
func newWorkbench() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "workbench",
|
|
Short: "Run the connector workbench for local development",
|
|
Long: `The connector workbench provides a lightweight development environment
|
|
for building and testing payment connectors without requiring Temporal,
|
|
PostgreSQL, or other heavy infrastructure.
|
|
|
|
Features:
|
|
- In-memory storage (no database required)
|
|
- Multi-connector support - create multiple instances from the UI
|
|
- Step-by-step execution of connector operations
|
|
- HTTP API for triggering operations
|
|
- Web UI for debugging and inspection
|
|
- No Docker required
|
|
|
|
Examples:
|
|
# Run workbench without any connector (create from UI)
|
|
payments workbench
|
|
|
|
# Run workbench with a pre-configured connector
|
|
payments workbench --provider=stripe --config='{"apiKey":"sk_test_..."}'
|
|
|
|
# Run workbench with config file
|
|
payments workbench --provider=wise --config-file=./wise-config.json
|
|
|
|
# List available providers
|
|
payments workbench --list-providers`,
|
|
RunE: runWorkbench,
|
|
}
|
|
|
|
cmd.Flags().StringP(workbenchProviderFlag, "p", "", "Connector provider name (e.g., stripe, wise, adyen)")
|
|
cmd.Flags().StringP(workbenchConfigFlag, "c", "", "Connector configuration as JSON string")
|
|
cmd.Flags().StringP(workbenchConfigFileFlag, "f", "", "Path to connector configuration JSON file")
|
|
cmd.Flags().String(workbenchListenFlag, "127.0.0.1:8080", "HTTP server listen address")
|
|
cmd.Flags().Int(workbenchPageSizeFlag, 25, "Page size for fetch operations")
|
|
cmd.Flags().Bool("list-providers", false, "List available connector providers")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func runWorkbench(cmd *cobra.Command, args []string) error {
|
|
// Check if listing providers
|
|
listProviders, _ := cmd.Flags().GetBool("list-providers")
|
|
if listProviders {
|
|
return printProviders()
|
|
}
|
|
|
|
// Get optional provider and config for initial connector
|
|
provider, _ := cmd.Flags().GetString(workbenchProviderFlag)
|
|
configJSON, _ := cmd.Flags().GetString(workbenchConfigFlag)
|
|
configFile, _ := cmd.Flags().GetString(workbenchConfigFileFlag)
|
|
|
|
var connectorConfig json.RawMessage
|
|
if provider != "" {
|
|
provider = strings.ToLower(provider)
|
|
|
|
if configFile != "" {
|
|
data, err := os.ReadFile(configFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read config file: %w", err)
|
|
}
|
|
connectorConfig = data
|
|
} else if configJSON != "" {
|
|
connectorConfig = json.RawMessage(configJSON)
|
|
} else {
|
|
return fmt.Errorf("connector config is required when provider is specified (use --config or --config-file)")
|
|
}
|
|
|
|
// Validate JSON
|
|
var validateJSON map[string]interface{}
|
|
if err := json.Unmarshal(connectorConfig, &validateJSON); err != nil {
|
|
return fmt.Errorf("invalid config JSON: %w", err)
|
|
}
|
|
}
|
|
|
|
// Get other flags
|
|
listenAddr, _ := cmd.Flags().GetString(workbenchListenFlag)
|
|
pageSize, _ := cmd.Flags().GetInt(workbenchPageSizeFlag)
|
|
|
|
// Create logger
|
|
logger := logging.NewDefaultLogger(os.Stdout, true, false, false)
|
|
|
|
// Create workbench config
|
|
cfg := workbench.Config{
|
|
ListenAddr: listenAddr,
|
|
EnableUI: true,
|
|
DefaultPageSize: pageSize,
|
|
}
|
|
|
|
// Create workbench
|
|
wb, err := workbench.New(cfg, logger)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create workbench: %w", err)
|
|
}
|
|
|
|
// Handle signals
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
<-sigChan
|
|
fmt.Println("\nShutting down...")
|
|
cancel()
|
|
_ = wb.Stop(context.Background())
|
|
}()
|
|
|
|
// Start workbench
|
|
if err := wb.Start(ctx); err != nil {
|
|
return fmt.Errorf("failed to start workbench: %w", err)
|
|
}
|
|
|
|
// If provider was specified, create and install a connector
|
|
if provider != "" {
|
|
conn, err := wb.CreateConnector(ctx, workbench.CreateConnectorRequest{
|
|
Provider: provider,
|
|
Name: "default",
|
|
Config: connectorConfig,
|
|
})
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to create connector: %v", err))
|
|
} else {
|
|
logger.Info(fmt.Sprintf("Created connector instance: %s", conn.ID))
|
|
|
|
// Install the connector
|
|
if err := wb.InstallConnector(ctx, conn.ID); err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to install connector: %v", err))
|
|
} else {
|
|
logger.Info("Connector installed successfully")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait for shutdown
|
|
wb.Wait()
|
|
|
|
return nil
|
|
}
|
|
|
|
func printProviders() error {
|
|
configs := registry.GetConfigs(true) // include debug connectors
|
|
|
|
fmt.Println("Available connector providers:")
|
|
fmt.Println()
|
|
|
|
for provider, config := range configs {
|
|
fmt.Printf(" %s\n", provider)
|
|
fmt.Printf(" Config parameters:\n")
|
|
for paramName, param := range config {
|
|
required := ""
|
|
if param.Required {
|
|
required = " (required)"
|
|
}
|
|
fmt.Printf(" - %s: %s%s\n", paramName, param.DataType, required)
|
|
}
|
|
fmt.Println()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
// This will be added to root in NewRootCommand
|
|
}
|