waveterm/pkg/wshutil/wshcommands.go

174 lines
4.9 KiB
Go

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package wshutil
import (
"encoding/json"
"fmt"
"reflect"
"github.com/wavetermdev/thenextwave/pkg/ijson"
"github.com/wavetermdev/thenextwave/pkg/shellexec"
"github.com/wavetermdev/thenextwave/pkg/tsgen/tsgenmeta"
"github.com/wavetermdev/thenextwave/pkg/wstore"
)
const CommandKey = "command"
const (
BlockCommand_Message = "message"
BlockCommand_SetView = "setview"
BlockCommand_SetMeta = "setmeta"
BlockCommand_GetMeta = "getmeta"
BlockCommand_Input = "controller:input"
BlockCommand_AppendBlockFile = "blockfile:append"
BlockCommand_AppendIJson = "blockfile:appendijson"
Command_ResolveIds = "resolveids"
Command_CreateBlock = "createblock"
)
var CommandToTypeMap = map[string]reflect.Type{
BlockCommand_Input: reflect.TypeOf(BlockInputCommand{}),
BlockCommand_SetView: reflect.TypeOf(BlockSetViewCommand{}),
BlockCommand_SetMeta: reflect.TypeOf(BlockSetMetaCommand{}),
BlockCommand_GetMeta: reflect.TypeOf(BlockGetMetaCommand{}),
BlockCommand_Message: reflect.TypeOf(BlockMessageCommand{}),
BlockCommand_AppendBlockFile: reflect.TypeOf(BlockAppendFileCommand{}),
BlockCommand_AppendIJson: reflect.TypeOf(BlockAppendIJsonCommand{}),
Command_ResolveIds: reflect.TypeOf(ResolveIdsCommand{}),
Command_CreateBlock: reflect.TypeOf(CreateBlockCommand{}),
}
func CommandTypeUnionMeta() tsgenmeta.TypeUnionMeta {
var rtypes []reflect.Type
for _, rtype := range CommandToTypeMap {
rtypes = append(rtypes, rtype)
}
return tsgenmeta.TypeUnionMeta{
BaseType: reflect.TypeOf((*BlockCommand)(nil)).Elem(),
TypeFieldName: "command",
Types: rtypes,
}
}
type baseCommand struct {
Command string `json:"command"`
}
type BlockCommand interface {
GetCommand() string
}
type BlockCommandWrapper struct {
BlockCommand
}
func ParseCmdMap(cmdMap map[string]any) (BlockCommand, error) {
cmdType, ok := cmdMap[CommandKey].(string)
if !ok {
return nil, fmt.Errorf("no %s field in command map", CommandKey)
}
mapJson, err := json.Marshal(cmdMap)
if err != nil {
return nil, fmt.Errorf("error marshalling command map: %w", err)
}
rtype := CommandToTypeMap[cmdType]
if rtype == nil {
return nil, fmt.Errorf("unknown command type %q", cmdType)
}
cmd := reflect.New(rtype).Interface()
err = json.Unmarshal(mapJson, cmd)
if err != nil {
return nil, fmt.Errorf("error unmarshalling command: %w", err)
}
return cmd.(BlockCommand), nil
}
type BlockInputCommand struct {
Command string `json:"command" tstype:"\"controller:input\""`
InputData64 string `json:"inputdata64,omitempty"`
SigName string `json:"signame,omitempty"`
TermSize *shellexec.TermSize `json:"termsize,omitempty"`
}
func (ic *BlockInputCommand) GetCommand() string {
return BlockCommand_Input
}
type ResolveIdsCommand struct {
Command string `json:"command" tstype:"\"resolveids\""`
Ids []string `json:"ids"`
}
func (ric *ResolveIdsCommand) GetCommand() string {
return Command_ResolveIds
}
type BlockSetViewCommand struct {
Command string `json:"command" tstype:"\"setview\""`
View string `json:"view"`
}
func (svc *BlockSetViewCommand) GetCommand() string {
return BlockCommand_SetView
}
type BlockGetMetaCommand struct {
Command string `json:"command" tstype:"\"getmeta\""`
ORef string `json:"oref"` // oref string
}
func (gmc *BlockGetMetaCommand) GetCommand() string {
return BlockCommand_GetMeta
}
type BlockSetMetaCommand struct {
Command string `json:"command" tstype:"\"setmeta\""`
ORef string `json:"oref,omitempty"` // allows oref, 8-char oid, or full uuid (empty is current block)
Meta map[string]any `json:"meta"`
}
func (smc *BlockSetMetaCommand) GetCommand() string {
return BlockCommand_SetMeta
}
type BlockMessageCommand struct {
Command string `json:"command" tstype:"\"message\""`
Message string `json:"message"`
}
func (bmc *BlockMessageCommand) GetCommand() string {
return BlockCommand_Message
}
type BlockAppendFileCommand struct {
Command string `json:"command" tstype:"\"blockfile:append\""`
FileName string `json:"filename"`
Data []byte `json:"data"`
}
func (bwc *BlockAppendFileCommand) GetCommand() string {
return BlockCommand_AppendBlockFile
}
type BlockAppendIJsonCommand struct {
Command string `json:"command" tstype:"\"blockfile:appendijson\""`
FileName string `json:"filename"`
Data ijson.Command `json:"data"`
}
func (bwc *BlockAppendIJsonCommand) GetCommand() string {
return BlockCommand_AppendIJson
}
type CreateBlockCommand struct {
Command string `json:"command" tstype:"\"createblock\""`
BlockDef *wstore.BlockDef `json:"blockdef"`
RtOpts *wstore.RuntimeOpts `json:"rtopts,omitempty"`
}
func (cbc *CreateBlockCommand) GetCommand() string {
return Command_CreateBlock
}