58 lines
2.2 KiB
Go
58 lines
2.2 KiB
Go
package external
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
|
||
"github.com/vladimir/goherence/internal/module"
|
||
"github.com/vladimir/goherence/internal/ssh"
|
||
)
|
||
|
||
// Module — обёртка над внешним (сторонним) модулем: реализует тот же
|
||
// интерфейс module.Module, что и builtin-модули, но вместо чистого Go-кода
|
||
// доставляет и запускает на хосте subprocess, обмениваясь с ним JSON
|
||
// по stdin/stdout. Executor не отличает Module от builtin — он получает
|
||
// его из того же Registry, резолвя по имени.
|
||
type Module struct {
|
||
Manifest Manifest
|
||
BinPath map[string]string // arch ("linux/amd64") → путь к локальному бинарнику
|
||
}
|
||
|
||
func (m *Module) Name() string { return m.Manifest.Name }
|
||
|
||
func (m *Module) Run(ctx context.Context, in module.Input, conn *ssh.Conn) (module.Result, error) {
|
||
if m.Manifest.SchemaVersion != module.SchemaVersion {
|
||
return module.Result{}, fmt.Errorf(
|
||
"модуль %s: schema_version %d не совпадает с ожидаемой %d — "+
|
||
"обнови модуль или goherence", m.Manifest.Name, m.Manifest.SchemaVersion, module.SchemaVersion)
|
||
}
|
||
|
||
remoteBin, err := ensureDeployed(conn, m)
|
||
if err != nil {
|
||
return module.Result{}, err
|
||
}
|
||
|
||
inputJSON, err := json.Marshal(in)
|
||
if err != nil {
|
||
return module.Result{}, fmt.Errorf("сериализация input для %s: %w", m.Manifest.Name, err)
|
||
}
|
||
|
||
res, err := conn.RunWithInput(remoteBin, inputJSON)
|
||
if err != nil {
|
||
return module.Result{}, fmt.Errorf("запуск внешнего модуля %s: %w", m.Manifest.Name, err)
|
||
}
|
||
if res.ExitCode != 0 {
|
||
return module.Result{}, fmt.Errorf(
|
||
"внешний модуль %s завершился с кодом %d, stderr: %s",
|
||
m.Manifest.Name, res.ExitCode, res.Stderr)
|
||
}
|
||
|
||
var out module.Result
|
||
if err := json.Unmarshal([]byte(res.Stdout), &out); err != nil {
|
||
return module.Result{}, fmt.Errorf(
|
||
"внешний модуль %s вернул невалидный JSON: %w (stdout: %s)",
|
||
m.Manifest.Name, err, res.Stdout)
|
||
}
|
||
return out, nil
|
||
}
|