- Consolidate DialRemote/DialTunnel common logic into buildResources + dialEnv interface - Remove strict capability check that prevented ConnResources creation for host-exec-only nodes - Merge gRPC-discovered capabilities with registration-declared capabilities in DialTunnel - Replace requireKubeConfig hard-fail with graceful skip when kubeconfig is absent - Introduce tai/types package for shared Ports/Capabilities/SystemInfo/AuthInfo/NodeMeta - Add tai/conn.go (ConnResources) and tai/dial.go (DialRemote/DialTunnel/DialLocal) - Rename tai/sandbox → tai/runtime for clarity - Update sandbox/v2, workspace, agent/sandbox/v2 test utilities for build-tag isolation Made-with: Cursor
144 lines
4 KiB
Go
144 lines
4 KiB
Go
package jsapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/yaoapp/yao/tai/registry"
|
|
taitypes "github.com/yaoapp/yao/tai/types"
|
|
"rogchap.com/v8go"
|
|
)
|
|
|
|
// sbGetNode: `sandbox.GetNode(taiID)` → NodeInfo | null
|
|
func sbGetNode(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
|
iso := info.Context().Isolate()
|
|
args := info.Args()
|
|
if len(args) < 1 || !args[0].IsString() {
|
|
return throwError(info, "GetNode requires taiID (string)")
|
|
}
|
|
|
|
reg := registry.Global()
|
|
if reg == nil {
|
|
return throwError(info, "registry not initialized")
|
|
}
|
|
|
|
snap, ok := reg.Get(args[0].String())
|
|
if !ok {
|
|
return v8go.Null(iso)
|
|
}
|
|
|
|
val, err := snapshotToJS(info.Context(), snap)
|
|
if err != nil {
|
|
return throwError(info, err.Error())
|
|
}
|
|
return val
|
|
}
|
|
|
|
// sbNodes: `sandbox.Nodes()` → NodeInfo[]
|
|
func sbNodes(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
|
v8ctx := info.Context()
|
|
|
|
reg := registry.Global()
|
|
if reg == nil {
|
|
return throwError(info, "registry not initialized")
|
|
}
|
|
|
|
snaps := reg.List()
|
|
return snapshotsToJSArray(v8ctx, snaps)
|
|
}
|
|
|
|
// sbNodesByTeam: `sandbox.NodesByTeam(teamID)` → NodeInfo[]
|
|
func sbNodesByTeam(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
|
v8ctx := info.Context()
|
|
args := info.Args()
|
|
if len(args) < 1 || !args[0].IsString() {
|
|
return throwError(info, "NodesByTeam requires teamID (string)")
|
|
}
|
|
|
|
reg := registry.Global()
|
|
if reg == nil {
|
|
return throwError(info, "registry not initialized")
|
|
}
|
|
|
|
snaps := reg.ListByTeam(args[0].String())
|
|
return snapshotsToJSArray(v8ctx, snaps)
|
|
}
|
|
|
|
// snapshotToJS converts a NodeMeta to a JS NodeInfo object.
|
|
// Auth and YaoBase are excluded for security.
|
|
func snapshotToJS(v8ctx *v8go.Context, snap *taitypes.NodeMeta) (*v8go.Value, error) {
|
|
ports := map[string]interface{}{
|
|
"grpc": snap.Ports.GRPC, "http": snap.Ports.HTTP,
|
|
"vnc": snap.Ports.VNC, "docker": snap.Ports.Docker, "k8s": snap.Ports.K8s,
|
|
}
|
|
|
|
caps := map[string]interface{}{
|
|
"docker": snap.Capabilities.Docker, "k8s": snap.Capabilities.K8s,
|
|
"host_exec": snap.Capabilities.HostExec,
|
|
}
|
|
|
|
data, err := json.Marshal(map[string]interface{}{
|
|
"tai_id": snap.TaiID,
|
|
"machine_id": snap.MachineID,
|
|
"version": snap.Version,
|
|
"mode": snap.Mode,
|
|
"addr": snap.Addr,
|
|
"status": snap.Status,
|
|
"display_name": snap.DisplayName,
|
|
"connected_at": snap.ConnectedAt.Format(time.RFC3339),
|
|
"last_ping": snap.LastPing.Format(time.RFC3339),
|
|
"ports": ports,
|
|
"capabilities": caps,
|
|
"system": map[string]interface{}{
|
|
"os": snap.System.OS,
|
|
"arch": snap.System.Arch,
|
|
"hostname": snap.System.Hostname,
|
|
"num_cpu": snap.System.NumCPU,
|
|
"total_mem": snap.System.TotalMem,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return v8go.JSONParse(v8ctx, string(data))
|
|
}
|
|
|
|
func snapshotsToJSArray(v8ctx *v8go.Context, snaps []taitypes.NodeMeta) *v8go.Value {
|
|
items := make([]interface{}, 0, len(snaps))
|
|
for i := range snaps {
|
|
snap := &snaps[i]
|
|
ports := map[string]interface{}{
|
|
"grpc": snap.Ports.GRPC, "http": snap.Ports.HTTP,
|
|
"vnc": snap.Ports.VNC, "docker": snap.Ports.Docker, "k8s": snap.Ports.K8s,
|
|
}
|
|
caps := map[string]interface{}{
|
|
"docker": snap.Capabilities.Docker, "k8s": snap.Capabilities.K8s,
|
|
"host_exec": snap.Capabilities.HostExec,
|
|
}
|
|
items = append(items, map[string]interface{}{
|
|
"tai_id": snap.TaiID,
|
|
"node_id": snap.TaiID,
|
|
"machine_id": snap.MachineID,
|
|
"version": snap.Version,
|
|
"mode": snap.Mode,
|
|
"addr": snap.Addr,
|
|
"status": snap.Status,
|
|
"display_name": snap.DisplayName,
|
|
"connected_at": snap.ConnectedAt.Format(time.RFC3339),
|
|
"last_ping": snap.LastPing.Format(time.RFC3339),
|
|
"ports": ports,
|
|
"capabilities": caps,
|
|
"system": map[string]interface{}{
|
|
"os": snap.System.OS,
|
|
"arch": snap.System.Arch,
|
|
"hostname": snap.System.Hostname,
|
|
"num_cpu": snap.System.NumCPU,
|
|
"total_mem": snap.System.TotalMem,
|
|
},
|
|
})
|
|
}
|
|
data, _ := json.Marshal(items)
|
|
val, _ := v8go.JSONParse(v8ctx, string(data))
|
|
return val
|
|
}
|