2023-10-17 12:31:13 +08:00
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
2022-06-13 11:11:56 -07:00
package sstore
import (
2022-07-01 12:17:19 -07:00
"context"
2022-08-15 18:42:25 -07:00
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
2022-07-05 16:54:49 -07:00
"database/sql/driver"
"fmt"
2022-07-01 14:07:13 -07:00
"log"
2022-08-16 15:08:28 -07:00
"os"
"os/user"
2022-06-30 17:02:19 -07:00
"path"
2022-08-24 02:14:16 -07:00
"strings"
2022-06-20 21:57:23 -07:00
"sync"
2022-06-13 11:11:56 -07:00
"time"
2023-11-01 01:26:19 -07:00
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
"github.com/sawka/txwrap"
2023-10-16 13:30:10 -07:00
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
2024-01-16 16:11:04 -08:00
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
2023-10-16 13:30:10 -07:00
"github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil"
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
2024-02-15 16:45:47 -08:00
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbus"
2024-02-08 19:16:56 -08:00
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
2022-07-01 10:48:14 -07:00
_ "github.com/mattn/go-sqlite3"
2022-06-13 11:11:56 -07:00
)
2024-02-08 19:16:56 -08:00
type RemotePtrType = scpacket . RemotePtrType
2022-10-27 00:33:50 -07:00
const LineNoHeight = - 1
2023-11-01 01:26:19 -07:00
const DBFileName = "waveterm.db"
2023-11-02 14:05:43 -07:00
const DBWALFileName = "waveterm.db-wal"
2023-11-01 01:26:19 -07:00
const DBFileNameBackup = "backup.waveterm.db"
2023-11-02 14:05:43 -07:00
const DBWALFileNameBackup = "backup.waveterm.db-wal"
2023-04-04 23:24:08 -07:00
const MaxWebShareLineCount = 50
2023-04-05 00:25:22 -07:00
const MaxWebShareScreenCount = 3
2023-09-01 15:21:35 -07:00
const MaxLineStateSize = 4 * 1024 // 4k for now, can raise if needed
2024-04-25 18:19:43 -07:00
const DefaultSudoTimeout = 5
2022-06-30 17:02:19 -07:00
2022-07-01 12:17:19 -07:00
const DefaultSessionName = "default"
2022-08-24 02:14:16 -07:00
const LocalRemoteAlias = "local"
2022-07-01 12:17:19 -07:00
2022-07-01 14:07:13 -07:00
const DefaultCwd = "~"
2023-05-08 16:06:51 -07:00
const APITokenSentinel = "--apitoken--"
2022-07-01 14:07:13 -07:00
2024-01-16 16:11:04 -08:00
// defined here and not in packet.go since this value should never
// be passed to waveshell (it should always get resolved prior to sending a run packet)
const ShellTypePref_Detect = "detect"
2023-05-04 01:01:13 -07:00
const (
LineTypeCmd = "cmd"
LineTypeText = "text"
LineTypeOpenAI = "openai"
)
2023-09-17 14:10:35 -07:00
const (
LineState_Source = "prompt:source"
LineState_File = "prompt:file"
2024-03-14 00:49:05 -07:00
LineState_FileUrl = "wave:fileurl"
2024-02-23 03:45:08 +08:00
LineState_Min = "wave:min"
2023-09-17 14:10:35 -07:00
LineState_Template = "template"
LineState_Mode = "mode"
LineState_Lang = "lang"
2024-03-07 12:04:17 -08:00
LineState_Minimap = "minimap"
2023-09-17 14:10:35 -07:00
)
2023-03-02 00:31:19 -08:00
const (
2024-03-13 18:47:16 -07:00
MainViewSession = "session"
MainViewBookmarks = "bookmarks"
MainViewHistory = "history"
MainViewConnections = "connections"
MainViewSettings = "clientsettings"
2023-03-02 00:31:19 -08:00
)
2022-08-15 18:42:25 -07:00
const (
CmdStatusRunning = "running"
CmdStatusDetached = "detached"
CmdStatusError = "error"
CmdStatusDone = "done"
CmdStatusHangup = "hangup"
2023-12-27 13:11:53 -08:00
CmdStatusUnknown = "unknown" // used for history items where we don't have a status
2022-08-15 18:42:25 -07:00
)
2023-05-04 01:01:13 -07:00
const (
CmdRendererOpenAI = "openai"
)
const (
OpenAIRoleSystem = "system"
OpenAIRoleUser = "user"
OpenAIRoleAssistant = "assistant"
)
2023-04-03 01:37:36 -07:00
const (
RemoteAuthTypeNone = "none"
RemoteAuthTypePassword = "password"
RemoteAuthTypeKey = "key"
RemoteAuthTypeKeyPassword = "key+password"
)
2023-12-28 11:09:41 -08:00
const (
SSHConfigSrcTypeManual = "waveterm-manual"
SSHConfigSrcTypeImport = "sshconfig-import"
)
2024-03-25 20:20:52 -07:00
// TODO: move to webshare package once sstore code is more modular
2022-08-15 18:42:25 -07:00
const (
2023-03-24 10:34:07 -07:00
ShareModeLocal = "local"
ShareModeWeb = "web"
2022-08-15 18:42:25 -07:00
)
2022-07-07 16:29:14 -07:00
2022-08-21 12:31:29 -07:00
const (
ConnectModeStartup = "startup"
ConnectModeAuto = "auto"
ConnectModeManual = "manual"
)
const (
2023-05-02 12:43:54 -07:00
RemoteTypeSsh = "ssh"
RemoteTypeOpenAI = "openai"
2022-08-21 12:31:29 -07:00
)
2022-10-11 01:11:04 -07:00
const (
2023-03-13 01:52:30 -07:00
ScreenFocusInput = "input"
ScreenFocusCmd = "cmd"
2022-10-11 01:11:04 -07:00
)
2023-03-20 19:20:57 -07:00
const (
CmdStoreTypeSession = "session"
CmdStoreTypeScreen = "screen"
)
2023-03-24 10:34:07 -07:00
const (
2023-03-30 18:08:35 -07:00
UpdateType_ScreenNew = "screen:new"
UpdateType_ScreenDel = "screen:del"
UpdateType_ScreenSelectedLine = "screen:selectedline"
UpdateType_ScreenName = "screen:sharename"
UpdateType_LineNew = "line:new"
UpdateType_LineDel = "line:del"
UpdateType_LineRenderer = "line:renderer"
2023-03-31 00:32:38 -07:00
UpdateType_LineContentHeight = "line:contentheight"
2023-09-01 15:21:35 -07:00
UpdateType_LineState = "line:state"
2023-03-30 18:08:35 -07:00
UpdateType_CmdStatus = "cmd:status"
UpdateType_CmdTermOpts = "cmd:termopts"
2023-07-30 17:16:43 -07:00
UpdateType_CmdExitCode = "cmd:exitcode"
UpdateType_CmdDurationMs = "cmd:durationms"
2023-03-30 18:08:35 -07:00
UpdateType_CmdRtnState = "cmd:rtnstate"
UpdateType_PtyPos = "pty:pos"
2023-03-24 10:34:07 -07:00
)
2022-07-01 12:17:19 -07:00
var globalDBLock = & sync . Mutex {}
var globalDB * sqlx . DB
var globalDBErr error
2023-07-30 17:16:43 -07:00
func lineIdFromCK ( ck base . CommandKey ) string {
return ck . GetCmdId ()
}
2023-03-12 14:42:18 -07:00
func GetDBName () string {
2023-11-01 01:26:19 -07:00
scHome := scbase . GetWaveHomeDir ()
2022-06-30 17:02:19 -07:00
return path . Join ( scHome , DBFileName )
}
2022-06-13 11:11:56 -07:00
2023-11-02 14:05:43 -07:00
func GetDBWALName () string {
scHome := scbase . GetWaveHomeDir ()
return path . Join ( scHome , DBWALFileName )
}
2023-03-12 14:42:18 -07:00
func GetDBBackupName () string {
2023-11-01 01:26:19 -07:00
scHome := scbase . GetWaveHomeDir ()
2023-03-12 14:42:18 -07:00
return path . Join ( scHome , DBFileNameBackup )
}
2023-11-02 14:05:43 -07:00
func GetDBWALBackupName () string {
scHome := scbase . GetWaveHomeDir ()
return path . Join ( scHome , DBWALFileNameBackup )
}
2022-09-01 12:47:10 -07:00
func IsValidConnectMode ( mode string ) bool {
2022-09-13 17:11:36 -07:00
return mode == ConnectModeStartup || mode == ConnectModeAuto || mode == ConnectModeManual
2022-09-01 12:47:10 -07:00
}
2022-07-12 16:10:46 -07:00
func GetDB ( ctx context . Context ) ( * sqlx . DB , error ) {
2023-02-14 16:17:54 -08:00
if txwrap . IsTxWrapContext ( ctx ) {
2022-07-12 16:10:46 -07:00
return nil , fmt . Errorf ( "cannot call GetDB from within a running transaction" )
}
2022-07-01 12:17:19 -07:00
globalDBLock . Lock ()
defer globalDBLock . Unlock ()
if globalDB == nil && globalDBErr == nil {
2023-03-12 14:42:18 -07:00
dbName := GetDBName ()
2022-08-16 12:08:26 -07:00
globalDB , globalDBErr = sqlx . Open ( "sqlite3" , fmt . Sprintf ( "file:%s?cache=shared&mode=rwc&_journal_mode=WAL&_busy_timeout=5000" , dbName ))
if globalDBErr != nil {
globalDBErr = fmt . Errorf ( "opening db[%s]: %w" , dbName , globalDBErr )
2022-12-28 17:47:12 -08:00
log . Printf ( "[db] error: %v\n" , globalDBErr )
} else {
log . Printf ( "[db] successfully opened db %s\n" , dbName )
2022-08-16 12:08:26 -07:00
}
2022-07-01 10:48:14 -07:00
}
2022-07-01 12:17:19 -07:00
return globalDB , globalDBErr
2022-07-01 10:48:14 -07:00
}
2023-03-12 15:16:49 -07:00
func CloseDB () {
globalDBLock . Lock ()
defer globalDBLock . Unlock ()
if globalDB == nil {
return
}
err := globalDB . Close ()
if err != nil {
log . Printf ( "[db] error closing database: %v\n" , err )
}
globalDB = nil
}
2023-03-26 13:21:58 -07:00
type CmdPtr struct {
ScreenId string
2023-07-30 17:16:43 -07:00
LineId string
2023-03-26 13:21:58 -07:00
}
2022-09-25 00:26:33 -07:00
type ClientWinSizeType struct {
Width int `json:"width"`
Height int `json:"height"`
Top int `json:"top"`
Left int `json:"left"`
FullScreen bool `json:"fullscreen,omitempty"`
}
2024-04-25 18:19:43 -07:00
type PowerMonitorEventType struct {
Status string `json:"status"`
}
2024-01-31 12:17:49 +08:00
type SidebarValueType struct {
Collapsed bool `json:"collapsed"`
Width int `json:"width"`
}
2023-01-22 23:10:18 -08:00
type ClientOptsType struct {
2024-02-13 20:43:02 -05:00
NoTelemetry bool `json:"notelemetry,omitempty"`
NoReleaseCheck bool `json:"noreleasecheck,omitempty"`
AcceptedTos int64 `json:"acceptedtos,omitempty"`
ConfirmFlags map [ string ] bool `json:"confirmflags,omitempty"`
MainSidebar * SidebarValueType `json:"mainsidebar,omitempty"`
2024-03-15 13:59:55 +08:00
RightSidebar * SidebarValueType `json:"rightsidebar,omitempty"`
2024-02-13 20:43:02 -05:00
GlobalShortcut string `json:"globalshortcut,omitempty"`
GlobalShortcutEnabled bool `json:"globalshortcutenabled,omitempty"`
2024-03-28 23:19:39 -07:00
WebGL bool `json:"webgl,omitempty"`
2024-05-28 17:17:29 -07:00
AutocompleteEnabled bool `json:"autocompleteenabled,omitempty"`
2023-01-22 23:10:18 -08:00
}
2023-02-26 14:33:01 -08:00
type FeOptsType struct {
2024-04-25 18:19:43 -07:00
TermFontSize int `json:"termfontsize,omitempty"`
TermFontFamily string `json:"termfontfamily,omitempty"`
Theme string `json:"theme,omitempty"`
TermThemeSettings map [ string ] string `json:"termthemesettings"`
SudoPwStore string `json:"sudopwstore,omitempty"`
SudoPwTimeoutMs int `json:"sudopwtimeoutms,omitempty"`
SudoPwTimeout int `json:"sudopwtimeout,omitempty"`
NoSudoPwClearOnSleep bool `json:"nosudopwclearonsleep,omitempty"`
2023-02-26 14:33:01 -08:00
}
2023-12-15 17:43:54 -08:00
type ReleaseInfoType struct {
LatestVersion string `json:"latestversion,omitempty"`
}
2022-08-26 16:21:19 -07:00
type ClientData struct {
2023-07-28 11:48:11 -07:00
ClientId string `json:"clientid"`
UserId string `json:"userid"`
UserPrivateKeyBytes [] byte `json:"-"`
UserPublicKeyBytes [] byte `json:"-"`
UserPrivateKey * ecdsa . PrivateKey `json:"-" dbmap:"-"`
UserPublicKey * ecdsa . PublicKey `json:"-" dbmap:"-"`
ActiveSessionId string `json:"activesessionid"`
WinSize ClientWinSizeType `json:"winsize"`
ClientOpts ClientOptsType `json:"clientopts"`
FeOpts FeOptsType `json:"feopts"`
CmdStoreType string `json:"cmdstoretype"`
DBVersion int `json:"dbversion" dbmap:"-"`
OpenAIOpts * OpenAIOptsType `json:"openaiopts,omitempty" dbmap:"openaiopts"`
2023-12-15 17:43:54 -08:00
ReleaseInfo ReleaseInfoType `json:"releaseinfo"`
2022-08-15 18:42:25 -07:00
}
2023-03-13 10:50:29 -07:00
func ( ClientData ) UseDBMap () {}
2022-09-21 22:02:38 -07:00
2023-05-08 16:06:51 -07:00
func ( cdata * ClientData ) Clean () * ClientData {
if cdata == nil {
return nil
}
rtn := * cdata
if rtn . OpenAIOpts != nil {
rtn . OpenAIOpts = & OpenAIOptsType {
Model : cdata . OpenAIOpts . Model ,
MaxTokens : cdata . OpenAIOpts . MaxTokens ,
MaxChoices : cdata . OpenAIOpts . MaxChoices ,
2024-04-25 16:14:37 -07:00
Timeout : cdata . OpenAIOpts . Timeout ,
BaseURL : cdata . OpenAIOpts . BaseURL ,
2023-05-08 16:06:51 -07:00
// omit API Token
}
if cdata . OpenAIOpts . APIToken != "" {
rtn . OpenAIOpts . APIToken = APITokenSentinel
}
}
return & rtn
}
2024-02-15 16:45:47 -08:00
func ( ClientData ) GetType () string {
2024-02-09 17:19:44 -08:00
return "clientdata"
}
2022-06-20 21:57:23 -07:00
type SessionType struct {
2022-07-12 21:51:17 -07:00
SessionId string `json:"sessionid"`
Name string `json:"name"`
SessionIdx int64 `json:"sessionidx"`
ActiveScreenId string `json:"activescreenid"`
2022-08-16 12:08:26 -07:00
ShareMode string `json:"sharemode"`
2022-07-12 21:51:17 -07:00
NotifyNum int64 `json:"notifynum"`
2022-12-25 13:03:11 -08:00
Archived bool `json:"archived,omitempty"`
2022-12-25 13:21:48 -08:00
ArchivedTs int64 `json:"archivedts,omitempty"`
2022-07-12 21:51:17 -07:00
Remotes [] * RemoteInstance `json:"remotes"`
2022-07-14 18:39:40 -07:00
// only for updates
Remove bool `json:"remove,omitempty"`
2024-02-09 17:19:44 -08:00
}
2024-02-15 16:45:47 -08:00
func ( SessionType ) GetType () string {
2024-02-09 17:19:44 -08:00
return "session"
}
func MakeSessionUpdateForRemote ( sessionId string , ri * RemoteInstance ) SessionType {
return SessionType {
SessionId : sessionId ,
Remotes : [] * RemoteInstance { ri },
}
2022-07-12 14:27:16 -07:00
}
2023-12-27 13:11:53 -08:00
type SessionTombstoneType struct {
SessionId string `json:"sessionid"`
Name string `json:"name"`
DeletedTs int64 `json:"deletedts"`
}
func ( SessionTombstoneType ) UseDBMap () {}
2024-02-15 16:45:47 -08:00
func ( SessionTombstoneType ) GetType () string {
2024-02-09 17:19:44 -08:00
return "sessiontombstone"
}
2022-09-20 14:15:20 -07:00
type SessionStatsType struct {
2022-12-25 13:03:11 -08:00
SessionId string `json:"sessionid"`
NumScreens int `json:"numscreens"`
NumArchivedScreens int `json:"numarchivedscreens"`
NumLines int `json:"numlines"`
NumCmds int `json:"numcmds"`
DiskStats SessionDiskSizeType `json:"diskstats"`
2022-09-20 14:15:20 -07:00
}
2022-07-12 21:51:17 -07:00
type ScreenOptsType struct {
2022-08-26 21:44:18 -07:00
TabColor string `json:"tabcolor,omitempty"`
2023-12-13 14:03:22 -08:00
TabIcon string `json:"tabicon,omitempty"`
2023-03-13 01:52:30 -07:00
PTerm string `json:"pterm,omitempty"`
2022-07-12 21:51:17 -07:00
}
2023-03-13 10:50:29 -07:00
type ScreenLinesType struct {
2023-03-15 18:12:55 -07:00
ScreenId string `json:"screenid"`
Lines [] * LineType `json:"lines" dbmap:"-"`
Cmds [] * CmdType `json:"cmds" dbmap:"-"`
2023-03-13 10:50:29 -07:00
}
func ( ScreenLinesType ) UseDBMap () {}
2024-02-15 16:45:47 -08:00
func ( ScreenLinesType ) GetType () string {
2024-02-09 17:19:44 -08:00
return "screenlines"
}
2023-03-24 10:34:07 -07:00
type ScreenWebShareOpts struct {
2023-04-04 22:28:52 -07:00
ShareName string `json:"sharename"`
ViewKey string `json:"viewkey"`
2023-03-24 10:34:07 -07:00
}
2023-07-26 10:10:27 -07:00
type ScreenCreateOpts struct {
BaseScreenId string
CopyRemote bool
CopyCwd bool
CopyEnv bool
2024-03-27 00:22:57 -07:00
RtnScreenId * string
2023-07-26 10:10:27 -07:00
}
func ( sco ScreenCreateOpts ) HasCopy () bool {
return sco . CopyRemote || sco . CopyCwd || sco . CopyEnv
}
2023-12-17 23:46:53 -08:00
type ScreenSidebarOptsType struct {
Open bool `json:"open,omitempty"`
Width string `json:"width,omitempty"`
// this used to be more complicated (sections with types). simplified for this release
SidebarLineId string `json:"sidebarlineid,omitempty"`
}
type ScreenViewOptsType struct {
Sidebar * ScreenSidebarOptsType `json:"sidebar,omitempty"`
}
2022-07-12 14:27:16 -07:00
type ScreenType struct {
2023-12-17 23:46:53 -08:00
SessionId string `json:"sessionid"`
ScreenId string `json:"screenid"`
Name string `json:"name"`
ScreenIdx int64 `json:"screenidx"`
ScreenOpts ScreenOptsType `json:"screenopts"`
ScreenViewOpts ScreenViewOptsType `json:"screenviewopts"`
OwnerId string `json:"ownerid"`
ShareMode string `json:"sharemode"`
WebShareOpts * ScreenWebShareOpts `json:"webshareopts,omitempty"`
CurRemote RemotePtrType `json:"curremote"`
NextLineNum int64 `json:"nextlinenum"`
SelectedLine int64 `json:"selectedline"`
Anchor ScreenAnchorType `json:"anchor"`
FocusType string `json:"focustype"`
Archived bool `json:"archived,omitempty"`
ArchivedTs int64 `json:"archivedts,omitempty"`
2023-03-13 01:52:30 -07:00
2022-07-14 18:39:40 -07:00
// only for updates
2024-02-09 17:19:44 -08:00
Remove bool `json:"remove,omitempty"`
2022-07-12 14:27:16 -07:00
}
2023-03-13 01:52:30 -07:00
func ( s * ScreenType ) ToMap () map [ string ] interface {} {
rtn := make ( map [ string ] interface {})
rtn [ "sessionid" ] = s . SessionId
rtn [ "screenid" ] = s . ScreenId
rtn [ "name" ] = s . Name
rtn [ "screenidx" ] = s . ScreenIdx
rtn [ "screenopts" ] = quickJson ( s . ScreenOpts )
2023-12-17 23:46:53 -08:00
rtn [ "screenviewopts" ] = quickJson ( s . ScreenViewOpts )
2023-03-13 01:52:30 -07:00
rtn [ "ownerid" ] = s . OwnerId
rtn [ "sharemode" ] = s . ShareMode
2023-03-24 10:34:07 -07:00
rtn [ "webshareopts" ] = quickNullableJson ( s . WebShareOpts )
2023-03-13 01:52:30 -07:00
rtn [ "curremoteownerid" ] = s . CurRemote . OwnerId
rtn [ "curremoteid" ] = s . CurRemote . RemoteId
rtn [ "curremotename" ] = s . CurRemote . Name
rtn [ "nextlinenum" ] = s . NextLineNum
rtn [ "selectedline" ] = s . SelectedLine
rtn [ "anchor" ] = quickJson ( s . Anchor )
rtn [ "focustype" ] = s . FocusType
rtn [ "archived" ] = s . Archived
rtn [ "archivedts" ] = s . ArchivedTs
return rtn
}
func ( s * ScreenType ) FromMap ( m map [ string ] interface {}) bool {
quickSetStr ( & s . SessionId , m , "sessionid" )
quickSetStr ( & s . ScreenId , m , "screenid" )
quickSetStr ( & s . Name , m , "name" )
quickSetInt64 ( & s . ScreenIdx , m , "screenidx" )
quickSetJson ( & s . ScreenOpts , m , "screenopts" )
2023-12-17 23:46:53 -08:00
quickSetJson ( & s . ScreenViewOpts , m , "screenviewopts" )
2023-03-13 01:52:30 -07:00
quickSetStr ( & s . OwnerId , m , "ownerid" )
quickSetStr ( & s . ShareMode , m , "sharemode" )
2023-03-24 10:34:07 -07:00
quickSetNullableJson ( & s . WebShareOpts , m , "webshareopts" )
2023-03-13 01:52:30 -07:00
quickSetStr ( & s . CurRemote . OwnerId , m , "curremoteownerid" )
quickSetStr ( & s . CurRemote . RemoteId , m , "curremoteid" )
quickSetStr ( & s . CurRemote . Name , m , "curremotename" )
quickSetInt64 ( & s . NextLineNum , m , "nextlinenum" )
quickSetInt64 ( & s . SelectedLine , m , "selectedline" )
quickSetJson ( & s . Anchor , m , "anchor" )
quickSetStr ( & s . FocusType , m , "focustype" )
quickSetBool ( & s . Archived , m , "archived" )
quickSetInt64 ( & s . ArchivedTs , m , "archivedts" )
return true
}
2024-02-15 16:45:47 -08:00
func ( ScreenType ) GetType () string {
2024-02-09 17:19:44 -08:00
return "screen"
}
2024-02-15 16:45:47 -08:00
func AddScreenUpdate ( update * scbus . ModelUpdatePacketType , newScreen * ScreenType ) {
2024-02-09 17:19:44 -08:00
if newScreen == nil {
return
}
2024-02-15 16:45:47 -08:00
screenUpdates := scbus . GetUpdateItems [ ScreenType ]( update )
2024-02-09 17:19:44 -08:00
for _ , screenUpdate := range screenUpdates {
if screenUpdate . ScreenId == newScreen . ScreenId {
screenUpdate = newScreen
return
}
}
2024-02-15 16:45:47 -08:00
update . AddUpdate ( newScreen )
2024-02-09 17:19:44 -08:00
}
2023-12-27 13:11:53 -08:00
type ScreenTombstoneType struct {
ScreenId string `json:"screenid"`
SessionId string `json:"sessionid"`
Name string `json:"name"`
DeletedTs int64 `json:"deletedts"`
ScreenOpts ScreenOptsType `json:"screenopts"`
}
func ( ScreenTombstoneType ) UseDBMap () {}
2024-02-15 16:45:47 -08:00
func ( ScreenTombstoneType ) GetType () string {
2024-02-09 17:19:44 -08:00
return "screentombstone"
}
2022-07-12 21:51:17 -07:00
const (
LayoutFull = "full"
)
2022-07-12 14:27:16 -07:00
type LayoutType struct {
2022-07-12 21:51:17 -07:00
Type string `json:"type"`
Parent string `json:"parent,omitempty"`
ZIndex int64 `json:"zindex,omitempty"`
Float bool `json:"float,omitempty"`
Top string `json:"top,omitempty"`
Bottom string `json:"bottom,omitempty"`
Left string `json:"left,omitempty"`
Right string `json:"right,omitempty"`
Width string `json:"width,omitempty"`
Height string `json:"height,omitempty"`
2022-07-12 14:27:16 -07:00
}
func ( l * LayoutType ) Scan ( val interface {}) error {
return quickScanJson ( l , val )
}
2022-07-12 16:10:46 -07:00
func ( l LayoutType ) Value () ( driver . Value , error ) {
2022-07-12 14:27:16 -07:00
return quickValueJson ( l )
}
2023-03-13 01:52:30 -07:00
type ScreenAnchorType struct {
2022-10-11 01:11:04 -07:00
AnchorLine int `json:"anchorline,omitempty"`
AnchorOffset int `json:"anchoroffset,omitempty"`
}
2022-07-07 00:10:37 -07:00
type TermOpts struct {
2022-08-19 13:23:00 -07:00
Rows int64 `json:"rows"`
Cols int64 `json:"cols"`
FlexRows bool `json:"flexrows,omitempty"`
MaxPtySize int64 `json:"maxptysize,omitempty"`
2022-07-07 00:10:37 -07:00
}
func ( opts * TermOpts ) Scan ( val interface {}) error {
2022-07-12 14:27:16 -07:00
return quickScanJson ( opts , val )
2022-07-07 00:10:37 -07:00
}
2022-07-12 16:10:46 -07:00
func ( opts TermOpts ) Value () ( driver . Value , error ) {
2022-07-12 14:27:16 -07:00
return quickValueJson ( opts )
2022-07-07 00:10:37 -07:00
}
2022-07-05 16:54:49 -07:00
type RemoteInstance struct {
2023-04-11 23:54:18 -07:00
RIId string `json:"riid"`
Name string `json:"name"`
SessionId string `json:"sessionid"`
ScreenId string `json:"screenid"`
RemoteOwnerId string `json:"remoteownerid"`
RemoteId string `json:"remoteid"`
FeState map [ string ] string `json:"festate"`
2024-01-16 16:11:04 -08:00
ShellType string `json:"shelltype"`
2023-04-11 23:54:18 -07:00
StateBaseHash string `json:"-"`
StateDiffHashArr [] string `json:"-"`
2022-08-10 18:33:32 -07:00
// only for updates
Remove bool `json:"remove,omitempty"`
2022-06-20 21:57:23 -07:00
}
2022-11-28 00:13:00 -08:00
type StateBase struct {
BaseHash string
Version string
Ts int64
Data [] byte
}
type StateDiff struct {
DiffHash string
Ts int64
BaseHash string
DiffHashArr [] string
Data [] byte
}
2023-03-09 18:44:01 -08:00
func ( sd * StateDiff ) FromMap ( m map [ string ] interface {}) bool {
2022-11-28 00:13:00 -08:00
quickSetStr ( & sd . DiffHash , m , "diffhash" )
quickSetInt64 ( & sd . Ts , m , "ts" )
quickSetStr ( & sd . BaseHash , m , "basehash" )
quickSetJsonArr ( & sd . DiffHashArr , m , "diffhasharr" )
quickSetBytes ( & sd . Data , m , "data" )
2023-03-09 18:44:01 -08:00
return true
2022-11-28 00:13:00 -08:00
}
func ( sd * StateDiff ) ToMap () map [ string ] interface {} {
2022-10-16 23:51:04 -07:00
rtn := make ( map [ string ] interface {})
2022-11-28 00:13:00 -08:00
rtn [ "diffhash" ] = sd . DiffHash
rtn [ "ts" ] = sd . Ts
rtn [ "basehash" ] = sd . BaseHash
rtn [ "diffhasharr" ] = quickJsonArr ( sd . DiffHashArr )
rtn [ "data" ] = sd . Data
2022-10-16 23:51:04 -07:00
return rtn
}
2023-04-11 23:54:18 -07:00
func FeStateFromShellState ( state * packet . ShellState ) map [ string ] string {
2022-11-28 00:13:00 -08:00
if state == nil {
return nil
}
2023-04-11 23:54:18 -07:00
rtn := make ( map [ string ] string )
rtn [ "cwd" ] = state . Cwd
2024-03-18 22:51:16 -07:00
declMap := shellenv . DeclMapFromState ( state )
if decl , ok := declMap [ "VIRTUAL_ENV" ]; ok {
rtn [ "VIRTUAL_ENV" ] = decl . UnescapedValue ()
2023-04-11 23:54:18 -07:00
}
2024-03-18 22:51:16 -07:00
if decl , ok := declMap [ "CONDA_DEFAULT_ENV" ]; ok {
rtn [ "CONDA_DEFAULT_ENV" ] = decl . UnescapedValue ()
2024-02-28 10:00:06 -08:00
}
2024-03-18 22:51:16 -07:00
for _ , decl := range declMap {
// works for both legacy and new IsExtVar decls
if strings . HasPrefix ( decl . Name , "PROMPTVAR_" ) {
rtn [ decl . Name ] = decl . UnescapedValue ()
2023-04-11 23:54:18 -07:00
}
}
2024-01-16 16:11:04 -08:00
_ , _ , err := packet . ParseShellStateVersion ( state . Version )
if err != nil {
rtn [ "invalidstate" ] = "1"
}
2023-04-11 23:54:18 -07:00
return rtn
2022-11-28 00:13:00 -08:00
}
2023-03-09 18:44:01 -08:00
func ( ri * RemoteInstance ) FromMap ( m map [ string ] interface {}) bool {
2022-10-16 23:51:04 -07:00
quickSetStr ( & ri . RIId , m , "riid" )
quickSetStr ( & ri . Name , m , "name" )
quickSetStr ( & ri . SessionId , m , "sessionid" )
2023-03-14 16:37:22 -07:00
quickSetStr ( & ri . ScreenId , m , "screenid" )
2022-10-16 23:51:04 -07:00
quickSetStr ( & ri . RemoteOwnerId , m , "remoteownerid" )
quickSetStr ( & ri . RemoteId , m , "remoteid" )
2022-11-28 00:13:00 -08:00
quickSetJson ( & ri . FeState , m , "festate" )
quickSetStr ( & ri . StateBaseHash , m , "statebasehash" )
quickSetJsonArr ( & ri . StateDiffHashArr , m , "statediffhasharr" )
2024-01-16 16:11:04 -08:00
quickSetStr ( & ri . ShellType , m , "shelltype" )
2023-03-09 18:44:01 -08:00
return true
2022-10-16 23:51:04 -07:00
}
2022-11-28 00:13:00 -08:00
func ( ri * RemoteInstance ) ToMap () map [ string ] interface {} {
rtn := make ( map [ string ] interface {})
rtn [ "riid" ] = ri . RIId
rtn [ "name" ] = ri . Name
rtn [ "sessionid" ] = ri . SessionId
2023-03-14 16:37:22 -07:00
rtn [ "screenid" ] = ri . ScreenId
2022-11-28 00:13:00 -08:00
rtn [ "remoteownerid" ] = ri . RemoteOwnerId
rtn [ "remoteid" ] = ri . RemoteId
rtn [ "festate" ] = quickJson ( ri . FeState )
rtn [ "statebasehash" ] = ri . StateBaseHash
rtn [ "statediffhasharr" ] = quickJsonArr ( ri . StateDiffHashArr )
2024-01-16 16:11:04 -08:00
rtn [ "shelltype" ] = ri . ShellType
2022-11-28 00:13:00 -08:00
return rtn
}
2023-03-24 10:34:07 -07:00
type ScreenUpdateType struct {
UpdateId int64 `json:"updateid"`
ScreenId string `json:"screenid"`
LineId string `json:"lineid"`
UpdateType string `json:"updatetype"`
UpdateTs int64 `json:"updatets"`
}
func ( ScreenUpdateType ) UseDBMap () {}
2022-06-13 11:11:56 -07:00
type LineType struct {
2023-09-01 15:21:35 -07:00
ScreenId string `json:"screenid"`
UserId string `json:"userid"`
LineId string `json:"lineid"`
Ts int64 `json:"ts"`
LineNum int64 `json:"linenum"`
LineNumTemp bool `json:"linenumtemp,omitempty"`
LineLocal bool `json:"linelocal"`
LineType string `json:"linetype"`
LineState map [ string ] any `json:"linestate"`
Renderer string `json:"renderer,omitempty"`
Text string `json:"text,omitempty"`
Ephemeral bool `json:"ephemeral,omitempty"`
ContentHeight int64 `json:"contentheight,omitempty"`
Star bool `json:"star,omitempty"`
Archived bool `json:"archived,omitempty"`
Remove bool `json:"remove,omitempty"`
2022-07-01 10:48:14 -07:00
}
2023-09-01 15:21:35 -07:00
func ( LineType ) UseDBMap () {}
2023-05-04 01:01:13 -07:00
type OpenAIUsage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
}
type OpenAIChoiceType struct {
Text string `json:"text"`
Index int `json:"index"`
FinishReason string `json:"finish_reason"`
}
type OpenAIResponse struct {
Model string `json:"model"`
Created int64 `json:"created"`
Usage * OpenAIUsage `json:"usage,omitempty"`
Choices [] OpenAIChoiceType `json:"choices,omitempty"`
}
2022-10-06 23:58:38 -07:00
type ResolveItem struct {
2022-12-23 15:56:29 -08:00
Name string
Num int
Id string
Hidden bool
2022-10-06 23:58:38 -07:00
}
2022-07-07 13:26:46 -07:00
type SSHOpts struct {
2022-09-30 16:23:40 -07:00
Local bool `json:"local,omitempty"`
2023-05-02 12:43:54 -07:00
IsSudo bool `json:"issudo,omitempty"`
2022-07-01 17:38:36 -07:00
SSHHost string `json:"sshhost"`
SSHUser string `json:"sshuser"`
2022-09-30 16:23:40 -07:00
SSHOptsStr string `json:"sshopts,omitempty"`
SSHIdentity string `json:"sshidentity,omitempty"`
SSHPort int `json:"sshport,omitempty"`
2022-09-30 17:22:28 -07:00
SSHPassword string `json:"sshpassword,omitempty"`
2022-07-07 13:26:46 -07:00
}
2022-07-01 17:38:36 -07:00
2023-04-03 01:37:36 -07:00
func ( opts SSHOpts ) GetAuthType () string {
if opts . SSHPassword != "" && opts . SSHIdentity != "" {
return RemoteAuthTypeKeyPassword
}
if opts . SSHIdentity != "" {
return RemoteAuthTypeKey
}
if opts . SSHPassword != "" {
return RemoteAuthTypePassword
}
return RemoteAuthTypeNone
}
2022-08-19 13:23:00 -07:00
type RemoteOptsType struct {
2022-08-24 02:14:16 -07:00
Color string `json:"color"`
2022-08-19 13:23:00 -07:00
}
2023-05-02 12:43:54 -07:00
type OpenAIOptsType struct {
2023-05-04 01:01:13 -07:00
Model string `json:"model"`
APIToken string `json:"apitoken"`
2023-12-13 14:03:22 -08:00
BaseURL string `json:"baseurl,omitempty"`
2023-05-04 01:01:13 -07:00
MaxTokens int `json:"maxtokens,omitempty"`
MaxChoices int `json:"maxchoices,omitempty"`
2024-04-25 16:14:37 -07:00
Timeout int `json:"timeout,omitempty"`
2022-08-19 13:23:00 -07:00
}
2023-12-28 11:09:41 -08:00
const (
RemoteStatus_Connected = "connected"
RemoteStatus_Connecting = "connecting"
RemoteStatus_Disconnected = "disconnected"
RemoteStatus_Error = "error"
)
type RemoteRuntimeState struct {
2024-05-02 14:16:00 -07:00
RemoteType string `json:"remotetype"`
RemoteId string `json:"remoteid"`
RemoteAlias string `json:"remotealias,omitempty"`
RemoteCanonicalName string `json:"remotecanonicalname"`
RemoteVars map [ string ] string `json:"remotevars"`
Status string `json:"status"`
ConnectTimeout int `json:"connecttimeout,omitempty"`
CountdownActive bool `json:"countdownactive"`
ErrorStr string `json:"errorstr,omitempty"`
InstallStatus string `json:"installstatus"`
InstallErrorStr string `json:"installerrorstr,omitempty"`
NeedsWaveshellUpgrade bool `json:"needswaveshellupgrade,omitempty"`
NoInitPk bool `json:"noinitpk,omitempty"`
AuthType string `json:"authtype,omitempty"`
ConnectMode string `json:"connectmode"`
AutoInstall bool `json:"autoinstall"`
Archived bool `json:"archived,omitempty"`
RemoteIdx int64 `json:"remoteidx"`
SSHConfigSrc string `json:"sshconfigsrc"`
UName string `json:"uname"`
WaveshellVersion string `json:"waveshellversion"`
WaitingForPassword bool `json:"waitingforpassword,omitempty"`
Local bool `json:"local,omitempty"`
IsSudo bool `json:"issudo,omitempty"`
RemoteOpts * RemoteOptsType `json:"remoteopts,omitempty"`
CanComplete bool `json:"cancomplete,omitempty"`
ShellPref string `json:"shellpref,omitempty"`
DefaultShellType string `json:"defaultshelltype,omitempty"`
2023-12-28 11:09:41 -08:00
}
func ( state RemoteRuntimeState ) IsConnected () bool {
return state . Status == RemoteStatus_Connected
}
func ( state RemoteRuntimeState ) GetBaseDisplayName () string {
if state . RemoteAlias != "" {
return state . RemoteAlias
}
return state . RemoteCanonicalName
}
func ( state RemoteRuntimeState ) GetDisplayName ( rptr * RemotePtrType ) string {
baseDisplayName := state . GetBaseDisplayName ()
if rptr == nil {
return baseDisplayName
}
return rptr . GetDisplayName ( baseDisplayName )
}
func ( state RemoteRuntimeState ) ExpandHomeDir ( pathStr string ) ( string , error ) {
if pathStr != "~" && ! strings . HasPrefix ( pathStr , "~/" ) {
return pathStr , nil
}
homeDir := state . RemoteVars [ "home" ]
if homeDir == "" {
return "" , fmt . Errorf ( "remote does not have HOME set, cannot do ~ expansion" )
}
if pathStr == "~" {
return homeDir , nil
}
return path . Join ( homeDir , pathStr [ 2 :]), nil
}
2024-02-15 16:45:47 -08:00
func ( RemoteRuntimeState ) GetType () string {
2024-02-09 17:19:44 -08:00
return "remote"
}
2022-07-07 13:26:46 -07:00
type RemoteType struct {
2023-05-02 12:43:54 -07:00
RemoteId string `json:"remoteid"`
RemoteType string `json:"remotetype"`
RemoteAlias string `json:"remotealias"`
RemoteCanonicalName string `json:"remotecanonicalname"`
RemoteOpts * RemoteOptsType `json:"remoteopts"`
LastConnectTs int64 `json:"lastconnectts"`
RemoteIdx int64 `json:"remoteidx"`
Archived bool `json:"archived"`
// SSH fields
2023-12-28 11:09:41 -08:00
Local bool `json:"local"`
RemoteUser string `json:"remoteuser"`
RemoteHost string `json:"remotehost"`
ConnectMode string `json:"connectmode"`
AutoInstall bool `json:"autoinstall"`
SSHOpts * SSHOpts `json:"sshopts"`
StateVars map [ string ] string `json:"statevars"`
SSHConfigSrc string `json:"sshconfigsrc"`
2024-01-16 16:11:04 -08:00
ShellPref string `json:"shellpref"` // bash, zsh, or detect
2023-05-02 12:43:54 -07:00
2024-01-16 16:11:04 -08:00
// OpenAI fields (unused)
2023-05-02 12:43:54 -07:00
OpenAIOpts * OpenAIOptsType `json:"openaiopts,omitempty"`
}
2024-02-08 12:37:23 -08:00
func ( r * RemoteType ) IsLocal () bool {
return r . Local && ! r . IsSudo ()
}
2023-05-02 12:43:54 -07:00
func ( r * RemoteType ) IsSudo () bool {
return r . SSHOpts != nil && r . SSHOpts . IsSudo
2022-07-07 13:26:46 -07:00
}
2022-08-16 15:08:28 -07:00
func ( r * RemoteType ) GetName () string {
if r . RemoteAlias != "" {
return r . RemoteAlias
2022-07-07 13:26:46 -07:00
}
2022-09-13 17:11:36 -07:00
return r . RemoteCanonicalName
2022-07-01 10:48:14 -07:00
}
2022-07-07 13:26:46 -07:00
func ( r * RemoteType ) ToMap () map [ string ] interface {} {
rtn := make ( map [ string ] interface {})
rtn [ "remoteid" ] = r . RemoteId
rtn [ "remotetype" ] = r . RemoteType
2022-08-16 15:08:28 -07:00
rtn [ "remotealias" ] = r . RemoteAlias
rtn [ "remotecanonicalname" ] = r . RemoteCanonicalName
rtn [ "remoteuser" ] = r . RemoteUser
rtn [ "remotehost" ] = r . RemoteHost
2022-08-21 12:31:29 -07:00
rtn [ "connectmode" ] = r . ConnectMode
2022-09-24 19:54:06 -07:00
rtn [ "autoinstall" ] = r . AutoInstall
2022-07-07 13:26:46 -07:00
rtn [ "sshopts" ] = quickJson ( r . SSHOpts )
2022-08-19 13:23:00 -07:00
rtn [ "remoteopts" ] = quickJson ( r . RemoteOpts )
2022-07-07 13:26:46 -07:00
rtn [ "lastconnectts" ] = r . LastConnectTs
2022-09-13 17:11:36 -07:00
rtn [ "archived" ] = r . Archived
2022-09-14 12:06:55 -07:00
rtn [ "remoteidx" ] = r . RemoteIdx
2022-10-04 11:45:24 -07:00
rtn [ "local" ] = r . Local
2023-03-29 12:42:04 -07:00
rtn [ "statevars" ] = quickJson ( r . StateVars )
2023-12-28 11:09:41 -08:00
rtn [ "sshconfigsrc" ] = r . SSHConfigSrc
2023-05-02 12:43:54 -07:00
rtn [ "openaiopts" ] = quickJson ( r . OpenAIOpts )
2024-01-16 16:11:04 -08:00
rtn [ "shellpref" ] = r . ShellPref
2022-07-07 13:26:46 -07:00
return rtn
}
2023-03-09 18:44:01 -08:00
func ( r * RemoteType ) FromMap ( m map [ string ] interface {}) bool {
2022-07-07 13:26:46 -07:00
quickSetStr ( & r . RemoteId , m , "remoteid" )
quickSetStr ( & r . RemoteType , m , "remotetype" )
2022-08-16 15:08:28 -07:00
quickSetStr ( & r . RemoteAlias , m , "remotealias" )
quickSetStr ( & r . RemoteCanonicalName , m , "remotecanonicalname" )
quickSetStr ( & r . RemoteUser , m , "remoteuser" )
quickSetStr ( & r . RemoteHost , m , "remotehost" )
2022-08-21 12:31:29 -07:00
quickSetStr ( & r . ConnectMode , m , "connectmode" )
2022-09-24 19:54:06 -07:00
quickSetBool ( & r . AutoInstall , m , "autoinstall" )
2022-07-07 13:26:46 -07:00
quickSetJson ( & r . SSHOpts , m , "sshopts" )
2022-08-19 13:23:00 -07:00
quickSetJson ( & r . RemoteOpts , m , "remoteopts" )
2022-07-07 13:26:46 -07:00
quickSetInt64 ( & r . LastConnectTs , m , "lastconnectts" )
2022-09-13 17:11:36 -07:00
quickSetBool ( & r . Archived , m , "archived" )
2022-09-14 12:06:55 -07:00
quickSetInt64 ( & r . RemoteIdx , m , "remoteidx" )
2022-10-04 11:45:24 -07:00
quickSetBool ( & r . Local , m , "local" )
2023-03-29 12:42:04 -07:00
quickSetJson ( & r . StateVars , m , "statevars" )
2023-12-28 11:09:41 -08:00
quickSetStr ( & r . SSHConfigSrc , m , "sshconfigsrc" )
2023-05-02 12:43:54 -07:00
quickSetJson ( & r . OpenAIOpts , m , "openaiopts" )
2024-01-16 16:11:04 -08:00
quickSetStr ( & r . ShellPref , m , "shellpref" )
2023-03-09 18:44:01 -08:00
return true
2022-07-07 00:10:37 -07:00
}
2024-04-02 15:46:32 -07:00
type CmdType struct {
ScreenId string `json:"screenid"`
LineId string `json:"lineid"`
Remote RemotePtrType `json:"remote"`
CmdStr string `json:"cmdstr"`
RawCmdStr string `json:"rawcmdstr"`
FeState map [ string ] string `json:"festate"`
StatePtr packet . ShellStatePtr `json:"state"`
TermOpts TermOpts `json:"termopts"`
OrigTermOpts TermOpts `json:"origtermopts"`
Status string `json:"status"`
CmdPid int `json:"cmdpid"`
RemotePid int `json:"remotepid"`
RestartTs int64 `json:"restartts,omitempty"`
DoneTs int64 `json:"donets"`
ExitCode int `json:"exitcode"`
DurationMs int `json:"durationms"`
RunOut [] packet . PacketType `json:"runout,omitempty"`
RtnState bool `json:"rtnstate,omitempty"`
RtnStatePtr packet . ShellStatePtr `json:"rtnstateptr,omitempty"`
Remove bool `json:"remove,omitempty"` // not persisted to DB
Restarted bool `json:"restarted,omitempty"` // not persisted to DB
}
func ( CmdType ) GetType () string {
return "cmd"
}
2022-07-07 00:10:37 -07:00
func ( cmd * CmdType ) ToMap () map [ string ] interface {} {
rtn := make ( map [ string ] interface {})
2023-03-15 18:12:55 -07:00
rtn [ "screenid" ] = cmd . ScreenId
2023-07-30 17:16:43 -07:00
rtn [ "lineid" ] = cmd . LineId
2022-08-24 13:21:54 -07:00
rtn [ "remoteownerid" ] = cmd . Remote . OwnerId
rtn [ "remoteid" ] = cmd . Remote . RemoteId
rtn [ "remotename" ] = cmd . Remote . Name
2022-07-07 00:10:37 -07:00
rtn [ "cmdstr" ] = cmd . CmdStr
2023-03-20 19:20:57 -07:00
rtn [ "rawcmdstr" ] = cmd . RawCmdStr
2022-11-28 18:03:02 -08:00
rtn [ "festate" ] = quickJson ( cmd . FeState )
rtn [ "statebasehash" ] = cmd . StatePtr . BaseHash
rtn [ "statediffhasharr" ] = quickJsonArr ( cmd . StatePtr . DiffHashArr )
2022-07-07 00:10:37 -07:00
rtn [ "termopts" ] = quickJson ( cmd . TermOpts )
2022-09-21 22:02:38 -07:00
rtn [ "origtermopts" ] = quickJson ( cmd . OrigTermOpts )
2022-07-07 00:10:37 -07:00
rtn [ "status" ] = cmd . Status
2023-07-30 17:16:43 -07:00
rtn [ "cmdpid" ] = cmd . CmdPid
rtn [ "remotepid" ] = cmd . RemotePid
2024-01-26 16:25:21 -08:00
rtn [ "restartts" ] = cmd . RestartTs
2023-07-30 17:16:43 -07:00
rtn [ "donets" ] = cmd . DoneTs
rtn [ "exitcode" ] = cmd . ExitCode
rtn [ "durationms" ] = cmd . DurationMs
2022-07-07 00:10:37 -07:00
rtn [ "runout" ] = quickJson ( cmd . RunOut )
2022-10-27 00:33:50 -07:00
rtn [ "rtnstate" ] = cmd . RtnState
2022-11-28 18:03:02 -08:00
rtn [ "rtnbasehash" ] = cmd . RtnStatePtr . BaseHash
rtn [ "rtndiffhasharr" ] = quickJsonArr ( cmd . RtnStatePtr . DiffHashArr )
2022-07-07 00:10:37 -07:00
return rtn
}
2023-03-09 18:44:01 -08:00
func ( cmd * CmdType ) FromMap ( m map [ string ] interface {}) bool {
2023-03-15 18:12:55 -07:00
quickSetStr ( & cmd . ScreenId , m , "screenid" )
2023-07-30 17:16:43 -07:00
quickSetStr ( & cmd . LineId , m , "lineid" )
2022-08-24 13:21:54 -07:00
quickSetStr ( & cmd . Remote . OwnerId , m , "remoteownerid" )
quickSetStr ( & cmd . Remote . RemoteId , m , "remoteid" )
quickSetStr ( & cmd . Remote . Name , m , "remotename" )
2022-07-07 00:10:37 -07:00
quickSetStr ( & cmd . CmdStr , m , "cmdstr" )
2023-03-20 19:20:57 -07:00
quickSetStr ( & cmd . RawCmdStr , m , "rawcmdstr" )
2022-11-28 18:03:02 -08:00
quickSetJson ( & cmd . FeState , m , "festate" )
quickSetStr ( & cmd . StatePtr . BaseHash , m , "statebasehash" )
quickSetJsonArr ( & cmd . StatePtr . DiffHashArr , m , "statediffhasharr" )
2022-07-07 00:10:37 -07:00
quickSetJson ( & cmd . TermOpts , m , "termopts" )
2022-09-21 22:02:38 -07:00
quickSetJson ( & cmd . OrigTermOpts , m , "origtermopts" )
2022-07-07 00:10:37 -07:00
quickSetStr ( & cmd . Status , m , "status" )
2023-07-30 17:16:43 -07:00
quickSetInt ( & cmd . CmdPid , m , "cmdpid" )
quickSetInt ( & cmd . RemotePid , m , "remotepid" )
quickSetInt64 ( & cmd . DoneTs , m , "donets" )
2024-01-26 16:25:21 -08:00
quickSetInt64 ( & cmd . RestartTs , m , "restartts" )
2023-07-30 17:16:43 -07:00
quickSetInt ( & cmd . ExitCode , m , "exitcode" )
quickSetInt ( & cmd . DurationMs , m , "durationms" )
2022-07-07 00:10:37 -07:00
quickSetJson ( & cmd . RunOut , m , "runout" )
2022-10-27 00:33:50 -07:00
quickSetBool ( & cmd . RtnState , m , "rtnstate" )
2022-11-28 18:03:02 -08:00
quickSetStr ( & cmd . RtnStatePtr . BaseHash , m , "rtnbasehash" )
quickSetJsonArr ( & cmd . RtnStatePtr . DiffHashArr , m , "rtndiffhasharr" )
2023-03-09 18:44:01 -08:00
return true
2022-06-13 11:11:56 -07:00
}
2023-07-30 17:16:43 -07:00
func ( cmd * CmdType ) IsRunning () bool {
return cmd . Status == CmdStatusRunning || cmd . Status == CmdStatusDetached
}
2023-09-17 14:10:35 -07:00
func makeNewLineCmd ( screenId string , userId string , lineId string , renderer string , lineState map [ string ] any ) * LineType {
2022-06-13 11:11:56 -07:00
rtn := & LineType {}
2023-03-14 16:37:22 -07:00
rtn . ScreenId = screenId
2022-09-20 17:01:25 -07:00
rtn . UserId = userId
2023-07-30 17:16:43 -07:00
rtn . LineId = lineId
2022-06-13 11:11:56 -07:00
rtn . Ts = time . Now (). UnixMilli ()
2022-09-20 17:01:25 -07:00
rtn . LineLocal = true
2022-06-13 11:11:56 -07:00
rtn . LineType = LineTypeCmd
2023-07-30 17:16:43 -07:00
rtn . LineId = lineId
2022-10-27 00:33:50 -07:00
rtn . ContentHeight = LineNoHeight
2023-02-06 00:30:23 -08:00
rtn . Renderer = renderer
2023-09-17 14:10:35 -07:00
if lineState == nil {
lineState = make ( map [ string ] any )
}
rtn . LineState = lineState
2022-06-13 11:11:56 -07:00
return rtn
}
2023-03-20 19:20:57 -07:00
func makeNewLineText ( screenId string , userId string , text string ) * LineType {
2022-06-13 11:11:56 -07:00
rtn := & LineType {}
2023-03-14 16:37:22 -07:00
rtn . ScreenId = screenId
2022-09-20 17:01:25 -07:00
rtn . UserId = userId
2023-11-01 01:26:19 -07:00
rtn . LineId = scbase . GenWaveUUID ()
2022-06-13 11:11:56 -07:00
rtn . Ts = time . Now (). UnixMilli ()
2022-09-20 17:01:25 -07:00
rtn . LineLocal = true
2022-06-13 11:11:56 -07:00
rtn . LineType = LineTypeText
rtn . Text = text
2022-10-27 00:33:50 -07:00
rtn . ContentHeight = LineNoHeight
2023-09-01 16:45:01 -07:00
rtn . LineState = make ( map [ string ] any )
2022-06-13 11:11:56 -07:00
return rtn
}
2022-06-20 21:57:23 -07:00
2023-07-30 17:16:43 -07:00
func makeNewLineOpenAI ( screenId string , userId string , lineId string ) * LineType {
2023-05-04 01:01:13 -07:00
rtn := & LineType {}
rtn . ScreenId = screenId
rtn . UserId = userId
2023-07-30 17:16:43 -07:00
rtn . LineId = lineId
2023-05-04 01:01:13 -07:00
rtn . Ts = time . Now (). UnixMilli ()
rtn . LineLocal = true
rtn . LineType = LineTypeOpenAI
rtn . ContentHeight = LineNoHeight
rtn . Renderer = CmdRendererOpenAI
2023-09-01 16:45:01 -07:00
rtn . LineState = make ( map [ string ] any )
2023-05-04 01:01:13 -07:00
return rtn
}
2023-03-20 19:20:57 -07:00
func AddCommentLine ( ctx context . Context , screenId string , userId string , commentText string ) ( * LineType , error ) {
rtnLine := makeNewLineText ( screenId , userId , commentText )
2022-07-07 21:39:25 -07:00
err := InsertLine ( ctx , rtnLine , nil )
2022-07-05 10:51:47 -07:00
if err != nil {
return nil , err
}
return rtnLine , nil
}
2023-05-04 01:01:13 -07:00
func AddOpenAILine ( ctx context . Context , screenId string , userId string , cmd * CmdType ) ( * LineType , error ) {
2023-07-30 17:16:43 -07:00
rtnLine := makeNewLineOpenAI ( screenId , userId , cmd . LineId )
2023-05-04 01:01:13 -07:00
err := InsertLine ( ctx , rtnLine , cmd )
if err != nil {
return nil , err
}
return rtnLine , nil
}
2023-09-17 14:10:35 -07:00
func AddCmdLine ( ctx context . Context , screenId string , userId string , cmd * CmdType , renderer string , lineState map [ string ] any ) ( * LineType , error ) {
rtnLine := makeNewLineCmd ( screenId , userId , cmd . LineId , renderer , lineState )
2022-07-07 21:39:25 -07:00
err := InsertLine ( ctx , rtnLine , cmd )
2022-07-05 10:51:47 -07:00
if err != nil {
return nil , err
}
return rtnLine , nil
}
2022-07-01 12:17:19 -07:00
func EnsureLocalRemote ( ctx context . Context ) error {
2022-10-04 11:45:24 -07:00
remote , err := GetLocalRemote ( ctx )
2022-07-01 12:17:19 -07:00
if err != nil {
2022-10-04 11:45:24 -07:00
return fmt . Errorf ( "getting local remote from db: %w" , err )
2022-07-01 12:17:19 -07:00
}
if remote != nil {
return nil
}
2022-08-16 15:08:28 -07:00
hostName , err := os . Hostname ()
if err != nil {
return fmt . Errorf ( "getting hostname: %w" , err )
}
user , err := user . Current ()
if err != nil {
return fmt . Errorf ( "getting user: %w" , err )
}
2022-07-01 12:17:19 -07:00
// create the local remote
localRemote := & RemoteType {
2023-11-01 01:26:19 -07:00
RemoteId : scbase . GenWaveUUID (),
2022-08-21 12:31:29 -07:00
RemoteType : RemoteTypeSsh ,
2022-08-24 02:14:16 -07:00
RemoteAlias : LocalRemoteAlias ,
2022-08-16 15:08:28 -07:00
RemoteCanonicalName : fmt . Sprintf ( "%s@%s" , user . Username , hostName ),
RemoteUser : user . Username ,
RemoteHost : hostName ,
2022-08-21 12:31:29 -07:00
ConnectMode : ConnectModeStartup ,
2022-09-24 22:42:52 -07:00
AutoInstall : true ,
2022-08-23 21:05:49 -07:00
SSHOpts : & SSHOpts { Local : true },
2022-10-04 11:45:24 -07:00
Local : true ,
2023-12-28 11:09:41 -08:00
SSHConfigSrc : SSHConfigSrcTypeManual ,
2024-01-16 16:11:04 -08:00
ShellPref : ShellTypePref_Detect ,
2022-07-01 12:17:19 -07:00
}
2022-09-13 17:11:36 -07:00
err = UpsertRemote ( ctx , localRemote )
2022-07-01 12:17:19 -07:00
if err != nil {
return err
}
2022-10-04 11:45:24 -07:00
log . Printf ( "[db] added local remote '%s', id=%s\n" , localRemote . RemoteCanonicalName , localRemote . RemoteId )
2022-12-29 00:07:16 -08:00
sudoRemote := & RemoteType {
2023-11-01 01:26:19 -07:00
RemoteId : scbase . GenWaveUUID (),
2022-12-29 00:07:16 -08:00
RemoteType : RemoteTypeSsh ,
RemoteAlias : "sudo" ,
RemoteCanonicalName : fmt . Sprintf ( "sudo@%s@%s" , user . Username , hostName ),
RemoteUser : "root" ,
RemoteHost : hostName ,
ConnectMode : ConnectModeManual ,
AutoInstall : true ,
2023-05-02 12:43:54 -07:00
SSHOpts : & SSHOpts { Local : true , IsSudo : true },
2022-12-29 00:07:16 -08:00
RemoteOpts : & RemoteOptsType { Color : "red" },
Local : true ,
2023-12-28 11:09:41 -08:00
SSHConfigSrc : SSHConfigSrcTypeManual ,
2024-01-16 16:11:04 -08:00
ShellPref : ShellTypePref_Detect ,
2022-12-29 00:07:16 -08:00
}
err = UpsertRemote ( ctx , sudoRemote )
if err != nil {
return err
}
log . Printf ( "[db] added sudo remote '%s', id=%s\n" , sudoRemote . RemoteCanonicalName , sudoRemote . RemoteId )
2022-08-19 13:23:00 -07:00
return nil
}
2022-08-26 16:21:19 -07:00
func createClientData ( tx * TxWrap ) error {
2022-08-15 18:42:25 -07:00
curve := elliptic . P384 ()
pkey , err := ecdsa . GenerateKey ( curve , rand . Reader )
if err != nil {
return fmt . Errorf ( "generating P-834 key: %w" , err )
}
pkBytes , err := x509 . MarshalECPrivateKey ( pkey )
if err != nil {
return fmt . Errorf ( "marshaling (pkcs8) private key bytes: %w" , err )
}
pubBytes , err := x509 . MarshalPKIXPublicKey ( & pkey . PublicKey )
if err != nil {
return fmt . Errorf ( "marshaling (pkix) public key bytes: %w" , err )
}
2022-09-21 22:02:38 -07:00
c := ClientData {
ClientId : uuid . New (). String (),
UserId : uuid . New (). String (),
UserPrivateKeyBytes : pkBytes ,
UserPublicKeyBytes : pubBytes ,
ActiveSessionId : "" ,
2022-09-25 00:26:33 -07:00
WinSize : ClientWinSizeType {},
2023-03-20 19:20:57 -07:00
CmdStoreType : CmdStoreTypeScreen ,
2023-12-15 17:43:54 -08:00
ReleaseInfo : ReleaseInfoType {},
2022-09-21 22:02:38 -07:00
}
2023-12-15 17:43:54 -08:00
query := `INSERT INTO client ( clientid, userid, activesessionid, userpublickeybytes, userprivatekeybytes, winsize, cmdstoretype, releaseinfo)
VALUES (:clientid,:userid,:activesessionid,:userpublickeybytes,:userprivatekeybytes,:winsize,:cmdstoretype,:releaseinfo)`
2023-03-27 14:11:02 -07:00
tx . NamedExec ( query , dbutil . ToDBMap ( c , false ))
2022-10-31 12:40:45 -07:00
log . Printf ( "create new clientid[%s] userid[%s] with public/private keypair\n" , c . ClientId , c . UserId )
2022-08-15 18:42:25 -07:00
return nil
}
2022-08-26 16:21:19 -07:00
func EnsureClientData ( ctx context . Context ) ( * ClientData , error ) {
2023-03-09 18:44:01 -08:00
rtn , err := WithTxRtn ( ctx , func ( tx * TxWrap ) ( * ClientData , error ) {
2022-08-15 18:42:25 -07:00
query := `SELECT count(*) FROM client`
count := tx . GetInt ( query )
if count > 1 {
2023-03-09 18:44:01 -08:00
return nil , fmt . Errorf ( "invalid client database, multiple (%d) rows in client table" , count )
2022-08-15 18:42:25 -07:00
}
if count == 0 {
2022-08-26 16:21:19 -07:00
createErr := createClientData ( tx )
2022-08-15 18:42:25 -07:00
if createErr != nil {
2023-03-09 18:44:01 -08:00
return nil , createErr
2022-08-15 18:42:25 -07:00
}
}
2023-03-27 14:11:02 -07:00
cdata := dbutil . GetMappable [ * ClientData ]( tx , `SELECT * FROM client` )
2022-09-21 22:02:38 -07:00
if cdata == nil {
2023-03-09 18:44:01 -08:00
return nil , fmt . Errorf ( "no client data found" )
2022-08-15 18:42:25 -07:00
}
2023-03-24 10:34:07 -07:00
dbVersion := tx . GetInt ( `SELECT version FROM schema_migrations` )
cdata . DBVersion = dbVersion
2023-03-09 18:44:01 -08:00
return cdata , nil
2022-08-15 18:42:25 -07:00
})
if err != nil {
return nil , err
}
if rtn . UserId == "" {
return nil , fmt . Errorf ( "invalid client data (no userid)" )
}
if len ( rtn . UserPrivateKeyBytes ) == 0 || len ( rtn . UserPublicKeyBytes ) == 0 {
return nil , fmt . Errorf ( "invalid client data (no public/private keypair)" )
}
rtn . UserPrivateKey , err = x509 . ParseECPrivateKey ( rtn . UserPrivateKeyBytes )
if err != nil {
return nil , fmt . Errorf ( "invalid client data, cannot parse private key: %w" , err )
}
pubKey , err := x509 . ParsePKIXPublicKey ( rtn . UserPublicKeyBytes )
if err != nil {
return nil , fmt . Errorf ( "invalid client data, cannot parse public key: %w" , err )
}
var ok bool
rtn . UserPublicKey , ok = pubKey .( * ecdsa . PublicKey )
if ! ok {
return nil , fmt . Errorf ( "invalid client data, wrong public key type: %T" , pubKey )
}
2023-03-09 18:44:01 -08:00
return rtn , nil
2022-08-15 18:42:25 -07:00
}
2023-01-22 23:10:18 -08:00
func SetClientOpts ( ctx context . Context , clientOpts ClientOptsType ) error {
txErr := WithTx ( ctx , func ( tx * TxWrap ) error {
query := `UPDATE client SET clientopts = ?`
2023-02-14 16:17:54 -08:00
tx . Exec ( query , quickJson ( clientOpts ))
2023-01-22 23:10:18 -08:00
return nil
})
return txErr
}
2023-12-15 17:43:54 -08:00
func SetReleaseInfo ( ctx context . Context , releaseInfo ReleaseInfoType ) error {
txErr := WithTx ( ctx , func ( tx * TxWrap ) error {
query := `UPDATE client SET releaseinfo = ?`
tx . Exec ( query , quickJson ( releaseInfo ))
return nil
})
return txErr
}
2024-01-17 13:07:01 -05:00
// Sets the in-memory status indicator for the given screenId to the given value and adds it to the ModelUpdate. By default, the active screen will be ignored when updating status. To force a status update for the active screen, set force=true.
2024-02-15 16:45:47 -08:00
func SetStatusIndicatorLevel_Update ( ctx context . Context , update * scbus . ModelUpdatePacketType , screenId string , level StatusIndicatorLevel , force bool ) error {
2024-01-17 13:07:01 -05:00
var newStatus StatusIndicatorLevel
if force {
// Force the update and set the new status to the given level, regardless of the current status or the active screen
ScreenMemSetIndicatorLevel ( screenId , level )
newStatus = level
} else {
// Only update the status if the given screen is not the active screen and if the given level is higher than the current level
activeSessionId , err := GetActiveSessionId ( ctx )
if err != nil {
return fmt . Errorf ( "error getting active session id: %w" , err )
}
bareSession , err := GetBareSessionById ( ctx , activeSessionId )
if err != nil {
return fmt . Errorf ( "error getting bare session: %w" , err )
}
activeScreenId := bareSession . ActiveScreenId
if activeScreenId == screenId {
return nil
}
// If we are not forcing the update, follow the rules for combining status indicators
newLevel := ScreenMemCombineIndicatorLevels ( screenId , level )
if newLevel == level {
newStatus = level
} else {
return nil
}
}
2024-02-15 16:45:47 -08:00
update . AddUpdate ( ScreenStatusIndicatorType {
2024-01-17 13:07:01 -05:00
ScreenId : screenId ,
Status : newStatus ,
2024-02-09 17:19:44 -08:00
})
2024-01-17 13:07:01 -05:00
return nil
}
// Sets the in-memory status indicator for the given screenId to the given value and pushes the new value to the FE
2024-01-28 13:47:36 -08:00
func SetStatusIndicatorLevel ( ctx context . Context , screenId string , level StatusIndicatorLevel , force bool ) error {
2024-02-15 16:45:47 -08:00
update := scbus . MakeUpdatePacket ()
2024-01-17 13:07:01 -05:00
err := SetStatusIndicatorLevel_Update ( ctx , update , screenId , level , false )
if err != nil {
2024-01-28 13:47:36 -08:00
return err
2024-01-17 13:07:01 -05:00
}
2024-02-15 16:45:47 -08:00
scbus . MainUpdateBus . DoUpdate ( update )
2024-01-28 13:47:36 -08:00
return nil
2024-01-17 13:07:01 -05:00
}
// Resets the in-memory status indicator for the given screenId to StatusIndicatorLevel_None and adds it to the ModelUpdate
2024-02-15 16:45:47 -08:00
func ResetStatusIndicator_Update ( update * scbus . ModelUpdatePacketType , screenId string ) error {
2024-01-17 13:07:01 -05:00
// We do not need to set context when resetting the status indicator because we will not need to call the DB
return SetStatusIndicatorLevel_Update ( context . TODO (), update , screenId , StatusIndicatorLevel_None , true )
}
// Resets the in-memory status indicator for the given screenId to StatusIndicatorLevel_None and pushes the new value to the FE
2024-01-28 13:47:36 -08:00
func ResetStatusIndicator ( screenId string ) error {
2024-01-17 13:07:01 -05:00
// We do not need to set context when resetting the status indicator because we will not need to call the DB
2024-01-28 13:47:36 -08:00
return SetStatusIndicatorLevel ( context . TODO (), screenId , StatusIndicatorLevel_None , true )
}
2024-02-15 16:45:47 -08:00
func IncrementNumRunningCmds_Update ( update * scbus . ModelUpdatePacketType , screenId string , delta int ) {
2024-01-28 13:47:36 -08:00
newNum := ScreenMemIncrementNumRunningCommands ( screenId , delta )
2024-02-15 16:45:47 -08:00
update . AddUpdate ( ScreenNumRunningCommandsType {
2024-01-28 13:47:36 -08:00
ScreenId : screenId ,
Num : newNum ,
2024-02-09 17:19:44 -08:00
})
2024-01-28 13:47:36 -08:00
}
func IncrementNumRunningCmds ( screenId string , delta int ) {
2024-02-15 16:45:47 -08:00
update := scbus . MakeUpdatePacket ()
2024-01-28 13:47:36 -08:00
IncrementNumRunningCmds_Update ( update , screenId , delta )
2024-02-15 16:45:47 -08:00
scbus . MainUpdateBus . DoUpdate ( update )
2024-01-17 13:07:01 -05:00
}