2023-10-17 06:31:13 +02:00
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
2022-06-10 09:35:24 +02:00
package packet
import (
2022-06-16 01:29:39 +02:00
"bytes"
2022-07-06 23:35:27 +02:00
"context"
2022-06-29 06:57:30 +02:00
"encoding/base64"
2022-06-10 09:35:24 +02:00
"encoding/json"
2022-08-11 01:07:41 +02:00
"errors"
2022-06-10 09:35:24 +02:00
"fmt"
"io"
2024-03-19 01:11:13 +01:00
"io/fs"
2024-03-21 07:38:05 +01:00
"log"
2022-06-29 04:01:33 +02:00
"os"
2022-06-14 23:17:36 +02:00
"reflect"
2022-06-11 06:37:21 +02:00
"sync"
2024-03-19 01:11:13 +01:00
"time"
2022-06-27 21:03:47 +02:00
2023-10-16 22:25:53 +02:00
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
2024-02-16 02:42:43 +01:00
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
2022-06-10 09:35:24 +02:00
)
2022-07-06 02:45:46 +02:00
// single : <init, >run, >cmddata, >cmddone, <cmdstart, <>data, <>dataack, <cmddone
// single(detached): <init, >run, >cmddata, >cmddone, <cmdstart
// server : <init, >run, >cmddata, >cmddone, <cmdstart, <>data, <>dataack, <cmddone
// >cd, >getcmd, >untailcmd, >input, <resp
// all : <>error, <>message, <>ping, <raw
2023-09-01 07:03:38 +02:00
//
// >streamfile, <streamfileresp, <filedata*
// >writefile, <writefileready, >filedata*, <writefiledone
2022-06-23 19:16:54 +02:00
2022-08-09 23:23:59 +02:00
const MaxCompGenValues = 100
2022-06-24 22:25:09 +02:00
var GlobalDebug = false
2022-06-23 19:16:54 +02:00
const (
2023-09-01 07:03:38 +02:00
RunPacketStr = "run" // rpc
PingPacketStr = "ping"
InitPacketStr = "init"
DataPacketStr = "data" // command
DataAckPacketStr = "dataack" // command
CmdStartPacketStr = "cmdstart" // rpc-response
CmdDonePacketStr = "cmddone" // command
DataEndPacketStr = "dataend"
ResponsePacketStr = "resp" // rpc-response
DonePacketStr = "done"
MessagePacketStr = "message"
GetCmdPacketStr = "getcmd" // rpc
UntailCmdPacketStr = "untailcmd" // rpc
CdPacketStr = "cd" // rpc
RawPacketStr = "raw"
SpecialInputPacketStr = "sinput" // command
CompGenPacketStr = "compgen" // rpc
ReInitPacketStr = "reinit" // rpc
CmdFinalPacketStr = "cmdfinal" // command, pushed at the "end" of a command (fail-safe for no cmddone)
StreamFilePacketStr = "streamfile" // rpc
StreamFileResponseStr = "streamfileresp" // rpc-response
WriteFilePacketStr = "writefile" // rpc
WriteFileReadyPacketStr = "writefileready" // rpc-response
WriteFileDonePacketStr = "writefiledone" // rpc-response
FileDataPacketStr = "filedata"
2024-03-19 01:11:13 +01:00
FileStatPacketStr = "filestat"
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
LogPacketStr = "log" // logging packet (sent from waveshell back to server)
ShellStatePacketStr = "shellstate"
2024-03-21 07:38:05 +01:00
RpcInputPacketStr = "rpcinput" // rpc-followup
2023-05-09 03:00:46 +02:00
2023-12-16 07:43:59 +01:00
OpenAIPacketStr = "openai" // other
OpenAICloudReqStr = "openai-cloudreq"
2022-06-23 19:16:54 +02:00
)
2022-06-14 23:17:36 +02:00
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
const (
ShellType_bash = "bash"
ShellType_zsh = "zsh"
)
2024-03-07 01:37:54 +01:00
const (
reinit updates (#500)
* working on re-init when you create a tab. some refactoring of existing reinit to make the messaging clearer. auto-connect, etc.
* working to remove the 'default' shell states out of MShellProc. each tab should have its own state that gets set on open.
* refactor newtab settings into individual components (and move to a new file)
* more refactoring of tab settings -- use same control in settings and newtab
* have screensettings use the same newtab settings components
* use same conn dropdown, fix classes, update some of the confirm messages to be less confusing (replace screen with tab)
* force a cr on a new tab to initialize state in a new line. poc right now, need to add to new workspace workflow as well
* small fixups
* remove nohist from GetRawStr, make const
* update hover behavior for tabs
* fix interaction between change remote dropdown, cmdinput, error handling, and selecting a remote
* only switch screen remote if the activemainview is session (new remote flow). don't switch it if we're on the connections page which is confusing. also make it interactive
* fix wording on tos modal
* allow empty workspaces. also allow the last workspace to be deleted. (prep for new startup sequence where we initialize the first session after tos modal)
* add some dead code that might come in use later (when we change how we show connection in cmdinput)
* working a cople different angles. new settings tab-pulldown (likely orphaned). and then allowing null activeScreen and null activeSession in workspaceview (show appropriate messages, and give buttons to create new tabs/workspaces). prep for new startup flow
* don't call initActiveShells anymore. also call ensureWorkspace() on TOS close
* trying to use new pulldown screen settings
* experiment with an escape keybinding
* working on tab settings close triggers
* close tab settings on tab switch
* small updates to tos popup, reorder, update button text/size, small wording updates
* when deleting a screen, send SIGHUP to all running commands
* not sure how this happened, lineid should not be passed to setLineFocus
* remove context timeouts for ReInit (it is now interactive, so it gets canceled like a normal command -- via ^C, and should not timeout on its own)
* deal with screen/session tombstones updates (ignore to quite warning)
* remove defaultfestate from remote
* fix issue with removing default ris
* remove dead code
* open the settings pulldown for new screens
* update prompt to show when the shell is still initializing (or if it failed)
* switch buttons to use wave button class, update messages, and add warning for no shell state
* all an override of rptr for dyncmds. needed for the 'connect' command (we need to set the rptr to the *new* connection rather than the old one)
* remove old commented out code
2024-03-27 08:22:57 +01:00
EC_InvalidCwd = "ERRCWD"
EC_CmdNotRunning = "CMDNOTRUNNING"
2024-03-07 01:37:54 +01:00
)
2022-06-24 09:02:18 +02:00
const PacketSenderQueueSize = 20
2023-12-16 07:20:03 +01:00
const PacketEOFStr = "EOF"
2022-06-14 23:17:36 +02:00
var TypeStrToFactory map [ string ] reflect . Type
2024-01-18 00:39:24 +01:00
const OpenAICmdInfoChatGreetingMessage = "Hello, may I help you with this command? \n(Ctrl-Space: open, ESC: close, Ctrl+L: clear chat buffer, Up/Down: select code blocks, Enter: to copy a selected code block to the command input)"
2024-01-12 02:34:23 +01:00
2022-06-14 23:17:36 +02:00
func init ( ) {
TypeStrToFactory = make ( map [ string ] reflect . Type )
TypeStrToFactory [ RunPacketStr ] = reflect . TypeOf ( RunPacketType { } )
TypeStrToFactory [ PingPacketStr ] = reflect . TypeOf ( PingPacketType { } )
2022-06-23 19:16:54 +02:00
TypeStrToFactory [ ResponsePacketStr ] = reflect . TypeOf ( ResponsePacketType { } )
2022-06-14 23:17:36 +02:00
TypeStrToFactory [ DonePacketStr ] = reflect . TypeOf ( DonePacketType { } )
TypeStrToFactory [ MessagePacketStr ] = reflect . TypeOf ( MessagePacketType { } )
TypeStrToFactory [ CmdStartPacketStr ] = reflect . TypeOf ( CmdStartPacketType { } )
TypeStrToFactory [ CmdDonePacketStr ] = reflect . TypeOf ( CmdDonePacketType { } )
TypeStrToFactory [ GetCmdPacketStr ] = reflect . TypeOf ( GetCmdPacketType { } )
2022-06-17 02:24:29 +02:00
TypeStrToFactory [ UntailCmdPacketStr ] = reflect . TypeOf ( UntailCmdPacketType { } )
2022-06-23 21:48:45 +02:00
TypeStrToFactory [ InitPacketStr ] = reflect . TypeOf ( InitPacketType { } )
2022-06-15 07:16:58 +02:00
TypeStrToFactory [ CdPacketStr ] = reflect . TypeOf ( CdPacketType { } )
2022-06-16 01:29:39 +02:00
TypeStrToFactory [ RawPacketStr ] = reflect . TypeOf ( RawPacketType { } )
2022-09-06 01:32:08 +02:00
TypeStrToFactory [ SpecialInputPacketStr ] = reflect . TypeOf ( SpecialInputPacketType { } )
2022-06-23 19:16:54 +02:00
TypeStrToFactory [ DataPacketStr ] = reflect . TypeOf ( DataPacketType { } )
2022-06-24 02:37:05 +02:00
TypeStrToFactory [ DataAckPacketStr ] = reflect . TypeOf ( DataAckPacketType { } )
2022-06-29 06:57:30 +02:00
TypeStrToFactory [ DataEndPacketStr ] = reflect . TypeOf ( DataEndPacketType { } )
2022-08-09 23:23:59 +02:00
TypeStrToFactory [ CompGenPacketStr ] = reflect . TypeOf ( CompGenPacketType { } )
2022-10-28 06:59:17 +02:00
TypeStrToFactory [ ReInitPacketStr ] = reflect . TypeOf ( ReInitPacketType { } )
2022-11-27 22:47:18 +01:00
TypeStrToFactory [ CmdFinalPacketStr ] = reflect . TypeOf ( CmdFinalPacketType { } )
2023-09-01 07:03:38 +02:00
TypeStrToFactory [ StreamFilePacketStr ] = reflect . TypeOf ( StreamFilePacketType { } )
TypeStrToFactory [ StreamFileResponseStr ] = reflect . TypeOf ( StreamFileResponseType { } )
2023-05-09 03:00:46 +02:00
TypeStrToFactory [ OpenAIPacketStr ] = reflect . TypeOf ( OpenAIPacketType { } )
2023-09-01 07:03:38 +02:00
TypeStrToFactory [ FileDataPacketStr ] = reflect . TypeOf ( FileDataPacketType { } )
TypeStrToFactory [ WriteFilePacketStr ] = reflect . TypeOf ( WriteFilePacketType { } )
TypeStrToFactory [ WriteFileReadyPacketStr ] = reflect . TypeOf ( WriteFileReadyPacketType { } )
TypeStrToFactory [ WriteFileDonePacketStr ] = reflect . TypeOf ( WriteFileDonePacketType { } )
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
TypeStrToFactory [ LogPacketStr ] = reflect . TypeOf ( LogPacketType { } )
TypeStrToFactory [ ShellStatePacketStr ] = reflect . TypeOf ( ShellStatePacketType { } )
2024-03-19 01:11:13 +01:00
TypeStrToFactory [ FileStatPacketStr ] = reflect . TypeOf ( FileStatPacketType { } )
2024-03-21 07:38:05 +01:00
TypeStrToFactory [ RpcInputPacketStr ] = reflect . TypeOf ( RpcInputPacketType { } )
2022-07-06 01:53:31 +02:00
var _ RpcPacketType = ( * RunPacketType ) ( nil )
var _ RpcPacketType = ( * GetCmdPacketType ) ( nil )
var _ RpcPacketType = ( * UntailCmdPacketType ) ( nil )
var _ RpcPacketType = ( * CdPacketType ) ( nil )
2022-08-09 23:23:59 +02:00
var _ RpcPacketType = ( * CompGenPacketType ) ( nil )
2022-10-28 06:59:17 +02:00
var _ RpcPacketType = ( * ReInitPacketType ) ( nil )
2023-09-01 07:03:38 +02:00
var _ RpcPacketType = ( * StreamFilePacketType ) ( nil )
var _ RpcPacketType = ( * WriteFilePacketType ) ( nil )
2022-07-06 01:53:31 +02:00
var _ RpcResponsePacketType = ( * CmdStartPacketType ) ( nil )
var _ RpcResponsePacketType = ( * ResponsePacketType ) ( nil )
2023-09-01 07:03:38 +02:00
var _ RpcResponsePacketType = ( * StreamFileResponseType ) ( nil )
var _ RpcResponsePacketType = ( * FileDataPacketType ) ( nil )
var _ RpcResponsePacketType = ( * WriteFileReadyPacketType ) ( nil )
var _ RpcResponsePacketType = ( * WriteFileDonePacketType ) ( nil )
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
var _ RpcResponsePacketType = ( * ShellStatePacketType ) ( nil )
2022-07-06 01:53:31 +02:00
2024-03-21 07:38:05 +01:00
var _ RpcFollowUpPacketType = ( * FileDataPacketType ) ( nil )
var _ RpcFollowUpPacketType = ( * RpcInputPacketType ) ( nil )
2022-07-06 01:53:31 +02:00
var _ CommandPacketType = ( * DataPacketType ) ( nil )
var _ CommandPacketType = ( * DataAckPacketType ) ( nil )
var _ CommandPacketType = ( * CmdDonePacketType ) ( nil )
2022-09-06 01:32:08 +02:00
var _ CommandPacketType = ( * SpecialInputPacketType ) ( nil )
2022-11-27 22:47:18 +01:00
var _ CommandPacketType = ( * CmdFinalPacketType ) ( nil )
2022-06-14 23:17:36 +02:00
}
2022-07-02 02:37:37 +02:00
func RegisterPacketType ( typeStr string , rtype reflect . Type ) {
TypeStrToFactory [ typeStr ] = rtype
}
2022-06-14 23:17:36 +02:00
func MakePacket ( packetType string ) ( PacketType , error ) {
rtype := TypeStrToFactory [ packetType ]
if rtype == nil {
return nil , fmt . Errorf ( "invalid packet type '%s'" , packetType )
}
rtn := reflect . New ( rtype )
return rtn . Interface ( ) . ( PacketType ) , nil
}
2022-06-10 09:35:24 +02:00
type PingPacketType struct {
Type string ` json:"type" `
}
func ( * PingPacketType ) GetType ( ) string {
return PingPacketStr
}
func MakePingPacket ( ) * PingPacketType {
return & PingPacketType { Type : PingPacketStr }
}
2024-03-21 07:38:05 +01:00
type RpcInputPacketType struct {
Type string ` json:"type" `
ReqId string ` json:"reqid" `
Data [ ] byte ` json:"data" `
}
func ( * RpcInputPacketType ) GetType ( ) string {
return RpcInputPacketStr
}
func ( p * RpcInputPacketType ) GetAssociatedReqId ( ) string {
return p . ReqId
}
func MakeRpcInputPacket ( reqId string ) * RpcInputPacketType {
return & RpcInputPacketType { Type : RpcInputPacketStr , ReqId : reqId }
}
// these packets can travel either direction
// so it is both a RpcResponsePacketType and an RpcFollowUpPacketType
2023-09-01 07:03:38 +02:00
type FileDataPacketType struct {
Type string ` json:"type" `
RespId string ` json:"respid" `
Data [ ] byte ` json:"data" `
Eof bool ` json:"eof,omitempty" `
Error string ` json:"error,omitempty" `
}
func ( * FileDataPacketType ) GetType ( ) string {
return FileDataPacketStr
}
func MakeFileDataPacket ( reqId string ) * FileDataPacketType {
return & FileDataPacketType {
Type : FileDataPacketStr ,
RespId : reqId ,
}
}
2024-03-21 07:38:05 +01:00
func ( p * FileDataPacketType ) GetAssociatedReqId ( ) string {
return p . RespId
}
2023-09-01 07:03:38 +02:00
func ( p * FileDataPacketType ) GetResponseId ( ) string {
return p . RespId
}
func ( p * FileDataPacketType ) GetResponseDone ( ) bool {
return p . Eof || p . Error != ""
}
2022-06-23 19:16:54 +02:00
type DataPacketType struct {
2022-06-27 21:03:47 +02:00
Type string ` json:"type" `
CK base . CommandKey ` json:"ck" `
FdNum int ` json:"fdnum" `
Data64 string ` json:"data64" ` // base64 encoded
Eof bool ` json:"eof,omitempty" `
Error string ` json:"error,omitempty" `
2022-06-23 19:16:54 +02:00
}
func ( * DataPacketType ) GetType ( ) string {
return DataPacketStr
}
2022-06-27 21:03:47 +02:00
func ( p * DataPacketType ) GetCK ( ) base . CommandKey {
return p . CK
}
2022-06-25 08:42:00 +02:00
func B64DecodedLen ( b64 string ) int {
if len ( b64 ) < 4 {
return 0 // we use padded strings, so < 4 is always 0
}
realLen := 3 * ( len ( b64 ) / 4 )
if b64 [ len ( b64 ) - 1 ] == '=' {
realLen --
}
if b64 [ len ( b64 ) - 2 ] == '=' {
realLen --
}
return realLen
}
func ( p * DataPacketType ) String ( ) string {
eofStr := ""
if p . Eof {
eofStr = ", eof"
}
errStr := ""
if p . Error != "" {
errStr = fmt . Sprintf ( ", err=%s" , p . Error )
}
return fmt . Sprintf ( "data[fd=%d, len=%d%s%s]" , p . FdNum , B64DecodedLen ( p . Data64 ) , eofStr , errStr )
}
2022-06-23 21:48:45 +02:00
func MakeDataPacket ( ) * DataPacketType {
return & DataPacketType { Type : DataPacketStr }
2022-06-23 19:16:54 +02:00
}
2022-06-29 06:57:30 +02:00
type DataEndPacketType struct {
Type string ` json:"type" `
CK base . CommandKey ` json:"ck" `
}
func MakeDataEndPacket ( ck base . CommandKey ) * DataEndPacketType {
return & DataEndPacketType { Type : DataEndPacketStr , CK : ck }
}
func ( * DataEndPacketType ) GetType ( ) string {
return DataEndPacketStr
}
2022-06-24 02:37:05 +02:00
type DataAckPacketType struct {
2022-06-27 21:03:47 +02:00
Type string ` json:"type" `
CK base . CommandKey ` json:"ck" `
FdNum int ` json:"fdnum" `
AckLen int ` json:"acklen" `
Error string ` json:"error,omitempty" `
2022-06-24 02:37:05 +02:00
}
func ( * DataAckPacketType ) GetType ( ) string {
return DataAckPacketStr
}
2022-06-27 21:03:47 +02:00
func ( p * DataAckPacketType ) GetCK ( ) base . CommandKey {
return p . CK
}
2022-06-25 08:42:00 +02:00
func ( p * DataAckPacketType ) String ( ) string {
errStr := ""
if p . Error != "" {
errStr = fmt . Sprintf ( " err=%s" , p . Error )
}
return fmt . Sprintf ( "ack[fd=%d, acklen=%d%s]" , p . FdNum , p . AckLen , errStr )
}
2022-06-24 02:37:05 +02:00
func MakeDataAckPacket ( ) * DataAckPacketType {
return & DataAckPacketType { Type : DataAckPacketStr }
}
2022-09-06 01:32:08 +02:00
type WinSize struct {
Rows int ` json:"rows" `
Cols int ` json:"cols" `
}
2022-06-18 00:31:07 +02:00
// SigNum gets sent to process via a signal
// WinSize, if set, will run TIOCSWINSZ to set size, and then send SIGWINCH
2022-09-06 01:32:08 +02:00
type SpecialInputPacketType struct {
Type string ` json:"type" `
CK base . CommandKey ` json:"ck" `
2022-12-21 06:58:24 +01:00
SigName string ` json:"signame,omitempty" ` // passed to unix.SignalNum (needs 'SIG' prefix, e.g. "SIGTERM"), also accepts a number (e.g. "9")
2022-09-06 01:32:08 +02:00
WinSize * WinSize ` json:"winsize,omitempty" `
2022-06-18 00:31:07 +02:00
}
2022-09-06 01:32:08 +02:00
func ( * SpecialInputPacketType ) GetType ( ) string {
return SpecialInputPacketStr
2022-06-18 00:31:07 +02:00
}
2022-09-06 01:32:08 +02:00
func ( p * SpecialInputPacketType ) GetCK ( ) base . CommandKey {
2022-06-27 21:03:47 +02:00
return p . CK
}
2022-09-06 01:32:08 +02:00
func MakeSpecialInputPacket ( ) * SpecialInputPacketType {
return & SpecialInputPacketType { Type : SpecialInputPacketStr }
2022-06-18 00:31:07 +02:00
}
2022-06-17 02:24:29 +02:00
type UntailCmdPacketType struct {
2022-06-27 21:03:47 +02:00
Type string ` json:"type" `
ReqId string ` json:"reqid" `
CK base . CommandKey ` json:"ck" `
2022-06-17 02:24:29 +02:00
}
func ( * UntailCmdPacketType ) GetType ( ) string {
return UntailCmdPacketStr
}
2022-07-06 01:53:31 +02:00
func ( p * UntailCmdPacketType ) GetReqId ( ) string {
return p . ReqId
2022-06-27 21:03:47 +02:00
}
2022-06-17 02:24:29 +02:00
func MakeUntailCmdPacket ( ) * UntailCmdPacketType {
return & UntailCmdPacketType { Type : UntailCmdPacketStr }
}
2022-06-14 23:17:36 +02:00
type GetCmdPacketType struct {
2022-07-08 06:37:17 +02:00
Type string ` json:"type" `
ReqId string ` json:"reqid" `
CK base . CommandKey ` json:"ck" `
PtyPos int64 ` json:"ptypos" `
RunPos int64 ` json:"runpos" `
Tail bool ` json:"tail,omitempty" `
PtyOnly bool ` json:"ptyonly,omitempty" `
2022-06-14 23:17:36 +02:00
}
func ( * GetCmdPacketType ) GetType ( ) string {
return GetCmdPacketStr
}
2022-07-06 01:53:31 +02:00
func ( p * GetCmdPacketType ) GetReqId ( ) string {
return p . ReqId
2022-06-27 21:03:47 +02:00
}
2022-06-14 23:17:36 +02:00
func MakeGetCmdPacket ( ) * GetCmdPacketType {
return & GetCmdPacketType { Type : GetCmdPacketStr }
}
2022-06-15 07:16:58 +02:00
type CdPacketType struct {
2022-07-06 01:53:31 +02:00
Type string ` json:"type" `
ReqId string ` json:"reqid" `
Dir string ` json:"dir" `
2022-06-15 07:16:58 +02:00
}
func ( * CdPacketType ) GetType ( ) string {
return CdPacketStr
}
2022-07-06 01:53:31 +02:00
func ( p * CdPacketType ) GetReqId ( ) string {
return p . ReqId
2022-06-23 19:16:54 +02:00
}
2022-06-15 07:16:58 +02:00
func MakeCdPacket ( ) * CdPacketType {
return & CdPacketType { Type : CdPacketStr }
}
2022-10-28 06:59:17 +02:00
type ReInitPacketType struct {
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
Type string ` json:"type" `
ShellType string ` json:"shelltype" `
ReqId string ` json:"reqid" `
2022-10-28 06:59:17 +02:00
}
func ( * ReInitPacketType ) GetType ( ) string {
return ReInitPacketStr
}
func ( p * ReInitPacketType ) GetReqId ( ) string {
return p . ReqId
}
func MakeReInitPacket ( ) * ReInitPacketType {
return & ReInitPacketType { Type : ReInitPacketStr }
}
2024-03-19 01:11:13 +01:00
type FileStatPacketType struct {
Type string ` json:"type" `
Name string ` json:"name" `
Size int64 ` json:"size" `
ModTs time . Time ` json:"modts" `
IsDir bool ` json:"isdir" `
Perm int ` json:"perm" `
ModeStr string ` json:"modestr" `
Error string ` json:"error" `
Done bool ` json:"done" `
RespId string ` json:"respid" `
Path string ` json:"path" `
}
func ( * FileStatPacketType ) GetType ( ) string {
return FileStatPacketStr
}
func ( p * FileStatPacketType ) GetResponseDone ( ) bool {
return p . Done
}
func ( p * FileStatPacketType ) GetResponseId ( ) string {
return p . RespId
}
func MakeFileStatPacketType ( ) * FileStatPacketType {
return & FileStatPacketType { Type : FileStatPacketStr }
}
func MakeFileStatPacketFromFileInfo ( finfo fs . FileInfo , err string , done bool ) * FileStatPacketType {
resp := MakeFileStatPacketType ( )
resp . Error = err
resp . Done = done
resp . IsDir = finfo . IsDir ( )
resp . Name = finfo . Name ( )
resp . Size = finfo . Size ( )
resp . ModTs = finfo . ModTime ( )
resp . Perm = int ( finfo . Mode ( ) . Perm ( ) )
resp . ModeStr = finfo . Mode ( ) . String ( )
return resp
}
2023-09-01 07:03:38 +02:00
type StreamFilePacketType struct {
Type string ` json:"type" `
ReqId string ` json:"reqid" `
Path string ` json:"path" `
ByteRange [ ] int64 ` json:"byterange" ` // works like the http "Range" header (multiple ranges are not allowed)
StatOnly bool ` json:"statonly,omitempty" ` // set if you just want the stat response (no data returned)
}
func ( * StreamFilePacketType ) GetType ( ) string {
return StreamFilePacketStr
}
func ( p * StreamFilePacketType ) GetReqId ( ) string {
return p . ReqId
}
func MakeStreamFilePacket ( ) * StreamFilePacketType {
return & StreamFilePacketType { Type : StreamFilePacketStr }
}
type FileInfo struct {
2023-09-07 06:45:15 +02:00
Name string ` json:"name" `
Size int64 ` json:"size" `
ModTs int64 ` json:"modts" `
IsDir bool ` json:"isdir,omitempty" `
Perm int ` json:"perm" `
NotFound bool ` json:"notfound,omitempty" ` // when NotFound is set, Perm will be set to permission for directory
2023-09-01 07:03:38 +02:00
}
type StreamFileResponseType struct {
Type string ` json:"type" `
RespId string ` json:"respid" `
Done bool ` json:"done,omitempty" `
Info * FileInfo ` json:"info,omitempty" `
Error string ` json:"error,omitempty" `
}
func ( * StreamFileResponseType ) GetType ( ) string {
return StreamFileResponseStr
}
func ( p * StreamFileResponseType ) GetResponseId ( ) string {
return p . RespId
}
func ( p * StreamFileResponseType ) GetResponseDone ( ) bool {
return p . Done
}
func MakeStreamFileResponse ( respId string ) * StreamFileResponseType {
return & StreamFileResponseType {
Type : StreamFileResponseStr ,
RespId : respId ,
}
}
2022-08-09 23:23:59 +02:00
type CompGenPacketType struct {
Type string ` json:"type" `
ReqId string ` json:"reqid" `
Prefix string ` json:"prefix" `
CompType string ` json:"comptype" `
Cwd string ` json:"cwd" `
}
func IsValidCompGenType ( t string ) bool {
2022-11-10 05:38:47 +01:00
return ( t == "file" || t == "command" || t == "directory" || t == "variable" )
2022-08-09 23:23:59 +02:00
}
func ( * CompGenPacketType ) GetType ( ) string {
return CompGenPacketStr
}
func ( p * CompGenPacketType ) GetReqId ( ) string {
return p . ReqId
}
func MakeCompGenPacket ( ) * CompGenPacketType {
return & CompGenPacketType { Type : CompGenPacketStr }
}
2022-06-23 19:16:54 +02:00
type ResponsePacketType struct {
2024-03-07 01:37:54 +01:00
Type string ` json:"type" `
RespId string ` json:"respid" `
Success bool ` json:"success" `
Error string ` json:"error,omitempty" `
ErrorCode string ` json:"errorcode,omitempty" ` // can be used for structured errors
Data interface { } ` json:"data,omitempty" `
2022-06-23 19:16:54 +02:00
}
func ( * ResponsePacketType ) GetType ( ) string {
return ResponsePacketStr
2022-06-15 07:16:58 +02:00
}
2022-07-06 01:53:31 +02:00
func ( p * ResponsePacketType ) GetResponseId ( ) string {
return p . RespId
2022-06-15 07:16:58 +02:00
}
2022-07-06 08:14:14 +02:00
func ( * ResponsePacketType ) GetResponseDone ( ) bool {
return true
}
2022-08-11 01:07:41 +02:00
func ( p * ResponsePacketType ) Err ( ) error {
if p == nil {
return fmt . Errorf ( "no response received" )
}
if ! p . Success {
if p . Error != "" {
2024-03-07 01:37:54 +01:00
if p . ErrorCode != "" {
return & base . CodedError { ErrorCode : p . ErrorCode , Err : errors . New ( p . Error ) }
}
2022-08-11 01:07:41 +02:00
return errors . New ( p . Error )
}
return fmt . Errorf ( "rpc failed" )
}
return nil
}
2022-08-20 00:28:32 +02:00
func ( p * ResponsePacketType ) String ( ) string {
if p . Success {
return "response[success]"
}
return fmt . Sprintf ( "response[error:%s]" , p . Error )
}
2022-07-06 02:45:46 +02:00
func MakeErrorResponsePacket ( reqId string , err error ) * ResponsePacketType {
2024-03-07 01:37:54 +01:00
if codedErr , ok := err . ( * base . CodedError ) ; ok {
return & ResponsePacketType { Type : ResponsePacketStr , RespId : reqId , Error : codedErr . Err . Error ( ) , ErrorCode : codedErr . ErrorCode }
}
2022-07-06 02:45:46 +02:00
return & ResponsePacketType { Type : ResponsePacketStr , RespId : reqId , Error : err . Error ( ) }
}
func MakeResponsePacket ( reqId string , data interface { } ) * ResponsePacketType {
return & ResponsePacketType { Type : ResponsePacketStr , RespId : reqId , Success : true , Data : data }
2022-06-15 07:16:58 +02:00
}
2022-06-16 01:29:39 +02:00
type RawPacketType struct {
Type string ` json:"type" `
Data string ` json:"data" `
}
func ( * RawPacketType ) GetType ( ) string {
return RawPacketStr
}
2022-06-25 08:42:00 +02:00
func ( p * RawPacketType ) String ( ) string {
return fmt . Sprintf ( "raw[%s]" , p . Data )
}
2022-06-16 01:29:39 +02:00
func MakeRawPacket ( val string ) * RawPacketType {
return & RawPacketType { Type : RawPacketStr , Data : val }
}
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
type LogPacketType struct {
2024-02-16 02:42:43 +01:00
Type string ` json:"type" `
Entry wlog . LogEntry ` json:"entry" `
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
}
func ( * LogPacketType ) GetType ( ) string {
return LogPacketStr
}
func ( p * LogPacketType ) String ( ) string {
return "log"
}
2024-02-16 02:42:43 +01:00
func MakeLogPacket ( entry wlog . LogEntry ) * LogPacketType {
return & LogPacketType { Type : LogPacketStr , Entry : entry }
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
}
type ShellStatePacketType struct {
2024-03-20 00:38:38 +01:00
Type string ` json:"type" `
ShellType string ` json:"shelltype" `
RespId string ` json:"respid,omitempty" `
State * ShellState ` json:"state" `
Stats * ShellStateStats ` json:"stats" `
Error string ` json:"error,omitempty" `
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
}
func ( * ShellStatePacketType ) GetType ( ) string {
return ShellStatePacketStr
}
func ( p * ShellStatePacketType ) String ( ) string {
return fmt . Sprintf ( "shellstate[%s]" , p . ShellType )
}
func ( p * ShellStatePacketType ) GetResponseId ( ) string {
return p . RespId
}
func ( p * ShellStatePacketType ) GetResponseDone ( ) bool {
return true
}
func MakeShellStatePacket ( ) * ShellStatePacketType {
return & ShellStatePacketType { Type : ShellStatePacketStr }
}
2022-06-11 06:37:21 +02:00
type MessagePacketType struct {
2022-09-06 21:57:54 +02:00
Type string ` json:"type" `
CK base . CommandKey ` json:"ck,omitempty" `
Message string ` json:"message" `
2022-06-11 06:37:21 +02:00
}
func ( * MessagePacketType ) GetType ( ) string {
return MessagePacketStr
}
2022-06-25 08:42:00 +02:00
func ( p * MessagePacketType ) String ( ) string {
return fmt . Sprintf ( "messsage[%s]" , p . Message )
}
2022-06-11 06:37:21 +02:00
func MakeMessagePacket ( message string ) * MessagePacketType {
return & MessagePacketType { Type : MessagePacketStr , Message : message }
}
2022-06-16 10:10:56 +02:00
func FmtMessagePacket ( fmtStr string , args ... interface { } ) * MessagePacketType {
message := fmt . Sprintf ( fmtStr , args ... )
return & MessagePacketType { Type : MessagePacketStr , Message : message }
}
2022-06-23 21:48:45 +02:00
type InitPacketType struct {
zsh support (#227)
adds zsh support to waveterm. big change, lots going on here. lots of other improvements and bug fixes added while debugging and building out the feature.
Commits:
* refactor shexec parser.go into new package shellenv. separate out bash specific parsing from generic functions
* checkpoint
* work on refactoring shexec. created two new packages shellapi (for bash/zsh specific stuff), and shellutil (shared between shellapi and shexec)
* more refactoring
* create shellapi interface to abstract bash specific functionality
* more refactoring, move bash shell state parsing to shellapi
* move makeRcFile to shellapi. remove all of the 'client' options CLI options from waveshell
* get shellType passed through to server/single paths for waveshell
* add a local shelltype detector
* mock out a zshapi
* move shelltype through more of the code
* get a command to run via zsh
* zsh can now switch directories. poc, needs cleanup
* working on ShellState encoding differences between zsh/bash. Working on parsing zsh decls. move utilfn package into waveshell (shouldn't have been in wavesrv)
* switch to use []byte for vardecl serialization + diffs
* progress on zsh environment. still have issues reconciling init environment with trap environment
* fix typeset argument parsing
* parse promptvars, more zsh specific ignores
* fix bug with promptvar not getting set (wrong check in FeState func)
* add sdk (issue #188) to list of rtnstate commands
* more zsh compatibility -- working with a larger ohmyzsh environment. ignore more variables, handle exit trap better. unique path/fpath. add a processtype variable to base.
* must return a value
* zsh alias parsing/restoring. diff changes (and rtnstate changes). introduces linediff v1.
* force zmodload of zsh/parameter
* starting work on zsh functions
* need a v1 of mapdiff as well (to handle null chars)
* pack/unpack of ints was wrong (one used int and one use uint). turned out we only ever encoded '0' so it worked. that also means it is safe to change unpack to unpackUInt
* reworking for binary encoding of aliases and functions (because of zsh allows any character, including nulls, in names and values)
* fixes, working on functions, issue with line endings
* zsh functions. lots of ugliness here around dealing with line dicipline and cooked stty. new runcommand function to grab output from a non-tty fd. note that we still to run the actual command in a stty to get the proper output.
* write uuid tempdir, cleanup with tmprcfilename code
* hack in some simple zsh function declaration finding code for rtnstate. create function diff for rtnstate that supports zsh
* make sure key order is constant so shell hashes are consistent
* fix problems with state diffs to support new zsh formats. add diff/apply code to shellapi (moved from shellenv), that is now specific to zsh or bash
* add log packet and new shellstate packets
* switch to shellstate map that's also keyed by shelltype
* add shelltype to remoteinstance
* remove shell argument from waveshell
* added new shelltype statemap to remote.go (msh), deal with fallout
* move shellstate out of init packet, and move to an explicit reinit call. try to initialize all of the active shell states
* change dont always store init state (only store on demand). initialize shell states on demand (if not already initialized). allow reset to change shells
* add shellpref field to remote table. use to drive the default shell choice for new tabs
* show shelltag on cmdinput, pass through ri and remote (defaultshellstate)
* bump mshell version to v0.4
* better version validation for shellstate. also relax compatibility requirements for diffing states (shelltype + major version need to match)
* better error handling, check shellstate compatibility during run (on waveshell server)
* add extra separator for bash shellstate processing to deal with spurious output from rc files
* special migration for v30 -- flag invalid bash shell states and show special button in UI to fix
* format
* remove zsh-decls (unused)
* remove test code
* remove debug print
* fix typo
2024-01-17 01:11:04 +01:00
Type string ` json:"type" `
RespId string ` json:"respid,omitempty" `
Version string ` json:"version" `
BuildTime string ` json:"buildtime,omitempty" `
MShellHomeDir string ` json:"mshellhomedir,omitempty" `
HomeDir string ` json:"homedir,omitempty" `
User string ` json:"user,omitempty" `
HostName string ` json:"hostname,omitempty" `
NotFound bool ` json:"notfound,omitempty" `
UName string ` json:"uname,omitempty" `
Shell string ` json:"shell,omitempty" `
RemoteId string ` json:"remoteid,omitempty" `
2022-06-15 07:16:58 +02:00
}
2022-06-23 21:48:45 +02:00
func ( * InitPacketType ) GetType ( ) string {
return InitPacketStr
2022-06-15 07:16:58 +02:00
}
2022-10-25 21:31:07 +02:00
func ( pk * InitPacketType ) GetResponseId ( ) string {
return pk . RespId
}
func ( pk * InitPacketType ) GetResponseDone ( ) bool {
return true
}
2022-06-23 21:48:45 +02:00
func MakeInitPacket ( ) * InitPacketType {
return & InitPacketType { Type : InitPacketStr }
2022-06-15 07:16:58 +02:00
}
2022-06-10 09:35:24 +02:00
type DonePacketType struct {
Type string ` json:"type" `
}
func ( * DonePacketType ) GetType ( ) string {
return DonePacketStr
}
func MakeDonePacket ( ) * DonePacketType {
return & DonePacketType { Type : DonePacketStr }
}
2022-11-27 22:47:18 +01:00
type CmdFinalPacketType struct {
Type string ` json:"type" `
Ts int64 ` json:"ts" `
CK base . CommandKey ` json:"ck" `
Error string ` json:"error" `
}
func ( * CmdFinalPacketType ) GetType ( ) string {
return CmdFinalPacketStr
}
func ( pk * CmdFinalPacketType ) GetCK ( ) base . CommandKey {
return pk . CK
}
func MakeCmdFinalPacket ( ck base . CommandKey ) * CmdFinalPacketType {
return & CmdFinalPacketType { Type : CmdFinalPacketStr , CK : ck }
}
2022-06-11 06:37:21 +02:00
type CmdDonePacketType struct {
2024-03-29 00:56:39 +01:00
Type string ` json:"type" `
Ts int64 ` json:"ts" `
CK base . CommandKey ` json:"ck" `
ExitCode int ` json:"exitcode" `
DurationMs int64 ` json:"durationms" `
FinalState * ShellState ` json:"finalstate,omitempty" `
FinalStateDiff * ShellStateDiff ` json:"finalstatediff,omitempty" `
FinalStateBasePtr * ShellStatePtr ` json:"finalstatebaseptr,omitempty" `
2022-06-11 06:37:21 +02:00
}
func ( * CmdDonePacketType ) GetType ( ) string {
return CmdDonePacketStr
}
2022-06-27 21:03:47 +02:00
func ( p * CmdDonePacketType ) GetCK ( ) base . CommandKey {
return p . CK
}
2022-07-06 08:14:14 +02:00
func MakeCmdDonePacket ( ck base . CommandKey ) * CmdDonePacketType {
return & CmdDonePacketType { Type : CmdDonePacketStr , CK : ck }
2022-06-11 06:37:21 +02:00
}
type CmdStartPacketType struct {
2022-06-27 21:03:47 +02:00
Type string ` json:"type" `
2023-05-09 03:00:46 +02:00
RespId string ` json:"respid,omitempty" `
2022-06-27 21:03:47 +02:00
Ts int64 ` json:"ts" `
CK base . CommandKey ` json:"ck" `
2023-05-09 03:00:46 +02:00
Pid int ` json:"pid,omitempty" `
MShellPid int ` json:"mshellpid,omitempty" `
2022-06-10 09:35:24 +02:00
}
2022-06-11 06:37:21 +02:00
func ( * CmdStartPacketType ) GetType ( ) string {
return CmdStartPacketStr
2022-06-10 09:35:24 +02:00
}
2022-07-06 01:53:31 +02:00
func ( p * CmdStartPacketType ) GetResponseId ( ) string {
return p . RespId
2022-06-27 21:03:47 +02:00
}
2022-07-06 08:14:14 +02:00
func ( * CmdStartPacketType ) GetResponseDone ( ) bool {
return true
}
func MakeCmdStartPacket ( reqId string ) * CmdStartPacketType {
return & CmdStartPacketType { Type : CmdStartPacketStr , RespId : reqId }
2022-06-10 09:35:24 +02:00
}
2022-07-06 23:06:58 +02:00
type TermOpts struct {
2022-08-20 00:28:32 +02:00
Rows int ` json:"rows" `
Cols int ` json:"cols" `
Term string ` json:"term" `
MaxPtySize int64 ` json:"maxptysize,omitempty" `
2023-12-12 23:24:09 +01:00
FlexRows bool ` json:"flexrows,omitempty" `
2022-06-23 19:16:54 +02:00
}
type RemoteFd struct {
2022-06-29 06:57:30 +02:00
FdNum int ` json:"fdnum" `
Read bool ` json:"read" `
Write bool ` json:"write" `
DupStdin bool ` json:"-" `
}
type RunDataType struct {
FdNum int ` json:"fdnum" `
DataLen int ` json:"datalen" `
Data [ ] byte ` json:"-" `
2022-06-23 19:16:54 +02:00
}
2022-06-10 09:35:24 +02:00
type RunPacketType struct {
2022-10-17 08:46:59 +02:00
Type string ` json:"type" `
ReqId string ` json:"reqid" `
CK base . CommandKey ` json:"ck" `
2024-03-29 00:56:39 +01:00
ShellType string ` json:"shelltype" ` // added in Wave v0.6.0 (either "bash" or "zsh") (set by remote.go)
2022-10-17 08:46:59 +02:00
Command string ` json:"command" `
2022-11-27 22:47:18 +01:00
State * ShellState ` json:"state,omitempty" `
2024-03-29 00:56:39 +01:00
StatePtr * ShellStatePtr ` json:"stateptr,omitempty" ` // added in Wave v0.7.2
2022-10-17 08:46:59 +02:00
StateComplete bool ` json:"statecomplete,omitempty" ` // set to true if state is complete (the default env should not be set)
UsePty bool ` json:"usepty,omitempty" `
TermOpts * TermOpts ` json:"termopts,omitempty" `
Fds [ ] RemoteFd ` json:"fds,omitempty" `
RunData [ ] RunDataType ` json:"rundata,omitempty" `
Detached bool ` json:"detached,omitempty" `
2022-10-22 23:45:31 +02:00
ReturnState bool ` json:"returnstate,omitempty" `
2022-06-10 09:35:24 +02:00
}
2022-06-21 02:51:28 +02:00
func ( * RunPacketType ) GetType ( ) string {
2022-06-10 09:35:24 +02:00
return RunPacketStr
}
2022-07-06 01:53:31 +02:00
func ( p * RunPacketType ) GetReqId ( ) string {
return p . ReqId
2022-06-27 21:03:47 +02:00
}
2022-06-14 23:17:36 +02:00
func MakeRunPacket ( ) * RunPacketType {
return & RunPacketType { Type : RunPacketStr }
}
2023-05-09 03:00:46 +02:00
type OpenAIUsageType struct {
PromptTokens int ` json:"prompt_tokens,omitempty" `
CompletionTokens int ` json:"completion_tokens,omitempty" `
TotalTokens int ` json:"total_tokens,omitempty" `
}
2024-01-12 02:34:23 +01:00
type OpenAICmdInfoPacketOutputType struct {
Model string ` json:"model,omitempty" `
Created int64 ` json:"created,omitempty" `
FinishReason string ` json:"finish_reason,omitempty" `
Message string ` json:"message,omitempty" `
Error string ` json:"error,omitempty" `
}
2023-05-09 03:00:46 +02:00
type OpenAIPacketType struct {
Type string ` json:"type" `
Model string ` json:"model,omitempty" `
Created int64 ` json:"created,omitempty" `
FinishReason string ` json:"finish_reason,omitempty" `
Usage * OpenAIUsageType ` json:"usage,omitempty" `
Index int ` json:"index,omitempty" `
Text string ` json:"text,omitempty" `
Error string ` json:"error,omitempty" `
}
func ( * OpenAIPacketType ) GetType ( ) string {
return OpenAIPacketStr
}
func MakeOpenAIPacket ( ) * OpenAIPacketType {
return & OpenAIPacketType { Type : OpenAIPacketStr }
}
2022-06-10 09:35:24 +02:00
type BarePacketType struct {
Type string ` json:"type" `
}
2023-09-01 07:03:38 +02:00
type WriteFilePacketType struct {
Type string ` json:"type" `
ReqId string ` json:"reqid" `
UseTemp bool ` json:"usetemp,omitempty" `
Path string ` json:"path" `
}
func ( * WriteFilePacketType ) GetType ( ) string {
return WriteFilePacketStr
}
func ( p * WriteFilePacketType ) GetReqId ( ) string {
return p . ReqId
}
func MakeWriteFilePacket ( ) * WriteFilePacketType {
return & WriteFilePacketType { Type : WriteFilePacketStr }
}
type WriteFileReadyPacketType struct {
Type string ` json:"type" `
RespId string ` json:"reqid" `
Error string ` json:"error,omitempty" `
}
func ( * WriteFileReadyPacketType ) GetType ( ) string {
return WriteFileReadyPacketStr
}
func ( p * WriteFileReadyPacketType ) GetResponseId ( ) string {
return p . RespId
}
func ( p * WriteFileReadyPacketType ) GetResponseDone ( ) bool {
return p . Error != ""
}
func MakeWriteFileReadyPacket ( reqId string ) * WriteFileReadyPacketType {
return & WriteFileReadyPacketType {
Type : WriteFileReadyPacketStr ,
RespId : reqId ,
}
}
type WriteFileDonePacketType struct {
Type string ` json:"type" `
RespId string ` json:"reqid" `
Error string ` json:"error,omitempty" `
}
func ( * WriteFileDonePacketType ) GetType ( ) string {
return WriteFileDonePacketStr
}
func ( p * WriteFileDonePacketType ) GetResponseId ( ) string {
return p . RespId
}
func ( p * WriteFileDonePacketType ) GetResponseDone ( ) bool {
return true
}
func MakeWriteFileDonePacket ( reqId string ) * WriteFileDonePacketType {
return & WriteFileDonePacketType {
Type : WriteFileDonePacketStr ,
RespId : reqId ,
}
}
2024-01-12 02:34:23 +01:00
type OpenAICmdInfoChatMessage struct {
MessageID int ` json:"messageid" `
IsAssistantResponse bool ` json:"isassistantresponse,omitempty" `
AssistantResponse * OpenAICmdInfoPacketOutputType ` json:"assistantresponse,omitempty" `
UserQuery string ` json:"userquery,omitempty" `
UserEngineeredQuery string ` json:"userengineeredquery,omitempty" `
}
2023-12-16 07:43:59 +01:00
type OpenAIPromptMessageType struct {
Role string ` json:"role" `
Content string ` json:"content" `
Name string ` json:"name,omitempty" `
}
type OpenAICloudReqPacketType struct {
Type string ` json:"type" `
ClientId string ` json:"clientid" `
Prompt [ ] OpenAIPromptMessageType ` json:"prompt" `
MaxTokens int ` json:"maxtokens,omitempty" `
MaxChoices int ` json:"maxchoices,omitempty" `
}
func ( * OpenAICloudReqPacketType ) GetType ( ) string {
return OpenAICloudReqStr
}
func MakeOpenAICloudReqPacket ( ) * OpenAICloudReqPacketType {
return & OpenAICloudReqPacketType {
Type : OpenAICloudReqStr ,
}
}
2022-06-10 09:35:24 +02:00
type PacketType interface {
GetType ( ) string
}
2022-06-25 08:42:00 +02:00
func AsString ( pk PacketType ) string {
2022-08-31 21:45:59 +02:00
if pk == nil {
return "nil"
}
2022-06-25 08:42:00 +02:00
if s , ok := pk . ( fmt . Stringer ) ; ok {
return s . String ( )
}
return fmt . Sprintf ( "%s[]" , pk . GetType ( ) )
}
2022-06-23 19:16:54 +02:00
type RpcPacketType interface {
GetType ( ) string
2022-07-06 01:53:31 +02:00
GetReqId ( ) string
}
type RpcResponsePacketType interface {
GetType ( ) string
GetResponseId ( ) string
2022-07-06 08:14:14 +02:00
GetResponseDone ( ) bool
2022-06-23 19:16:54 +02:00
}
2022-06-27 21:03:47 +02:00
type CommandPacketType interface {
GetType ( ) string
GetCK ( ) base . CommandKey
}
2024-03-21 07:38:05 +01:00
// RpcPackets initiate an Rpc. these can be part of the data passed back and forth
type RpcFollowUpPacketType interface {
GetType ( ) string
GetAssociatedReqId ( ) string
}
2024-02-16 02:42:43 +01:00
type ModelUpdatePacketType struct {
Type string ` json:"type" `
Updates [ ] any ` json:"updates" `
}
2022-06-29 00:04:08 +02:00
func AsExtType ( pk PacketType ) string {
if rpcPacket , ok := pk . ( RpcPacketType ) ; ok {
2022-07-06 01:53:31 +02:00
return fmt . Sprintf ( "%s[%s]" , rpcPacket . GetType ( ) , rpcPacket . GetReqId ( ) )
2022-06-29 00:04:08 +02:00
} else if cmdPacket , ok := pk . ( CommandPacketType ) ; ok {
return fmt . Sprintf ( "%s[%s]" , cmdPacket . GetType ( ) , cmdPacket . GetCK ( ) )
} else {
return pk . GetType ( )
}
}
2022-06-10 09:35:24 +02:00
func ParseJsonPacket ( jsonBuf [ ] byte ) ( PacketType , error ) {
var bareCmd BarePacketType
err := json . Unmarshal ( jsonBuf , & bareCmd )
if err != nil {
return nil , err
}
if bareCmd . Type == "" {
return nil , fmt . Errorf ( "received packet with no type" )
}
2022-06-14 23:17:36 +02:00
pk , err := MakePacket ( bareCmd . Type )
if err != nil {
return nil , err
2022-06-11 06:37:21 +02:00
}
2022-06-14 23:17:36 +02:00
err = json . Unmarshal ( jsonBuf , pk )
if err != nil {
2022-11-23 07:59:29 +01:00
return nil , fmt . Errorf ( "unmarshaling %q packet: %v" , bareCmd . Type , err )
2022-06-10 09:35:24 +02:00
}
2022-06-14 23:17:36 +02:00
return pk , nil
2022-06-10 09:35:24 +02:00
}
2022-11-27 22:47:18 +01:00
type SendError struct {
IsWriteError bool // fatal
IsMarshalError bool // not fatal
PacketType string
Err error
}
func ( e * SendError ) Unwrap ( ) error {
return e . Err
}
func ( e * SendError ) Error ( ) string {
if e . IsMarshalError {
return fmt . Sprintf ( "SendPacket marshal-error '%s' packet: %v" , e . PacketType , e . Err )
} else if e . IsWriteError {
2022-12-06 07:26:13 +01:00
return fmt . Sprintf ( "SendPacket write-error packet[%s]: %v" , e . PacketType , e . Err )
2022-11-27 22:47:18 +01:00
} else {
return e . Err . Error ( )
}
}
2023-05-09 03:00:46 +02:00
func MarshalPacket ( packet PacketType ) ( [ ] byte , error ) {
2022-06-10 09:35:24 +02:00
if packet == nil {
2023-05-09 03:00:46 +02:00
return nil , fmt . Errorf ( "invalid nil packet" )
2022-06-10 09:35:24 +02:00
}
2022-06-16 01:29:39 +02:00
jsonBytes , err := json . Marshal ( packet )
2022-06-10 09:35:24 +02:00
if err != nil {
2023-05-09 03:00:46 +02:00
return nil , & SendError { IsMarshalError : true , PacketType : packet . GetType ( ) , Err : err }
2022-06-10 09:35:24 +02:00
}
2022-06-16 01:29:39 +02:00
var outBuf bytes . Buffer
outBuf . WriteByte ( '\n' )
outBuf . WriteString ( fmt . Sprintf ( "##%d" , len ( jsonBytes ) ) )
outBuf . Write ( jsonBytes )
outBuf . WriteByte ( '\n' )
2023-05-09 03:00:46 +02:00
outBytes := outBuf . Bytes ( )
return outBytes , nil
}
func SendPacket ( w io . Writer , packet PacketType ) error {
if packet == nil {
return nil
}
outBytes , err := MarshalPacket ( packet )
if err != nil {
return err
}
2022-06-24 22:25:09 +02:00
if GlobalDebug {
2022-12-06 07:26:13 +01:00
base . Logf ( "SEND> %s\n" , AsString ( packet ) )
2022-06-24 22:25:09 +02:00
}
2022-06-29 23:29:38 +02:00
_ , err = w . Write ( outBytes )
2022-06-10 09:35:24 +02:00
if err != nil {
2022-11-27 22:47:18 +01:00
return & SendError { IsWriteError : true , PacketType : packet . GetType ( ) , Err : err }
2022-06-10 09:35:24 +02:00
}
return nil
}
2022-06-11 06:37:21 +02:00
type PacketSender struct {
2022-11-27 22:47:18 +01:00
Lock * sync . Mutex
SendCh chan PacketType
Done bool
DoneCh chan bool
ErrHandler func ( * PacketSender , PacketType , error )
2022-12-06 07:26:13 +01:00
ExitErr error
2022-06-11 06:37:21 +02:00
}
2022-11-27 22:47:18 +01:00
func MakePacketSender ( output io . Writer , errHandler func ( * PacketSender , PacketType , error ) ) * PacketSender {
2022-06-11 06:37:21 +02:00
sender := & PacketSender {
2022-11-27 22:47:18 +01:00
Lock : & sync . Mutex { } ,
SendCh : make ( chan PacketType , PacketSenderQueueSize ) ,
DoneCh : make ( chan bool ) ,
ErrHandler : errHandler ,
2022-06-11 06:37:21 +02:00
}
go func ( ) {
2022-06-29 00:04:08 +02:00
defer close ( sender . DoneCh )
defer sender . Close ( )
2022-06-11 06:37:21 +02:00
for pk := range sender . SendCh {
err := SendPacket ( output , pk )
if err != nil {
2022-11-27 22:47:18 +01:00
sender . goHandleError ( pk , err )
if serr , ok := err . ( * SendError ) ; ok && serr . IsMarshalError {
// marshaler errors are recoverable
continue
}
// write errors are not recoverable
2022-12-06 07:26:13 +01:00
sender . Lock . Lock ( )
sender . ExitErr = err
sender . Lock . Unlock ( )
2022-06-11 06:37:21 +02:00
return
}
}
} ( )
return sender
}
2024-02-16 02:42:43 +01:00
func ( sender * PacketSender ) SendLogPacket ( entry wlog . LogEntry ) {
sender . SendPacket ( MakeLogPacket ( entry ) )
}
2022-11-27 22:47:18 +01:00
func ( sender * PacketSender ) goHandleError ( pk PacketType , err error ) {
sender . Lock . Lock ( )
defer sender . Lock . Unlock ( )
if sender . ErrHandler != nil {
go sender . ErrHandler ( sender , pk , err )
}
}
2022-07-02 02:37:37 +02:00
func MakeChannelPacketSender ( packetCh chan PacketType ) * PacketSender {
sender := & PacketSender {
Lock : & sync . Mutex { } ,
SendCh : make ( chan PacketType , PacketSenderQueueSize ) ,
DoneCh : make ( chan bool ) ,
}
go func ( ) {
defer close ( sender . DoneCh )
defer sender . Close ( )
for pk := range sender . SendCh {
packetCh <- pk
}
} ( )
return sender
}
2022-06-29 00:04:08 +02:00
func ( sender * PacketSender ) Close ( ) {
sender . Lock . Lock ( )
defer sender . Lock . Unlock ( )
if sender . Done {
return
}
sender . Done = true
2022-06-11 06:37:21 +02:00
close ( sender . SendCh )
}
2022-12-06 07:26:13 +01:00
// returns ExitErr if set
func ( sender * PacketSender ) WaitForDone ( ) error {
2022-06-11 06:37:21 +02:00
<- sender . DoneCh
2022-12-06 07:26:13 +01:00
sender . Lock . Lock ( )
defer sender . Lock . Unlock ( )
return sender . ExitErr
2022-06-11 06:37:21 +02:00
}
2022-12-06 07:26:13 +01:00
// this is "advisory", as there is a race condition between the loop closing and setting Done.
// that's okay because that's an impossible race condition anyway (you could enqueue the packet
// and then the connection dies, or it dies half way, etc.). this just stops blindly adding
// packets forever when the loop is done.
2022-06-11 06:37:21 +02:00
func ( sender * PacketSender ) checkStatus ( ) error {
sender . Lock . Lock ( )
defer sender . Lock . Unlock ( )
if sender . Done {
return fmt . Errorf ( "cannot send packet, sender write loop is closed" )
}
return nil
}
2022-07-06 23:35:27 +02:00
func ( sender * PacketSender ) SendPacketCtx ( ctx context . Context , pk PacketType ) error {
err := sender . checkStatus ( )
if err != nil {
return err
}
select {
case sender . SendCh <- pk :
return nil
case <- ctx . Done ( ) :
return ctx . Err ( )
}
}
2022-06-11 06:37:21 +02:00
func ( sender * PacketSender ) SendPacket ( pk PacketType ) error {
2024-03-21 07:38:05 +01:00
if pk == nil {
log . Printf ( "tried to send nil packet\n" )
return fmt . Errorf ( "tried to send nil packet" )
}
if pk . GetType ( ) == "" {
log . Printf ( "tried to send invalid packet: %T\n" , pk )
return fmt . Errorf ( "tried to send packet without a type: %T" , pk )
}
2022-06-11 06:37:21 +02:00
err := sender . checkStatus ( )
if err != nil {
return err
}
sender . SendCh <- pk
return nil
}
2022-07-06 02:45:46 +02:00
func ( sender * PacketSender ) SendErrorResponse ( reqId string , err error ) error {
pk := MakeErrorResponsePacket ( reqId , err )
return sender . SendPacket ( pk )
2022-06-11 06:37:21 +02:00
}
2022-07-06 02:45:46 +02:00
func ( sender * PacketSender ) SendResponse ( reqId string , data interface { } ) error {
pk := MakeResponsePacket ( reqId , data )
return sender . SendPacket ( pk )
2022-06-29 04:01:33 +02:00
}
2022-11-27 22:47:18 +01:00
func ( sender * PacketSender ) SendMessageFmt ( fmtStr string , args ... interface { } ) error {
2022-06-15 07:16:58 +02:00
return sender . SendPacket ( MakeMessagePacket ( fmt . Sprintf ( fmtStr , args ... ) ) )
}
2022-06-29 04:01:33 +02:00
type UnknownPacketReporter interface {
UnknownPacket ( pk PacketType )
2022-06-16 10:10:56 +02:00
}
2022-06-29 04:01:33 +02:00
type DefaultUPR struct { }
func ( DefaultUPR ) UnknownPacket ( pk PacketType ) {
2024-03-14 02:52:41 +01:00
if pk . GetType ( ) == RawPacketStr {
2022-06-29 04:01:33 +02:00
rawPacket := pk . ( * RawPacketType )
fmt . Fprintf ( os . Stderr , "%s\n" , rawPacket . Data )
2022-07-02 02:37:37 +02:00
} else if pk . GetType ( ) == CmdStartPacketStr {
return // do nothing
2022-06-29 04:01:33 +02:00
} else {
2024-03-14 02:52:41 +01:00
wlog . Logf ( "[upr] invalid packet received '%s'" , AsExtType ( pk ) )
2022-06-29 04:01:33 +02:00
}
2022-09-06 21:57:54 +02:00
}
type MessageUPR struct {
CK base . CommandKey
Sender * PacketSender
}
2022-06-29 04:01:33 +02:00
2022-09-06 21:57:54 +02:00
func ( upr MessageUPR ) UnknownPacket ( pk PacketType ) {
msg := FmtMessagePacket ( "[error] invalid packet received %s" , AsString ( pk ) )
msg . CK = upr . CK
upr . Sender . SendPacket ( msg )
2022-06-16 10:10:56 +02:00
}
2022-06-29 06:57:30 +02:00
// todo: clean hanging entries in RunMap when in server mode
type RunPacketBuilder struct {
RunMap map [ base . CommandKey ] * RunPacketType
}
func MakeRunPacketBuilder ( ) * RunPacketBuilder {
return & RunPacketBuilder {
RunMap : make ( map [ base . CommandKey ] * RunPacketType ) ,
}
}
// returns (consumed, fullRunPacket)
func ( b * RunPacketBuilder ) ProcessPacket ( pk PacketType ) ( bool , * RunPacketType ) {
if pk . GetType ( ) == RunPacketStr {
runPacket := pk . ( * RunPacketType )
2022-06-29 23:29:38 +02:00
if len ( runPacket . RunData ) == 0 {
return true , runPacket
}
2022-06-29 06:57:30 +02:00
b . RunMap [ runPacket . CK ] = runPacket
return true , nil
}
if pk . GetType ( ) == DataEndPacketStr {
endPacket := pk . ( * DataEndPacketType )
runPacket := b . RunMap [ endPacket . CK ] // might be nil
delete ( b . RunMap , endPacket . CK )
return true , runPacket
}
if pk . GetType ( ) == DataPacketStr {
dataPacket := pk . ( * DataPacketType )
runPacket := b . RunMap [ dataPacket . CK ]
if runPacket == nil {
return false , nil
}
for idx , runData := range runPacket . RunData {
if runData . FdNum == dataPacket . FdNum {
// can ignore error, will get caught later with RunData.DataLen check
realData , _ := base64 . StdEncoding . DecodeString ( dataPacket . Data64 )
runData . Data = append ( runData . Data , realData ... )
runPacket . RunData [ idx ] = runData
break
}
}
return true , nil
}
return false , nil
}