implement wsh setconfig (#284)

This commit is contained in:
Mike Sawka 2024-08-27 22:02:21 -07:00 committed by GitHub
parent 8630e23239
commit a3aa941b68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 126 additions and 59 deletions

View File

@ -0,0 +1,37 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"github.com/spf13/cobra"
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
)
var setConfigCmd = &cobra.Command{
Use: "setconfig",
Short: "set config",
Args: cobra.MinimumNArgs(1),
Run: setConfigRun,
PreRunE: preRunSetupRpcClient,
}
func init() {
rootCmd.AddCommand(setConfigCmd)
}
func setConfigRun(cmd *cobra.Command, args []string) {
metaSetsStrs := args[:]
meta, err := parseMetaSets(metaSetsStrs)
if err != nil {
WriteStderr("[error] %v\n", err)
return
}
err = wshclient.SetConfigCommand(RpcClient, meta, &wshrpc.RpcOpts{Timeout: 2000})
if err != nil {
WriteStderr("[error] setting config: %v\n", err)
return
}
WriteStdout("config set\n")
}

View File

@ -8,97 +8,97 @@ import * as WOS from "./wos";
// WshServerCommandToDeclMap // WshServerCommandToDeclMap
class WshServerType { class WshServerType {
// command "announce" [call] // command "announce" [call]
AnnounceCommand(data: string, opts?: RpcOpts): Promise<void> { AnnounceCommand(data: string, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("announce", data, opts); return WOS.wshServerRpcHelper_call("announce", data, opts);
} }
// command "authenticate" [call] // command "authenticate" [call]
AuthenticateCommand(data: string, opts?: RpcOpts): Promise<CommandAuthenticateRtnData> { AuthenticateCommand(data: string, opts?: RpcOpts): Promise<CommandAuthenticateRtnData> {
return WOS.wshServerRpcHelper_call("authenticate", data, opts); return WOS.wshServerRpcHelper_call("authenticate", data, opts);
} }
// command "controllerinput" [call] // command "controllerinput" [call]
ControllerInputCommand(data: CommandBlockInputData, opts?: RpcOpts): Promise<void> { ControllerInputCommand(data: CommandBlockInputData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("controllerinput", data, opts); return WOS.wshServerRpcHelper_call("controllerinput", data, opts);
} }
// command "controllerrestart" [call] // command "controllerrestart" [call]
ControllerRestartCommand(data: CommandBlockRestartData, opts?: RpcOpts): Promise<void> { ControllerRestartCommand(data: CommandBlockRestartData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("controllerrestart", data, opts); return WOS.wshServerRpcHelper_call("controllerrestart", data, opts);
} }
// command "createblock" [call] // command "createblock" [call]
CreateBlockCommand(data: CommandCreateBlockData, opts?: RpcOpts): Promise<ORef> { CreateBlockCommand(data: CommandCreateBlockData, opts?: RpcOpts): Promise<ORef> {
return WOS.wshServerRpcHelper_call("createblock", data, opts); return WOS.wshServerRpcHelper_call("createblock", data, opts);
} }
// command "deleteblock" [call] // command "deleteblock" [call]
DeleteBlockCommand(data: CommandDeleteBlockData, opts?: RpcOpts): Promise<void> { DeleteBlockCommand(data: CommandDeleteBlockData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("deleteblock", data, opts); return WOS.wshServerRpcHelper_call("deleteblock", data, opts);
} }
// command "eventpublish" [call] // command "eventpublish" [call]
EventPublishCommand(data: WaveEvent, opts?: RpcOpts): Promise<void> { EventPublishCommand(data: WaveEvent, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("eventpublish", data, opts); return WOS.wshServerRpcHelper_call("eventpublish", data, opts);
} }
// command "eventrecv" [call] // command "eventrecv" [call]
EventRecvCommand(data: WaveEvent, opts?: RpcOpts): Promise<void> { EventRecvCommand(data: WaveEvent, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("eventrecv", data, opts); return WOS.wshServerRpcHelper_call("eventrecv", data, opts);
} }
// command "eventsub" [call] // command "eventsub" [call]
EventSubCommand(data: SubscriptionRequest, opts?: RpcOpts): Promise<void> { EventSubCommand(data: SubscriptionRequest, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("eventsub", data, opts); return WOS.wshServerRpcHelper_call("eventsub", data, opts);
} }
// command "eventunsub" [call] // command "eventunsub" [call]
EventUnsubCommand(data: string, opts?: RpcOpts): Promise<void> { EventUnsubCommand(data: string, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("eventunsub", data, opts); return WOS.wshServerRpcHelper_call("eventunsub", data, opts);
} }
// command "eventunsuball" [call] // command "eventunsuball" [call]
EventUnsubAllCommand(opts?: RpcOpts): Promise<void> { EventUnsubAllCommand(opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("eventunsuball", null, opts); return WOS.wshServerRpcHelper_call("eventunsuball", null, opts);
} }
// command "fileappend" [call] // command "fileappend" [call]
FileAppendCommand(data: CommandFileData, opts?: RpcOpts): Promise<void> { FileAppendCommand(data: CommandFileData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("fileappend", data, opts); return WOS.wshServerRpcHelper_call("fileappend", data, opts);
} }
// command "fileappendijson" [call] // command "fileappendijson" [call]
FileAppendIJsonCommand(data: CommandAppendIJsonData, opts?: RpcOpts): Promise<void> { FileAppendIJsonCommand(data: CommandAppendIJsonData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("fileappendijson", data, opts); return WOS.wshServerRpcHelper_call("fileappendijson", data, opts);
} }
// command "fileread" [call] // command "fileread" [call]
FileReadCommand(data: CommandFileData, opts?: RpcOpts): Promise<string> { FileReadCommand(data: CommandFileData, opts?: RpcOpts): Promise<string> {
return WOS.wshServerRpcHelper_call("fileread", data, opts); return WOS.wshServerRpcHelper_call("fileread", data, opts);
} }
// command "filewrite" [call] // command "filewrite" [call]
FileWriteCommand(data: CommandFileData, opts?: RpcOpts): Promise<void> { FileWriteCommand(data: CommandFileData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("filewrite", data, opts); return WOS.wshServerRpcHelper_call("filewrite", data, opts);
} }
// command "getmeta" [call] // command "getmeta" [call]
GetMetaCommand(data: CommandGetMetaData, opts?: RpcOpts): Promise<MetaType> { GetMetaCommand(data: CommandGetMetaData, opts?: RpcOpts): Promise<MetaType> {
return WOS.wshServerRpcHelper_call("getmeta", data, opts); return WOS.wshServerRpcHelper_call("getmeta", data, opts);
} }
// command "message" [call] // command "message" [call]
MessageCommand(data: CommandMessageData, opts?: RpcOpts): Promise<void> { MessageCommand(data: CommandMessageData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("message", data, opts); return WOS.wshServerRpcHelper_call("message", data, opts);
} }
// command "remotefiledelete" [call] // command "remotefiledelete" [call]
RemoteFileDeleteCommand(data: string, opts?: RpcOpts): Promise<void> { RemoteFileDeleteCommand(data: string, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("remotefiledelete", data, opts); return WOS.wshServerRpcHelper_call("remotefiledelete", data, opts);
} }
// command "remotefileinfo" [call] // command "remotefileinfo" [call]
RemoteFileInfoCommand(data: string, opts?: RpcOpts): Promise<FileInfo> { RemoteFileInfoCommand(data: string, opts?: RpcOpts): Promise<FileInfo> {
return WOS.wshServerRpcHelper_call("remotefileinfo", data, opts); return WOS.wshServerRpcHelper_call("remotefileinfo", data, opts);
} }
@ -113,22 +113,27 @@ class WshServerType {
} }
// command "remotewritefile" [call] // command "remotewritefile" [call]
RemoteWriteFileCommand(data: CommandRemoteWriteFileData, opts?: RpcOpts): Promise<void> { RemoteWriteFileCommand(data: CommandRemoteWriteFileData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("remotewritefile", data, opts); return WOS.wshServerRpcHelper_call("remotewritefile", data, opts);
} }
// command "resolveids" [call] // command "resolveids" [call]
ResolveIdsCommand(data: CommandResolveIdsData, opts?: RpcOpts): Promise<CommandResolveIdsRtnData> { ResolveIdsCommand(data: CommandResolveIdsData, opts?: RpcOpts): Promise<CommandResolveIdsRtnData> {
return WOS.wshServerRpcHelper_call("resolveids", data, opts); return WOS.wshServerRpcHelper_call("resolveids", data, opts);
} }
// command "setconfig" [call]
SetConfigCommand(data: MetaMapType, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("setconfig", data, opts);
}
// command "setmeta" [call] // command "setmeta" [call]
SetMetaCommand(data: CommandSetMetaData, opts?: RpcOpts): Promise<void> { SetMetaCommand(data: CommandSetMetaData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("setmeta", data, opts); return WOS.wshServerRpcHelper_call("setmeta", data, opts);
} }
// command "setview" [call] // command "setview" [call]
SetViewCommand(data: CommandBlockSetViewData, opts?: RpcOpts): Promise<void> { SetViewCommand(data: CommandBlockSetViewData, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("setview", data, opts); return WOS.wshServerRpcHelper_call("setview", data, opts);
} }
@ -148,7 +153,7 @@ class WshServerType {
} }
// command "test" [call] // command "test" [call]
TestCommand(data: string, opts?: RpcOpts): Promise<void> { TestCommand(data: string, opts?: RpcOpts): Promise<void> {
return WOS.wshServerRpcHelper_call("test", data, opts); return WOS.wshServerRpcHelper_call("test", data, opts);
} }

View File

@ -8,6 +8,7 @@ import (
"reflect" "reflect"
"strings" "strings"
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
"github.com/wavetermdev/thenextwave/pkg/wshrpc" "github.com/wavetermdev/thenextwave/pkg/wshrpc"
) )
@ -42,10 +43,7 @@ func GenerateMetaMapConsts(buf *strings.Builder, constPrefix string, rtype refle
continue continue
} }
fieldName := field.Name fieldName := field.Name
jsonTag := field.Tag.Get("json") jsonTag := utilfn.GetJsonTag(field)
if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 {
jsonTag = jsonTag[:commaIdx]
}
if jsonTag == "" { if jsonTag == "" {
jsonTag = fieldName jsonTag = fieldName
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/wavetermdev/thenextwave/pkg/service" "github.com/wavetermdev/thenextwave/pkg/service"
"github.com/wavetermdev/thenextwave/pkg/tsgen/tsgenmeta" "github.com/wavetermdev/thenextwave/pkg/tsgen/tsgenmeta"
"github.com/wavetermdev/thenextwave/pkg/userinput" "github.com/wavetermdev/thenextwave/pkg/userinput"
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
"github.com/wavetermdev/thenextwave/pkg/vdom" "github.com/wavetermdev/thenextwave/pkg/vdom"
"github.com/wavetermdev/thenextwave/pkg/waveobj" "github.com/wavetermdev/thenextwave/pkg/waveobj"
"github.com/wavetermdev/thenextwave/pkg/wconfig" "github.com/wavetermdev/thenextwave/pkg/wconfig"
@ -84,20 +85,15 @@ func getTSFieldName(field reflect.StructField) string {
} }
return tsFieldTag return tsFieldTag
} }
jsonTag := field.Tag.Get("json") jsonTag := utilfn.GetJsonTag(field)
if jsonTag == "-" {
return ""
}
if strings.Contains(jsonTag, ":") {
return "\"" + jsonTag + "\""
}
if jsonTag != "" { if jsonTag != "" {
parts := strings.Split(jsonTag, ",") return jsonTag
namePart := parts[0]
if namePart != "" {
if namePart == "-" {
return ""
}
if strings.Contains(namePart, ":") {
return "\"" + namePart + "\""
}
return namePart
}
// if namePart is empty, still uses default
} }
return field.Name return field.Name
} }
@ -452,9 +448,9 @@ func GenerateWshServerMethod_Call(methodDecl *wshrpc.WshRpcMethodDecl, tsTypesMa
dataName = "data" dataName = "data"
} }
if methodDecl.CommandDataType != nil { if methodDecl.CommandDataType != nil {
sb.WriteString(fmt.Sprintf(" %s(data: %s, opts?: RpcOpts): %s {\n", methodDecl.MethodName, methodDecl.CommandDataType.Name(), rtnType)) sb.WriteString(fmt.Sprintf(" %s(data: %s, opts?: RpcOpts): %s {\n", methodDecl.MethodName, methodDecl.CommandDataType.Name(), rtnType))
} else { } else {
sb.WriteString(fmt.Sprintf(" %s(opts?: RpcOpts): %s {\n", methodDecl.MethodName, rtnType)) sb.WriteString(fmt.Sprintf(" %s(opts?: RpcOpts): %s {\n", methodDecl.MethodName, rtnType))
} }
methodBody := fmt.Sprintf(" return WOS.wshServerRpcHelper_call(%q, %s, opts);\n", methodDecl.Command, dataName) methodBody := fmt.Sprintf(" return WOS.wshServerRpcHelper_call(%q, %s, opts);\n", methodDecl.Command, dataName)
sb.WriteString(methodBody) sb.WriteString(methodBody)

View File

@ -20,6 +20,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"reflect"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
@ -899,3 +900,15 @@ func RandomHexString(numHexDigits int) (string, error) {
hexStr := hex.EncodeToString(bytes) hexStr := hex.EncodeToString(bytes)
return hexStr[:numHexDigits], nil // Return the exact number of hex digits return hexStr[:numHexDigits], nil // Return the exact number of hex digits
} }
func GetJsonTag(field reflect.StructField) string {
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
return ""
}
commaIdx := strings.Index(jsonTag, ",")
if commaIdx != -1 {
jsonTag = jsonTag[:commaIdx]
}
return jsonTag
}

View File

@ -13,6 +13,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
) )
const ( const (
@ -127,7 +128,8 @@ func RegisterType(rtype reflect.Type) {
if oidField.Type.Kind() != reflect.String { if oidField.Type.Kind() != reflect.String {
panic(fmt.Sprintf("OID field must be string for %v", rtype)) panic(fmt.Sprintf("OID field must be string for %v", rtype))
} }
if oidField.Tag.Get("json") != OIDKeyName { oidJsonTag := utilfn.GetJsonTag(oidField)
if oidJsonTag != OIDKeyName {
panic(fmt.Sprintf("OID field json tag must be %q for %v", OIDKeyName, rtype)) panic(fmt.Sprintf("OID field json tag must be %q for %v", OIDKeyName, rtype))
} }
versionField, found := rtype.Elem().FieldByName(VersionGoFieldName) versionField, found := rtype.Elem().FieldByName(VersionGoFieldName)
@ -137,7 +139,8 @@ func RegisterType(rtype reflect.Type) {
if versionField.Type.Kind() != reflect.Int { if versionField.Type.Kind() != reflect.Int {
panic(fmt.Sprintf("Version field must be int for %v", rtype)) panic(fmt.Sprintf("Version field must be int for %v", rtype))
} }
if versionField.Tag.Get("json") != VersionKeyName { versionJsonTag := utilfn.GetJsonTag(versionField)
if versionJsonTag != VersionKeyName {
panic(fmt.Sprintf("Version field json tag must be %q for %v", VersionKeyName, rtype)) panic(fmt.Sprintf("Version field json tag must be %q for %v", VersionKeyName, rtype))
} }
metaField, found := rtype.Elem().FieldByName(MetaGoFieldName) metaField, found := rtype.Elem().FieldByName(MetaGoFieldName)

View File

@ -157,12 +157,12 @@ func ReadFullConfig() FullConfigType {
if configFile == "-" { if configFile == "-" {
continue continue
} }
jsonTag := field.Tag.Get("json") jsonTag := utilfn.GetJsonTag(field)
if jsonTag == "-" || jsonTag == "" { if jsonTag == "-" || jsonTag == "" {
continue continue
} }
simpleMerge := field.Tag.Get("merge") == "" simpleMerge := field.Tag.Get("merge") == ""
fileName := field.Tag.Get("json") + ".json" fileName := jsonTag + ".json"
configPart, cerrs := ReadConfigPart(fileName, simpleMerge) configPart, cerrs := ReadConfigPart(fileName, simpleMerge)
fullConfig.ConfigErrors = append(fullConfig.ConfigErrors, cerrs...) fullConfig.ConfigErrors = append(fullConfig.ConfigErrors, cerrs...)
if configPart != nil { if configPart != nil {
@ -177,7 +177,8 @@ func getConfigKeyType(configKey string) reflect.Type {
ctype := reflect.TypeOf(SettingsType{}) ctype := reflect.TypeOf(SettingsType{})
for i := 0; i < ctype.NumField(); i++ { for i := 0; i < ctype.NumField(); i++ {
field := ctype.Field(i) field := ctype.Field(i)
if field.Tag.Get("json") == configKey { jsonTag := utilfn.GetJsonTag(field)
if jsonTag == configKey {
return field.Type return field.Type
} }
} }
@ -261,11 +262,7 @@ func jsonMarshalConfigInOrder(m waveobj.MetaMapType) ([]byte, error) {
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func SetBaseConfigValue(configKey string, val any) error { func SetBaseConfigValue(toMerge waveobj.MetaMapType) error {
ctype := getConfigKeyType(configKey)
if ctype == nil {
return fmt.Errorf("invalid config key: %s", configKey)
}
m, cerrs := ReadWaveHomeConfigFile(SettingsFile) m, cerrs := ReadWaveHomeConfigFile(SettingsFile)
if len(cerrs) > 0 { if len(cerrs) > 0 {
return fmt.Errorf("error reading config file: %v", cerrs[0]) return fmt.Errorf("error reading config file: %v", cerrs[0])
@ -273,13 +270,19 @@ func SetBaseConfigValue(configKey string, val any) error {
if m == nil { if m == nil {
m = make(waveobj.MetaMapType) m = make(waveobj.MetaMapType)
} }
if val == nil { for configKey, val := range toMerge {
delete(m, configKey) ctype := getConfigKeyType(configKey)
} else { if ctype == nil {
if reflect.TypeOf(val) != ctype { return fmt.Errorf("invalid config key: %s", configKey)
return fmt.Errorf("invalid value type for %s: %T", configKey, val) }
if val == nil {
delete(m, configKey)
} else {
if reflect.TypeOf(val) != ctype {
return fmt.Errorf("invalid value type for %s: %T", configKey, val)
}
m[configKey] = val
} }
m[configKey] = val
} }
return WriteWaveHomeConfigFile(SettingsFile, m) return WriteWaveHomeConfigFile(SettingsFile, m)
} }

View File

@ -147,6 +147,12 @@ func ResolveIdsCommand(w *wshutil.WshRpc, data wshrpc.CommandResolveIdsData, opt
return resp, err return resp, err
} }
// command "setconfig", wshserver.SetConfigCommand
func SetConfigCommand(w *wshutil.WshRpc, data waveobj.MetaMapType, opts *wshrpc.RpcOpts) error {
_, err := sendRpcRequestCallHelper[any](w, "setconfig", data, opts)
return err
}
// command "setmeta", wshserver.SetMetaCommand // command "setmeta", wshserver.SetMetaCommand
func SetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandSetMetaData, opts *wshrpc.RpcOpts) error { func SetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandSetMetaData, opts *wshrpc.RpcOpts) error {
_, err := sendRpcRequestCallHelper[any](w, "setmeta", data, opts) _, err := sendRpcRequestCallHelper[any](w, "setmeta", data, opts)

View File

@ -90,6 +90,7 @@ type WshRpcInterface interface {
StreamWaveAiCommand(ctx context.Context, request OpenAiStreamRequest) chan RespOrErrorUnion[OpenAIPacketType] StreamWaveAiCommand(ctx context.Context, request OpenAiStreamRequest) chan RespOrErrorUnion[OpenAIPacketType]
StreamCpuDataCommand(ctx context.Context, request CpuDataRequest) chan RespOrErrorUnion[TimeSeriesData] StreamCpuDataCommand(ctx context.Context, request CpuDataRequest) chan RespOrErrorUnion[TimeSeriesData]
TestCommand(ctx context.Context, data string) error TestCommand(ctx context.Context, data string) error
SetConfigCommand(ctx context.Context, data waveobj.MetaMapType) error
// eventrecv is special, it's handled internally by WshRpc with EventListener // eventrecv is special, it's handled internally by WshRpc with EventListener
EventRecvCommand(ctx context.Context, data WaveEvent) error EventRecvCommand(ctx context.Context, data WaveEvent) error

View File

@ -21,6 +21,7 @@ import (
"github.com/wavetermdev/thenextwave/pkg/filestore" "github.com/wavetermdev/thenextwave/pkg/filestore"
"github.com/wavetermdev/thenextwave/pkg/waveai" "github.com/wavetermdev/thenextwave/pkg/waveai"
"github.com/wavetermdev/thenextwave/pkg/waveobj" "github.com/wavetermdev/thenextwave/pkg/waveobj"
"github.com/wavetermdev/thenextwave/pkg/wconfig"
"github.com/wavetermdev/thenextwave/pkg/wcore" "github.com/wavetermdev/thenextwave/pkg/wcore"
"github.com/wavetermdev/thenextwave/pkg/wlayout" "github.com/wavetermdev/thenextwave/pkg/wlayout"
"github.com/wavetermdev/thenextwave/pkg/wps" "github.com/wavetermdev/thenextwave/pkg/wps"
@ -477,3 +478,7 @@ func (ws *WshServer) EventUnsubAllCommand(ctx context.Context) error {
wps.Broker.UnsubscribeAll(rpcSource) wps.Broker.UnsubscribeAll(rpcSource)
return nil return nil
} }
func (ws *WshServer) SetConfigCommand(ctx context.Context, data waveobj.MetaMapType) error {
return wconfig.SetBaseConfigValue(data)
}