mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
8acda3525b
* Break update code out of sstore * add license disclaimers * missed one * add another * fix regression in openai updates, remove unnecessary functions * another copyright * update casts * fix issue with variadic updates * remove logs * remove log * remove unnecessary log * save work * moved a bunch of stuff to scbus * make modelupdate an object * fix new screen not updating active screen * add comment * make updates into packet types * different cast * update comments, remove unused methods * add one more comment * add an IsEmpty() on model updates to prevent sending empty updates to client
229 lines
5.5 KiB
Go
229 lines
5.5 KiB
Go
// Copyright 2023, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package sstore
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/cirfile"
|
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shexec"
|
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
|
|
)
|
|
|
|
func CreateCmdPtyFile(ctx context.Context, screenId string, lineId string, maxSize int64) error {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err := cirfile.CreateCirFile(ptyOutFileName, maxSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return f.Close()
|
|
}
|
|
|
|
func StatCmdPtyFile(ctx context.Context, screenId string, lineId string) (*cirfile.Stat, error) {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cirfile.StatCirFile(ctx, ptyOutFileName)
|
|
}
|
|
|
|
func ClearCmdPtyFile(ctx context.Context, screenId string, lineId string) error {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
stat, err := cirfile.StatCirFile(ctx, ptyOutFileName)
|
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
|
return err
|
|
}
|
|
os.Remove(ptyOutFileName) // ignore error
|
|
var maxSize int64 = shexec.DefaultMaxPtySize
|
|
if stat != nil {
|
|
maxSize = stat.MaxSize
|
|
}
|
|
err = CreateCmdPtyFile(ctx, screenId, lineId, maxSize)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func AppendToCmdPtyBlob(ctx context.Context, screenId string, lineId string, data []byte, pos int64) (*scbus.PtyDataUpdatePacketType, error) {
|
|
if screenId == "" {
|
|
return nil, fmt.Errorf("cannot append to PtyBlob, screenid is not set")
|
|
}
|
|
if pos < 0 {
|
|
return nil, fmt.Errorf("invalid seek pos '%d' in AppendToCmdPtyBlob", pos)
|
|
}
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
f, err := cirfile.OpenCirFile(ptyOutFileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
err = f.WriteAt(ctx, data, pos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data64 := base64.StdEncoding.EncodeToString(data)
|
|
update := scbus.MakePtyDataUpdate(&scbus.PtyDataUpdate{
|
|
ScreenId: screenId,
|
|
LineId: lineId,
|
|
PtyPos: pos,
|
|
PtyData64: data64,
|
|
PtyDataLen: int64(len(data)),
|
|
})
|
|
err = MaybeInsertPtyPosUpdate(ctx, screenId, lineId)
|
|
if err != nil {
|
|
// just log
|
|
log.Printf("error inserting ptypos update %s/%s: %v\n", screenId, lineId, err)
|
|
}
|
|
return update, nil
|
|
}
|
|
|
|
// returns (real-offset, data, err)
|
|
func ReadFullPtyOutFile(ctx context.Context, screenId string, lineId string) (int64, []byte, error) {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
f, err := cirfile.OpenCirFile(ptyOutFileName)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
defer f.Close()
|
|
return f.ReadAll(ctx)
|
|
}
|
|
|
|
// returns (real-offset, data, err)
|
|
func ReadPtyOutFile(ctx context.Context, screenId string, lineId string, offset int64, maxSize int64) (int64, []byte, error) {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
f, err := cirfile.OpenCirFile(ptyOutFileName)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
defer f.Close()
|
|
return f.ReadAtWithMax(ctx, offset, maxSize)
|
|
}
|
|
|
|
type SessionDiskSizeType struct {
|
|
NumFiles int
|
|
TotalSize int64
|
|
ErrorCount int
|
|
Location string
|
|
}
|
|
|
|
func directorySize(dirName string) (SessionDiskSizeType, error) {
|
|
var rtn SessionDiskSizeType
|
|
rtn.Location = dirName
|
|
entries, err := os.ReadDir(dirName)
|
|
if err != nil {
|
|
return rtn, err
|
|
}
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
rtn.ErrorCount++
|
|
continue
|
|
}
|
|
finfo, err := entry.Info()
|
|
if err != nil {
|
|
rtn.ErrorCount++
|
|
continue
|
|
}
|
|
rtn.NumFiles++
|
|
rtn.TotalSize += finfo.Size()
|
|
}
|
|
return rtn, nil
|
|
}
|
|
|
|
func SessionDiskSize(sessionId string) (SessionDiskSizeType, error) {
|
|
sessionDir, err := scbase.EnsureSessionDir(sessionId)
|
|
if err != nil {
|
|
return SessionDiskSizeType{}, err
|
|
}
|
|
return directorySize(sessionDir)
|
|
}
|
|
|
|
func FullSessionDiskSize() (map[string]SessionDiskSizeType, error) {
|
|
sdir := scbase.GetSessionsDir()
|
|
entries, err := os.ReadDir(sdir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rtn := make(map[string]SessionDiskSizeType)
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() {
|
|
continue
|
|
}
|
|
name := entry.Name()
|
|
_, err = uuid.Parse(name)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
diskSize, err := directorySize(path.Join(sdir, name))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
rtn[name] = diskSize
|
|
}
|
|
return rtn, nil
|
|
}
|
|
|
|
func DeletePtyOutFile(ctx context.Context, screenId string, lineId string) error {
|
|
ptyOutFileName, err := scbase.PtyOutFile(screenId, lineId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = os.Remove(ptyOutFileName)
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
func GoDeleteScreenDirs(screenIds ...string) {
|
|
go func() {
|
|
for _, screenId := range screenIds {
|
|
deleteScreenDirMakeCtx(screenId)
|
|
}
|
|
}()
|
|
}
|
|
|
|
func deleteScreenDirMakeCtx(screenId string) {
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), time.Minute)
|
|
defer cancelFn()
|
|
err := DeleteScreenDir(ctx, screenId)
|
|
if err != nil {
|
|
log.Printf("error deleting screendir %s: %v\n", screenId, err)
|
|
}
|
|
}
|
|
|
|
func DeleteScreenDir(ctx context.Context, screenId string) error {
|
|
screenDir, err := scbase.EnsureScreenDir(screenId)
|
|
if err != nil {
|
|
return fmt.Errorf("error getting screendir: %w", err)
|
|
}
|
|
log.Printf("delete screen dir, remove-all %s\n", screenDir)
|
|
return os.RemoveAll(screenDir)
|
|
}
|