2024-07-18 00:24:43 +02:00
|
|
|
// Copyright 2024, Command Line Inc.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
package wshserver
|
|
|
|
|
2024-07-19 00:56:04 +02:00
|
|
|
// this file contains the implementation of the wsh server methods
|
|
|
|
|
2024-07-18 00:24:43 +02:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
2024-07-31 23:13:36 +02:00
|
|
|
"encoding/json"
|
2024-07-18 00:24:43 +02:00
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
|
|
|
"log"
|
2024-08-31 05:20:25 +02:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2024-07-18 00:24:43 +02:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
|
|
|
"github.com/wavetermdev/thenextwave/pkg/eventbus"
|
|
|
|
"github.com/wavetermdev/thenextwave/pkg/filestore"
|
2024-07-25 11:30:49 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/waveai"
|
2024-07-18 00:24:43 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
2024-08-28 07:02:21 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
2024-08-20 23:56:48 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wcore"
|
2024-08-28 03:38:57 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wlayout"
|
2024-07-26 22:30:11 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wps"
|
2024-07-18 00:24:43 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
2024-08-12 19:58:39 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
|
2024-07-18 00:24:43 +02:00
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wshutil"
|
|
|
|
"github.com/wavetermdev/thenextwave/pkg/wstore"
|
|
|
|
)
|
|
|
|
|
2024-08-10 03:37:23 +02:00
|
|
|
const SimpleId_This = "this"
|
|
|
|
|
2024-08-31 05:20:25 +02:00
|
|
|
var SimpleId_BlockNum_Regex = regexp.MustCompile(`^\d+$`)
|
|
|
|
|
2024-08-14 01:52:35 +02:00
|
|
|
type WshServer struct{}
|
|
|
|
|
|
|
|
func (*WshServer) WshServerImpl() {}
|
|
|
|
|
|
|
|
var WshServerImpl = WshServer{}
|
|
|
|
|
2024-08-12 19:58:39 +02:00
|
|
|
func (ws *WshServer) TestCommand(ctx context.Context, data string) error {
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
log.Printf("panic in TestCommand: %v", r)
|
|
|
|
}
|
|
|
|
}()
|
2024-08-14 01:52:35 +02:00
|
|
|
rpcSource := wshutil.GetRpcSourceFromContext(ctx)
|
|
|
|
log.Printf("TEST src:%s | %s\n", rpcSource, data)
|
|
|
|
if rpcSource == "" {
|
2024-08-12 19:58:39 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
go func() {
|
2024-08-14 01:52:35 +02:00
|
|
|
mainClient := GetMainRpcClient()
|
|
|
|
wshclient.MessageCommand(mainClient, wshrpc.CommandMessageData{Message: "test message"}, &wshrpc.RpcOpts{NoResponse: true, Route: rpcSource})
|
|
|
|
resp, err := wshclient.RemoteFileInfoCommand(mainClient, "~/work/wails/thenextwave/README.md", &wshrpc.RpcOpts{Route: rpcSource})
|
2024-08-12 19:58:39 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("error getting remote file info: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf("remote file info: %#v\n", resp)
|
2024-08-14 01:52:35 +02:00
|
|
|
rch := wshclient.RemoteStreamFileCommand(mainClient, wshrpc.CommandRemoteStreamFileData{Path: "~/work/wails/thenextwave/README.md"}, &wshrpc.RpcOpts{Route: rpcSource})
|
2024-08-12 19:58:39 +02:00
|
|
|
for msg := range rch {
|
|
|
|
if msg.Error != nil {
|
|
|
|
log.Printf("error in stream: %v", msg.Error)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if msg.Response.FileInfo != nil {
|
|
|
|
log.Printf("stream resp (fileinfo): %v\n", msg.Response.FileInfo)
|
|
|
|
}
|
|
|
|
if msg.Response.Data64 != "" {
|
|
|
|
log.Printf("stream resp (data): %v\n", len(msg.Response.Data64))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-19 00:56:04 +02:00
|
|
|
// for testing
|
2024-07-18 00:24:43 +02:00
|
|
|
func (ws *WshServer) MessageCommand(ctx context.Context, data wshrpc.CommandMessageData) error {
|
|
|
|
log.Printf("MESSAGE: %s | %q\n", data.ORef, data.Message)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-19 00:56:04 +02:00
|
|
|
// for testing
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) StreamTestCommand(ctx context.Context) chan wshrpc.RespOrErrorUnion[int] {
|
2024-07-19 00:56:04 +02:00
|
|
|
rtn := make(chan wshrpc.RespOrErrorUnion[int])
|
|
|
|
go func() {
|
|
|
|
for i := 1; i <= 5; i++ {
|
|
|
|
rtn <- wshrpc.RespOrErrorUnion[int]{Response: i}
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
|
|
|
close(rtn)
|
|
|
|
}()
|
|
|
|
return rtn
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) StreamWaveAiCommand(ctx context.Context, request wshrpc.OpenAiStreamRequest) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
|
2024-07-25 11:30:49 +02:00
|
|
|
if request.Opts.BaseURL == "" && request.Opts.APIToken == "" {
|
|
|
|
return waveai.RunCloudCompletionStream(ctx, request)
|
|
|
|
}
|
|
|
|
return waveai.RunLocalCompletionStream(ctx, request)
|
|
|
|
}
|
|
|
|
|
2024-07-31 23:13:36 +02:00
|
|
|
func MakePlotData(ctx context.Context, blockId string) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
block, err := wstore.DBMustGet[*waveobj.Block](ctx, blockId)
|
2024-07-31 23:13:36 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
viewName := block.Meta.GetString(waveobj.MetaKey_View, "")
|
2024-07-31 23:13:36 +02:00
|
|
|
if viewName != "cpuplot" {
|
|
|
|
return fmt.Errorf("invalid view type: %s", viewName)
|
|
|
|
}
|
|
|
|
return filestore.WFS.MakeFile(ctx, blockId, "cpuplotdata", nil, filestore.FileOptsType{})
|
|
|
|
}
|
|
|
|
|
|
|
|
func SavePlotData(ctx context.Context, blockId string, history string) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
block, err := wstore.DBMustGet[*waveobj.Block](ctx, blockId)
|
2024-07-31 23:13:36 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
viewName := block.Meta.GetString(waveobj.MetaKey_View, "")
|
2024-07-31 23:13:36 +02:00
|
|
|
if viewName != "cpuplot" {
|
|
|
|
return fmt.Errorf("invalid view type: %s", viewName)
|
|
|
|
}
|
|
|
|
// todo: interpret the data being passed
|
|
|
|
// for now, this is just to throw an error if the block was closed
|
|
|
|
historyBytes, err := json.Marshal(history)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to serialize plot data: %v", err)
|
|
|
|
}
|
|
|
|
// ignore MakeFile error (already exists is ok)
|
|
|
|
return filestore.WFS.WriteFile(ctx, blockId, "cpuplotdata", historyBytes)
|
|
|
|
}
|
|
|
|
|
2024-07-30 21:33:28 +02:00
|
|
|
func (ws *WshServer) GetMetaCommand(ctx context.Context, data wshrpc.CommandGetMetaData) (waveobj.MetaMapType, error) {
|
2024-07-18 00:24:43 +02:00
|
|
|
obj, err := wstore.DBGetORef(ctx, data.ORef)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error getting object: %w", err)
|
|
|
|
}
|
|
|
|
if obj == nil {
|
|
|
|
return nil, fmt.Errorf("object not found: %s", data.ORef)
|
|
|
|
}
|
|
|
|
return waveobj.GetMeta(obj), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) SetMetaCommand(ctx context.Context, data wshrpc.CommandSetMetaData) error {
|
2024-07-23 22:16:53 +02:00
|
|
|
log.Printf("SETMETA: %s | %v\n", data.ORef, data.Meta)
|
2024-07-18 00:24:43 +02:00
|
|
|
oref := data.ORef
|
2024-07-30 21:33:28 +02:00
|
|
|
err := wstore.UpdateObjectMeta(ctx, oref, data.Meta)
|
2024-07-18 00:24:43 +02:00
|
|
|
if err != nil {
|
2024-07-30 21:33:28 +02:00
|
|
|
return fmt.Errorf("error updating object meta: %w", err)
|
2024-07-18 00:24:43 +02:00
|
|
|
}
|
|
|
|
sendWaveObjUpdate(oref)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendWaveObjUpdate(oref waveobj.ORef) {
|
|
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancelFn()
|
|
|
|
// send a waveobj:update event
|
|
|
|
waveObj, err := wstore.DBGetORef(ctx, oref)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error getting object for update event: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
eventbus.SendEvent(eventbus.WSEventType{
|
|
|
|
EventType: eventbus.WSEvent_WaveObjUpdate,
|
|
|
|
ORef: oref.String(),
|
2024-08-20 23:56:48 +02:00
|
|
|
Data: waveobj.WaveObjUpdate{
|
|
|
|
UpdateType: waveobj.UpdateType_Update,
|
2024-07-18 00:24:43 +02:00
|
|
|
OType: waveObj.GetOType(),
|
|
|
|
OID: waveobj.GetOID(waveObj),
|
|
|
|
Obj: waveObj,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-08-14 01:52:35 +02:00
|
|
|
func resolveSimpleId(ctx context.Context, data wshrpc.CommandResolveIdsData, simpleId string) (*waveobj.ORef, error) {
|
2024-08-10 03:37:23 +02:00
|
|
|
if simpleId == SimpleId_This {
|
2024-08-14 01:52:35 +02:00
|
|
|
if data.BlockId == "" {
|
|
|
|
return nil, fmt.Errorf("no blockid in request")
|
2024-08-10 03:37:23 +02:00
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
return &waveobj.ORef{OType: waveobj.OType_Block, OID: data.BlockId}, nil
|
2024-08-10 03:37:23 +02:00
|
|
|
}
|
2024-08-31 05:20:25 +02:00
|
|
|
blockNum, err := strconv.Atoi(simpleId)
|
|
|
|
if err == nil {
|
|
|
|
tabId, err := wstore.DBFindTabForBlockId(ctx, data.BlockId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error finding tab for blockid %s: %w", data.BlockId, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error retrieving tab %s: %w", tabId, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
layout, err := wstore.DBGet[*waveobj.LayoutState](ctx, tab.LayoutState)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error retrieving layout state %s: %w", tab.LayoutState, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if layout.LeafOrder == nil {
|
|
|
|
return nil, fmt.Errorf("could not resolve block num %v, leaf order is empty", blockNum)
|
|
|
|
}
|
|
|
|
|
|
|
|
leafIndex := blockNum - 1 // block nums are 1-indexed, we need the 0-indexed version
|
|
|
|
if len(*layout.LeafOrder) <= leafIndex {
|
|
|
|
return nil, fmt.Errorf("could not find a node in the layout matching blockNum %v", blockNum)
|
|
|
|
}
|
|
|
|
leafEntry := (*layout.LeafOrder)[leafIndex]
|
|
|
|
return &waveobj.ORef{OType: waveobj.OType_Block, OID: leafEntry.BlockId}, nil
|
|
|
|
} else if strings.Contains(simpleId, ":") {
|
2024-07-18 00:24:43 +02:00
|
|
|
rtn, err := waveobj.ParseORef(simpleId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error parsing simple id: %w", err)
|
|
|
|
}
|
|
|
|
return &rtn, nil
|
|
|
|
}
|
|
|
|
return wstore.DBResolveEasyOID(ctx, simpleId)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) ResolveIdsCommand(ctx context.Context, data wshrpc.CommandResolveIdsData) (wshrpc.CommandResolveIdsRtnData, error) {
|
|
|
|
rtn := wshrpc.CommandResolveIdsRtnData{}
|
|
|
|
rtn.ResolvedIds = make(map[string]waveobj.ORef)
|
|
|
|
for _, simpleId := range data.Ids {
|
2024-08-14 01:52:35 +02:00
|
|
|
oref, err := resolveSimpleId(ctx, data, simpleId)
|
2024-07-18 00:24:43 +02:00
|
|
|
if err != nil || oref == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
rtn.ResolvedIds[simpleId] = *oref
|
|
|
|
}
|
|
|
|
return rtn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) CreateBlockCommand(ctx context.Context, data wshrpc.CommandCreateBlockData) (*waveobj.ORef, error) {
|
2024-08-20 23:56:48 +02:00
|
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
2024-07-18 00:24:43 +02:00
|
|
|
tabId := data.TabId
|
2024-08-28 03:38:57 +02:00
|
|
|
blockData, err := wcore.CreateBlock(ctx, tabId, data.BlockDef, data.RtOpts)
|
2024-07-18 00:24:43 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error creating block: %w", err)
|
|
|
|
}
|
2024-08-28 03:38:57 +02:00
|
|
|
blockRef := &waveobj.ORef{OType: waveobj.OType_Block, OID: blockData.OID}
|
2024-07-18 00:24:43 +02:00
|
|
|
windowId, err := wstore.DBFindWindowForTabId(ctx, tabId)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error finding window for tab: %w", err)
|
|
|
|
}
|
|
|
|
if windowId == "" {
|
|
|
|
return nil, fmt.Errorf("no window found for tab")
|
|
|
|
}
|
2024-08-30 03:23:12 +02:00
|
|
|
err = wlayout.QueueLayoutActionForTab(ctx, tabId, waveobj.LayoutActionData{
|
2024-08-28 03:38:57 +02:00
|
|
|
ActionType: wlayout.LayoutActionDataType_Insert,
|
|
|
|
BlockId: blockRef.OID,
|
2024-08-28 08:16:07 +02:00
|
|
|
Magnified: data.Magnified,
|
|
|
|
Focused: true,
|
2024-07-18 00:24:43 +02:00
|
|
|
})
|
2024-08-30 03:23:12 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error queuing layout action: %w", err)
|
|
|
|
}
|
|
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
2024-08-30 03:39:27 +02:00
|
|
|
eventbus.SendUpdateEvents(updates)
|
2024-08-27 00:17:37 +02:00
|
|
|
return &waveobj.ORef{OType: waveobj.OType_Block, OID: blockRef.OID}, nil
|
2024-07-18 00:24:43 +02:00
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) SetViewCommand(ctx context.Context, data wshrpc.CommandBlockSetViewData) error {
|
2024-07-18 00:24:43 +02:00
|
|
|
log.Printf("SETVIEW: %s | %q\n", data.BlockId, data.View)
|
2024-08-20 23:56:48 +02:00
|
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
|
|
|
block, err := wstore.DBGet[*waveobj.Block](ctx, data.BlockId)
|
2024-07-18 00:24:43 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error getting block: %w", err)
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
block.Meta[waveobj.MetaKey_View] = data.View
|
2024-07-18 00:24:43 +02:00
|
|
|
err = wstore.DBUpdate(ctx, block)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error updating block: %w", err)
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
2024-08-30 03:39:27 +02:00
|
|
|
eventbus.SendUpdateEvents(updates)
|
2024-07-18 00:24:43 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) ControllerRestartCommand(ctx context.Context, data wshrpc.CommandBlockRestartData) error {
|
2024-07-18 00:24:43 +02:00
|
|
|
bc := blockcontroller.GetBlockController(data.BlockId)
|
|
|
|
if bc == nil {
|
|
|
|
return fmt.Errorf("block controller not found for block %q", data.BlockId)
|
|
|
|
}
|
|
|
|
return bc.RestartController()
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) ControllerInputCommand(ctx context.Context, data wshrpc.CommandBlockInputData) error {
|
2024-07-18 00:24:43 +02:00
|
|
|
bc := blockcontroller.GetBlockController(data.BlockId)
|
|
|
|
if bc == nil {
|
|
|
|
return fmt.Errorf("block controller not found for block %q", data.BlockId)
|
|
|
|
}
|
|
|
|
inputUnion := &blockcontroller.BlockInputUnion{
|
|
|
|
SigName: data.SigName,
|
|
|
|
TermSize: data.TermSize,
|
|
|
|
}
|
|
|
|
if len(data.InputData64) > 0 {
|
|
|
|
inputBuf := make([]byte, base64.StdEncoding.DecodedLen(len(data.InputData64)))
|
|
|
|
nw, err := base64.StdEncoding.Decode(inputBuf, []byte(data.InputData64))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error decoding input data: %w", err)
|
|
|
|
}
|
|
|
|
inputUnion.InputData = inputBuf[:nw]
|
|
|
|
}
|
|
|
|
return bc.SendInput(inputUnion)
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) FileWriteCommand(ctx context.Context, data wshrpc.CommandFileData) error {
|
2024-07-23 22:16:53 +02:00
|
|
|
dataBuf, err := base64.StdEncoding.DecodeString(data.Data64)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error decoding data64: %w", err)
|
|
|
|
}
|
|
|
|
err = filestore.WFS.WriteFile(ctx, data.ZoneId, data.FileName, dataBuf)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error writing to blockfile: %w", err)
|
|
|
|
}
|
|
|
|
eventbus.SendEvent(eventbus.WSEventType{
|
|
|
|
EventType: eventbus.WSEvent_BlockFile,
|
2024-08-20 23:56:48 +02:00
|
|
|
ORef: waveobj.MakeORef(waveobj.OType_Block, data.ZoneId).String(),
|
2024-07-23 22:16:53 +02:00
|
|
|
Data: &eventbus.WSFileEventData{
|
|
|
|
ZoneId: data.ZoneId,
|
|
|
|
FileName: data.FileName,
|
|
|
|
FileOp: eventbus.FileOp_Invalidate,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) FileReadCommand(ctx context.Context, data wshrpc.CommandFileData) (string, error) {
|
2024-07-23 22:16:53 +02:00
|
|
|
_, dataBuf, err := filestore.WFS.ReadFile(ctx, data.ZoneId, data.FileName)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error reading blockfile: %w", err)
|
|
|
|
}
|
|
|
|
return base64.StdEncoding.EncodeToString(dataBuf), nil
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) FileAppendCommand(ctx context.Context, data wshrpc.CommandFileData) error {
|
2024-07-18 00:24:43 +02:00
|
|
|
dataBuf, err := base64.StdEncoding.DecodeString(data.Data64)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error decoding data64: %w", err)
|
|
|
|
}
|
|
|
|
err = filestore.WFS.AppendData(ctx, data.ZoneId, data.FileName, dataBuf)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error appending to blockfile: %w", err)
|
|
|
|
}
|
|
|
|
eventbus.SendEvent(eventbus.WSEventType{
|
|
|
|
EventType: eventbus.WSEvent_BlockFile,
|
2024-08-20 23:56:48 +02:00
|
|
|
ORef: waveobj.MakeORef(waveobj.OType_Block, data.ZoneId).String(),
|
2024-07-18 00:24:43 +02:00
|
|
|
Data: &eventbus.WSFileEventData{
|
|
|
|
ZoneId: data.ZoneId,
|
|
|
|
FileName: data.FileName,
|
|
|
|
FileOp: eventbus.FileOp_Append,
|
|
|
|
Data64: base64.StdEncoding.EncodeToString(dataBuf),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-26 22:30:11 +02:00
|
|
|
func (ws *WshServer) FileAppendIJsonCommand(ctx context.Context, data wshrpc.CommandAppendIJsonData) error {
|
2024-07-18 00:24:43 +02:00
|
|
|
tryCreate := true
|
|
|
|
if data.FileName == blockcontroller.BlockFile_Html && tryCreate {
|
|
|
|
err := filestore.WFS.MakeFile(ctx, data.ZoneId, data.FileName, nil, filestore.FileOptsType{MaxSize: blockcontroller.DefaultHtmlMaxFileSize, IJson: true})
|
|
|
|
if err != nil && err != fs.ErrExist {
|
|
|
|
return fmt.Errorf("error creating blockfile[html]: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err := filestore.WFS.AppendIJson(ctx, data.ZoneId, data.FileName, data.Data)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error appending to blockfile(ijson): %w", err)
|
|
|
|
}
|
|
|
|
eventbus.SendEvent(eventbus.WSEventType{
|
|
|
|
EventType: eventbus.WSEvent_BlockFile,
|
2024-08-20 23:56:48 +02:00
|
|
|
ORef: waveobj.MakeORef(waveobj.OType_Block, data.ZoneId).String(),
|
2024-07-18 00:24:43 +02:00
|
|
|
Data: &eventbus.WSFileEventData{
|
|
|
|
ZoneId: data.ZoneId,
|
|
|
|
FileName: data.FileName,
|
|
|
|
FileOp: eventbus.FileOp_Append,
|
|
|
|
Data64: base64.StdEncoding.EncodeToString([]byte("{}")),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
2024-07-19 03:13:59 +02:00
|
|
|
|
|
|
|
func (ws *WshServer) DeleteBlockCommand(ctx context.Context, data wshrpc.CommandDeleteBlockData) error {
|
2024-08-20 23:56:48 +02:00
|
|
|
ctx = waveobj.ContextWithUpdates(ctx)
|
2024-07-19 03:13:59 +02:00
|
|
|
tabId, err := wstore.DBFindTabForBlockId(ctx, data.BlockId)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error finding tab for block: %w", err)
|
|
|
|
}
|
|
|
|
if tabId == "" {
|
|
|
|
return fmt.Errorf("no tab found for block")
|
|
|
|
}
|
|
|
|
windowId, err := wstore.DBFindWindowForTabId(ctx, tabId)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error finding window for tab: %w", err)
|
|
|
|
}
|
|
|
|
if windowId == "" {
|
|
|
|
return fmt.Errorf("no window found for tab")
|
|
|
|
}
|
2024-08-20 23:56:48 +02:00
|
|
|
err = wcore.DeleteBlock(ctx, tabId, data.BlockId)
|
2024-07-19 03:13:59 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error deleting block: %w", err)
|
|
|
|
}
|
2024-08-28 03:38:57 +02:00
|
|
|
wlayout.QueueLayoutActionForTab(ctx, tabId, waveobj.LayoutActionData{
|
|
|
|
ActionType: wlayout.LayoutActionDataType_Remove,
|
|
|
|
BlockId: data.BlockId,
|
2024-07-19 03:13:59 +02:00
|
|
|
})
|
2024-08-20 23:56:48 +02:00
|
|
|
updates := waveobj.ContextGetUpdatesRtn(ctx)
|
2024-08-30 03:39:27 +02:00
|
|
|
eventbus.SendUpdateEvents(updates)
|
2024-07-19 03:13:59 +02:00
|
|
|
return nil
|
|
|
|
}
|
2024-07-26 22:30:11 +02:00
|
|
|
|
|
|
|
func (ws *WshServer) EventRecvCommand(ctx context.Context, data wshrpc.WaveEvent) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) EventPublishCommand(ctx context.Context, data wshrpc.WaveEvent) error {
|
2024-08-14 01:52:35 +02:00
|
|
|
rpcSource := wshutil.GetRpcSourceFromContext(ctx)
|
|
|
|
if rpcSource == "" {
|
|
|
|
return fmt.Errorf("no rpc source set")
|
2024-07-26 22:30:11 +02:00
|
|
|
}
|
|
|
|
if data.Sender == "" {
|
2024-08-14 01:52:35 +02:00
|
|
|
data.Sender = rpcSource
|
2024-07-26 22:30:11 +02:00
|
|
|
}
|
|
|
|
wps.Broker.Publish(data)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) EventSubCommand(ctx context.Context, data wshrpc.SubscriptionRequest) error {
|
2024-08-14 01:52:35 +02:00
|
|
|
rpcSource := wshutil.GetRpcSourceFromContext(ctx)
|
|
|
|
if rpcSource == "" {
|
|
|
|
return fmt.Errorf("no rpc source set")
|
2024-07-26 22:30:11 +02:00
|
|
|
}
|
2024-08-14 01:52:35 +02:00
|
|
|
wps.Broker.Subscribe(rpcSource, data)
|
2024-07-26 22:30:11 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-08-24 03:12:40 +02:00
|
|
|
func (ws *WshServer) EventUnsubCommand(ctx context.Context, data string) error {
|
2024-08-14 01:52:35 +02:00
|
|
|
rpcSource := wshutil.GetRpcSourceFromContext(ctx)
|
|
|
|
if rpcSource == "" {
|
|
|
|
return fmt.Errorf("no rpc source set")
|
2024-07-26 22:30:11 +02:00
|
|
|
}
|
2024-08-14 01:52:35 +02:00
|
|
|
wps.Broker.Unsubscribe(rpcSource, data)
|
2024-07-26 22:30:11 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ws *WshServer) EventUnsubAllCommand(ctx context.Context) error {
|
2024-08-14 01:52:35 +02:00
|
|
|
rpcSource := wshutil.GetRpcSourceFromContext(ctx)
|
|
|
|
if rpcSource == "" {
|
|
|
|
return fmt.Errorf("no rpc source set")
|
2024-07-26 22:30:11 +02:00
|
|
|
}
|
2024-08-14 01:52:35 +02:00
|
|
|
wps.Broker.UnsubscribeAll(rpcSource)
|
2024-07-26 22:30:11 +02:00
|
|
|
return nil
|
|
|
|
}
|
2024-08-28 07:02:21 +02:00
|
|
|
|
2024-08-30 20:33:04 +02:00
|
|
|
func (ws *WshServer) EventReadHistoryCommand(ctx context.Context, data wshrpc.CommandEventReadHistoryData) ([]*wshrpc.WaveEvent, error) {
|
|
|
|
events := wps.Broker.ReadEventHistory(data.Event, data.Scope, data.MaxItems)
|
|
|
|
return events, nil
|
|
|
|
}
|
|
|
|
|
2024-09-03 05:21:35 +02:00
|
|
|
func (ws *WshServer) SetConfigCommand(ctx context.Context, data wconfig.MetaSettingsType) error {
|
|
|
|
log.Printf("SETCONFIG: %v\n", data)
|
|
|
|
return wconfig.SetBaseConfigValue(data.MetaMapType)
|
2024-08-28 07:02:21 +02:00
|
|
|
}
|