lightning-terminal/scripting/runner.go
sputn1ck 43df8e2d7d scripting: fix LND RPC authentication using lndclient wrappers
This commit fixes LND RPC authentication by switching from raw gRPC
clients to lndclient wrappers that provide proper macaroon authentication.

Changes:
- Update LNDClients to use lndclient.LightningClient and
  lndclient.RouterClient instead of raw gRPC clients
- Add getRawLightningClient() and getRawRouterClient() helpers that use
  RawClientWithMacAuth() for authenticated raw client access
- Update all 21 LND builtin methods to use the new pattern
- Add InMemoryStore implementation for testing
- Wire up LND clients in terminal.go after LND connects
- Fix integration test function signatures

All 7 scripts integration tests now pass:
- scripts_basic_crud
- scripts_validation
- scripts_execution
- scripts_kv_store
- scripts_lnd_access
- scripts_builtins
- scripts_kv_builtins
2026-01-30 23:28:52 +01:00

144 lines
2.9 KiB
Go

package scripting
import (
"context"
"sync"
)
// Runner manages the lifecycle of a running script.
type Runner struct {
manager *Manager
script *Script
executionID int64
kvStore KVStore
rpcCaller RPCCaller
lndClients *LNDClients
engine *Engine
ctx context.Context
cancel context.CancelFunc
mu sync.Mutex
stopped bool
outputs []ScriptOutput
}
// ScriptOutput represents a single output from the script.
type ScriptOutput struct {
Level string
Message string
}
// NewRunner creates a new script runner.
func NewRunner(manager *Manager, script *Script, executionID int64, kvStore KVStore, rpcCaller RPCCaller, lndClients *LNDClients) *Runner {
ctx, cancel := context.WithCancel(context.Background())
return &Runner{
manager: manager,
script: script,
executionID: executionID,
kvStore: kvStore,
rpcCaller: rpcCaller,
lndClients: lndClients,
ctx: ctx,
cancel: cancel,
outputs: make([]ScriptOutput, 0),
}
}
// Run executes the script.
func (r *Runner) Run(ctx context.Context, args map[string]interface{}) *ExecutionResult {
r.mu.Lock()
if r.stopped {
r.mu.Unlock()
return &ExecutionResult{
Success: false,
Error: "runner was stopped before execution",
}
}
r.mu.Unlock()
// Create the engine.
cfg := EngineConfig{
ScriptName: r.script.Name,
Source: r.script.Source,
Macaroon: r.script.Macaroon,
AllowedURLs: r.script.AllowedURLs,
AllowedBuckets: r.script.AllowedBuckets,
Limits: ResourceLimits{
MaxMemoryBytes: r.script.MaxMemoryBytes,
TimeoutSecs: r.script.TimeoutSecs,
},
KVStore: r.kvStore,
RPCCaller: r.rpcCaller,
LNDClients: r.lndClients,
OutputCallback: func(level, message string) {
r.mu.Lock()
r.outputs = append(r.outputs, ScriptOutput{
Level: level,
Message: message,
})
r.mu.Unlock()
},
}
r.engine = NewEngine(r.ctx, cfg)
// Execute the script.
result, err := r.engine.Execute(args)
if err != nil {
return &ExecutionResult{
Success: false,
Error: err.Error(),
}
}
return result
}
// Stop gracefully stops the script.
func (r *Runner) Stop() {
r.mu.Lock()
if r.stopped {
r.mu.Unlock()
return
}
r.stopped = true
r.mu.Unlock()
// Cancel the context.
r.cancel()
// Stop the engine if it exists.
if r.engine != nil {
r.engine.Stop()
}
}
// IsStopped returns whether the runner has been stopped.
func (r *Runner) IsStopped() bool {
r.mu.Lock()
defer r.mu.Unlock()
return r.stopped
}
// GetOutputs returns all collected outputs.
func (r *Runner) GetOutputs() []ScriptOutput {
r.mu.Lock()
defer r.mu.Unlock()
// Return a copy.
outputs := make([]ScriptOutput, len(r.outputs))
copy(outputs, r.outputs)
return outputs
}
// ExecutionID returns the execution ID.
func (r *Runner) ExecutionID() int64 {
return r.executionID
}
// ScriptName returns the script name.
func (r *Runner) ScriptName() string {
return r.script.Name
}