2023-10-17 12:31:13 +08:00
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
2022-06-10 00:35:24 -07:00
package packet
import (
2022-06-15 16:29:39 -07:00
"bytes"
2022-07-06 14:35:27 -07:00
"context"
2022-06-28 21:57:30 -07:00
"encoding/base64"
2022-06-10 00:35:24 -07:00
"encoding/json"
2022-08-10 16:07:41 -07:00
"errors"
2022-06-10 00:35:24 -07:00
"fmt"
"io"
2022-06-28 19:01:33 -07:00
"os"
2022-06-14 14:17:36 -07:00
"reflect"
2022-06-10 21:37:21 -07:00
"sync"
2024-01-16 16:11:04 -08:00
"time"
2022-06-27 12:03:47 -07:00
2023-10-16 13:25:53 -07:00
"github.com/wavetermdev/waveterm/waveshell/pkg/base"
2022-06-10 00:35:24 -07:00
)
2022-07-05 17:45:46 -07: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-08-31 22:03:38 -07:00
//
// >streamfile, <streamfileresp, <filedata*
// >writefile, <writefileready, >filedata*, <writefiledone
2022-06-23 10:16:54 -07:00
2022-08-09 14:23:59 -07:00
const MaxCompGenValues = 100
2022-06-24 13:25:09 -07:00
var GlobalDebug = false
2022-06-23 10:16:54 -07:00
const (
2023-08-31 22:03:38 -07: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"
CmdErrorPacketStr = "cmderror" // command
MessagePacketStr = "message"
GetCmdPacketStr = "getcmd" // rpc
UntailCmdPacketStr = "untailcmd" // rpc
CdPacketStr = "cd" // rpc
CmdDataPacketStr = "cmddata" // rpc-response
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-01-16 16:11:04 -08:00
LogPacketStr = "log" // logging packet (sent from waveshell back to server)
ShellStatePacketStr = "shellstate"
2023-05-08 18:00:46 -07:00
2023-12-15 22:43:59 -08:00
OpenAIPacketStr = "openai" // other
OpenAICloudReqStr = "openai-cloudreq"
2022-06-23 10:16:54 -07:00
)
2022-06-14 14:17:36 -07:00
2024-01-16 16:11:04 -08:00
const (
ShellType_bash = "bash"
ShellType_zsh = "zsh"
)
2022-06-24 00:02:18 -07:00
const PacketSenderQueueSize = 20
2023-12-15 22:20:03 -08:00
const PacketEOFStr = "EOF"
2022-06-14 14:17:36 -07:00
var TypeStrToFactory map [ string ] reflect . Type
2024-01-17 15:39:24 -08: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-11 17:34:23 -08:00
2022-06-14 14:17:36 -07:00
func init () {
TypeStrToFactory = make ( map [ string ] reflect . Type )
TypeStrToFactory [ RunPacketStr ] = reflect . TypeOf ( RunPacketType {})
TypeStrToFactory [ PingPacketStr ] = reflect . TypeOf ( PingPacketType {})
2022-06-23 10:16:54 -07:00
TypeStrToFactory [ ResponsePacketStr ] = reflect . TypeOf ( ResponsePacketType {})
2022-06-14 14:17:36 -07:00
TypeStrToFactory [ DonePacketStr ] = reflect . TypeOf ( DonePacketType {})
2022-07-05 17:45:46 -07:00
TypeStrToFactory [ CmdErrorPacketStr ] = reflect . TypeOf ( CmdErrorPacketType {})
2022-06-14 14:17:36 -07:00
TypeStrToFactory [ MessagePacketStr ] = reflect . TypeOf ( MessagePacketType {})
TypeStrToFactory [ CmdStartPacketStr ] = reflect . TypeOf ( CmdStartPacketType {})
TypeStrToFactory [ CmdDonePacketStr ] = reflect . TypeOf ( CmdDonePacketType {})
TypeStrToFactory [ GetCmdPacketStr ] = reflect . TypeOf ( GetCmdPacketType {})
2022-06-16 17:24:29 -07:00
TypeStrToFactory [ UntailCmdPacketStr ] = reflect . TypeOf ( UntailCmdPacketType {})
2022-06-23 12:48:45 -07:00
TypeStrToFactory [ InitPacketStr ] = reflect . TypeOf ( InitPacketType {})
2022-06-14 22:16:58 -07:00
TypeStrToFactory [ CdPacketStr ] = reflect . TypeOf ( CdPacketType {})
TypeStrToFactory [ CmdDataPacketStr ] = reflect . TypeOf ( CmdDataPacketType {})
2022-06-15 16:29:39 -07:00
TypeStrToFactory [ RawPacketStr ] = reflect . TypeOf ( RawPacketType {})
2022-09-05 16:32:08 -07:00
TypeStrToFactory [ SpecialInputPacketStr ] = reflect . TypeOf ( SpecialInputPacketType {})
2022-06-23 10:16:54 -07:00
TypeStrToFactory [ DataPacketStr ] = reflect . TypeOf ( DataPacketType {})
2022-06-23 17:37:05 -07:00
TypeStrToFactory [ DataAckPacketStr ] = reflect . TypeOf ( DataAckPacketType {})
2022-06-28 21:57:30 -07:00
TypeStrToFactory [ DataEndPacketStr ] = reflect . TypeOf ( DataEndPacketType {})
2022-08-09 14:23:59 -07:00
TypeStrToFactory [ CompGenPacketStr ] = reflect . TypeOf ( CompGenPacketType {})
2022-10-27 21:59:17 -07:00
TypeStrToFactory [ ReInitPacketStr ] = reflect . TypeOf ( ReInitPacketType {})
2022-11-27 13:47:18 -08:00
TypeStrToFactory [ CmdFinalPacketStr ] = reflect . TypeOf ( CmdFinalPacketType {})
2023-08-31 22:03:38 -07:00
TypeStrToFactory [ StreamFilePacketStr ] = reflect . TypeOf ( StreamFilePacketType {})
TypeStrToFactory [ StreamFileResponseStr ] = reflect . TypeOf ( StreamFileResponseType {})
2023-05-08 18:00:46 -07:00
TypeStrToFactory [ OpenAIPacketStr ] = reflect . TypeOf ( OpenAIPacketType {})
2023-08-31 22:03:38 -07:00
TypeStrToFactory [ FileDataPacketStr ] = reflect . TypeOf ( FileDataPacketType {})
TypeStrToFactory [ WriteFilePacketStr ] = reflect . TypeOf ( WriteFilePacketType {})
TypeStrToFactory [ WriteFileReadyPacketStr ] = reflect . TypeOf ( WriteFileReadyPacketType {})
TypeStrToFactory [ WriteFileDonePacketStr ] = reflect . TypeOf ( WriteFileDonePacketType {})
2024-01-16 16:11:04 -08:00
TypeStrToFactory [ LogPacketStr ] = reflect . TypeOf ( LogPacketType {})
TypeStrToFactory [ ShellStatePacketStr ] = reflect . TypeOf ( ShellStatePacketType {})
2022-07-05 16:53:31 -07:00
var _ RpcPacketType = ( * RunPacketType )( nil )
var _ RpcPacketType = ( * GetCmdPacketType )( nil )
var _ RpcPacketType = ( * UntailCmdPacketType )( nil )
var _ RpcPacketType = ( * CdPacketType )( nil )
2022-08-09 14:23:59 -07:00
var _ RpcPacketType = ( * CompGenPacketType )( nil )
2022-10-27 21:59:17 -07:00
var _ RpcPacketType = ( * ReInitPacketType )( nil )
2023-08-31 22:03:38 -07:00
var _ RpcPacketType = ( * StreamFilePacketType )( nil )
var _ RpcPacketType = ( * WriteFilePacketType )( nil )
2022-07-05 16:53:31 -07:00
var _ RpcResponsePacketType = ( * CmdStartPacketType )( nil )
var _ RpcResponsePacketType = ( * ResponsePacketType )( nil )
var _ RpcResponsePacketType = ( * CmdDataPacketType )( nil )
2023-08-31 22:03:38 -07:00
var _ RpcResponsePacketType = ( * StreamFileResponseType )( nil )
var _ RpcResponsePacketType = ( * FileDataPacketType )( nil )
var _ RpcResponsePacketType = ( * WriteFileReadyPacketType )( nil )
var _ RpcResponsePacketType = ( * WriteFileDonePacketType )( nil )
2024-01-16 16:11:04 -08:00
var _ RpcResponsePacketType = ( * ShellStatePacketType )( nil )
2022-07-05 16:53:31 -07:00
var _ CommandPacketType = ( * DataPacketType )( nil )
var _ CommandPacketType = ( * DataAckPacketType )( nil )
var _ CommandPacketType = ( * CmdDonePacketType )( nil )
2022-09-05 16:32:08 -07:00
var _ CommandPacketType = ( * SpecialInputPacketType )( nil )
2022-11-27 13:47:18 -08:00
var _ CommandPacketType = ( * CmdFinalPacketType )( nil )
2022-06-14 14:17:36 -07:00
}
2022-07-01 17:37:37 -07:00
func RegisterPacketType ( typeStr string , rtype reflect . Type ) {
TypeStrToFactory [ typeStr ] = rtype
}
2022-06-14 14:17:36 -07: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 00:35:24 -07:00
2022-06-14 22:16:58 -07:00
type CmdDataPacketType struct {
2022-06-27 12:03:47 -07:00
Type string `json:"type"`
2022-07-05 16:53:31 -07:00
RespId string `json:"respid"`
2022-06-27 12:03:47 -07:00
CK base . CommandKey `json:"ck"`
PtyPos int64 `json:"ptypos"`
PtyLen int64 `json:"ptylen"`
RunPos int64 `json:"runpos"`
RunLen int64 `json:"runlen"`
2022-07-05 23:14:14 -07:00
PtyData64 string `json:"ptydata64"`
2022-06-27 12:03:47 -07:00
PtyDataLen int `json:"ptydatalen"`
2022-07-05 23:14:14 -07:00
RunData64 string `json:"rundata64"`
2022-06-27 12:03:47 -07:00
RunDataLen int `json:"rundatalen"`
2022-06-14 22:16:58 -07:00
}
func ( * CmdDataPacketType ) GetType () string {
return CmdDataPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * CmdDataPacketType ) GetResponseId () string {
return p . RespId
2022-06-27 12:03:47 -07:00
}
2022-07-05 23:14:14 -07:00
func ( * CmdDataPacketType ) GetResponseDone () bool {
return false
}
func MakeCmdDataPacket ( reqId string ) * CmdDataPacketType {
return & CmdDataPacketType { Type : CmdDataPacketStr , RespId : reqId }
2022-06-14 22:16:58 -07:00
}
2022-06-10 00:35:24 -07:00
type PingPacketType struct {
Type string `json:"type"`
}
func ( * PingPacketType ) GetType () string {
return PingPacketStr
}
func MakePingPacket () * PingPacketType {
return & PingPacketType { Type : PingPacketStr }
}
2023-08-31 22:03:38 -07: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 ,
}
}
func ( p * FileDataPacketType ) GetResponseId () string {
return p . RespId
}
func ( p * FileDataPacketType ) GetResponseDone () bool {
return p . Eof || p . Error != ""
}
2022-06-23 10:16:54 -07:00
type DataPacketType struct {
2022-06-27 12:03:47 -07: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 10:16:54 -07:00
}
func ( * DataPacketType ) GetType () string {
return DataPacketStr
}
2022-06-27 12:03:47 -07:00
func ( p * DataPacketType ) GetCK () base . CommandKey {
return p . CK
}
2022-06-24 23:42:00 -07: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 12:48:45 -07:00
func MakeDataPacket () * DataPacketType {
return & DataPacketType { Type : DataPacketStr }
2022-06-23 10:16:54 -07:00
}
2022-06-28 21:57:30 -07: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-23 17:37:05 -07:00
type DataAckPacketType struct {
2022-06-27 12:03:47 -07: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-23 17:37:05 -07:00
}
func ( * DataAckPacketType ) GetType () string {
return DataAckPacketStr
}
2022-06-27 12:03:47 -07:00
func ( p * DataAckPacketType ) GetCK () base . CommandKey {
return p . CK
}
2022-06-24 23:42:00 -07: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-23 17:37:05 -07:00
func MakeDataAckPacket () * DataAckPacketType {
return & DataAckPacketType { Type : DataAckPacketStr }
}
2022-09-05 16:32:08 -07:00
type WinSize struct {
Rows int `json:"rows"`
Cols int `json:"cols"`
}
2022-06-17 15:31:07 -07:00
// SigNum gets sent to process via a signal
// WinSize, if set, will run TIOCSWINSZ to set size, and then send SIGWINCH
2022-09-05 16:32:08 -07:00
type SpecialInputPacketType struct {
Type string `json:"type"`
CK base . CommandKey `json:"ck"`
2022-12-20 21:58:24 -08: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-05 16:32:08 -07:00
WinSize * WinSize `json:"winsize,omitempty"`
2022-06-17 15:31:07 -07:00
}
2022-09-05 16:32:08 -07:00
func ( * SpecialInputPacketType ) GetType () string {
return SpecialInputPacketStr
2022-06-17 15:31:07 -07:00
}
2022-09-05 16:32:08 -07:00
func ( p * SpecialInputPacketType ) GetCK () base . CommandKey {
2022-06-27 12:03:47 -07:00
return p . CK
}
2022-09-05 16:32:08 -07:00
func MakeSpecialInputPacket () * SpecialInputPacketType {
return & SpecialInputPacketType { Type : SpecialInputPacketStr }
2022-06-17 15:31:07 -07:00
}
2022-06-16 17:24:29 -07:00
type UntailCmdPacketType struct {
2022-06-27 12:03:47 -07:00
Type string `json:"type"`
ReqId string `json:"reqid"`
CK base . CommandKey `json:"ck"`
2022-06-16 17:24:29 -07:00
}
func ( * UntailCmdPacketType ) GetType () string {
return UntailCmdPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * UntailCmdPacketType ) GetReqId () string {
return p . ReqId
2022-06-27 12:03:47 -07:00
}
2022-06-16 17:24:29 -07:00
func MakeUntailCmdPacket () * UntailCmdPacketType {
return & UntailCmdPacketType { Type : UntailCmdPacketStr }
}
2022-06-14 14:17:36 -07:00
type GetCmdPacketType struct {
2022-07-07 21:37:17 -07: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 14:17:36 -07:00
}
func ( * GetCmdPacketType ) GetType () string {
return GetCmdPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * GetCmdPacketType ) GetReqId () string {
return p . ReqId
2022-06-27 12:03:47 -07:00
}
2022-06-14 14:17:36 -07:00
func MakeGetCmdPacket () * GetCmdPacketType {
return & GetCmdPacketType { Type : GetCmdPacketStr }
}
2022-06-14 22:16:58 -07:00
type CdPacketType struct {
2022-07-05 16:53:31 -07:00
Type string `json:"type"`
ReqId string `json:"reqid"`
Dir string `json:"dir"`
2022-06-14 22:16:58 -07:00
}
func ( * CdPacketType ) GetType () string {
return CdPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * CdPacketType ) GetReqId () string {
return p . ReqId
2022-06-23 10:16:54 -07:00
}
2022-06-14 22:16:58 -07:00
func MakeCdPacket () * CdPacketType {
return & CdPacketType { Type : CdPacketStr }
}
2022-10-27 21:59:17 -07:00
type ReInitPacketType struct {
2024-01-16 16:11:04 -08:00
Type string `json:"type"`
ShellType string `json:"shelltype"`
ReqId string `json:"reqid"`
2022-10-27 21:59:17 -07:00
}
func ( * ReInitPacketType ) GetType () string {
return ReInitPacketStr
}
func ( p * ReInitPacketType ) GetReqId () string {
return p . ReqId
}
func MakeReInitPacket () * ReInitPacketType {
return & ReInitPacketType { Type : ReInitPacketStr }
}
2023-08-31 22:03:38 -07: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-06 21:45:15 -07: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-08-31 22:03:38 -07: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 14:23:59 -07: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-09 20:38:47 -08:00
return ( t == "file" || t == "command" || t == "directory" || t == "variable" )
2022-08-09 14:23:59 -07: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 10:16:54 -07:00
type ResponsePacketType struct {
2022-07-05 16:53:31 -07:00
Type string `json:"type"`
RespId string `json:"respid"`
Success bool `json:"success"`
2022-07-06 00:21:44 -07:00
Error string `json:"error,omitempty"`
Data interface {} `json:"data,omitempty"`
2022-06-14 22:16:58 -07:00
}
2022-06-23 10:16:54 -07:00
func ( * ResponsePacketType ) GetType () string {
return ResponsePacketStr
2022-06-14 22:16:58 -07:00
}
2022-07-05 16:53:31 -07:00
func ( p * ResponsePacketType ) GetResponseId () string {
return p . RespId
2022-06-23 10:16:54 -07:00
}
2022-07-05 23:14:14 -07:00
func ( * ResponsePacketType ) GetResponseDone () bool {
return true
}
2022-08-10 16:07:41 -07:00
func ( p * ResponsePacketType ) Err () error {
if p == nil {
return fmt . Errorf ( "no response received" )
}
if ! p . Success {
if p . Error != "" {
return errors . New ( p . Error )
}
return fmt . Errorf ( "rpc failed" )
}
return nil
}
2022-08-19 15:28:32 -07:00
func ( p * ResponsePacketType ) String () string {
if p . Success {
return "response[success]"
}
return fmt . Sprintf ( "response[error:%s]" , p . Error )
}
2022-07-05 17:45:46 -07:00
func MakeErrorResponsePacket ( reqId string , err error ) * ResponsePacketType {
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-14 22:16:58 -07:00
}
2022-06-15 16:29:39 -07:00
type RawPacketType struct {
Type string `json:"type"`
Data string `json:"data"`
}
func ( * RawPacketType ) GetType () string {
return RawPacketStr
}
2022-06-24 23:42:00 -07:00
func ( p * RawPacketType ) String () string {
return fmt . Sprintf ( "raw[%s]" , p . Data )
}
2022-06-15 16:29:39 -07:00
func MakeRawPacket ( val string ) * RawPacketType {
return & RawPacketType { Type : RawPacketStr , Data : val }
}
2024-01-16 16:11:04 -08:00
type LogPacketType struct {
Type string `json:"type"`
Ts int64 `json:"ts"` // log timestamp
ReqId string `json:"reqid,omitempty"` // if this log line is related to an rpc request
ProcInfo string `json:"procinfo,omitempty"` // server/single
LogLine string `json:"logline"` // the logline data
}
func ( * LogPacketType ) GetType () string {
return LogPacketStr
}
func ( p * LogPacketType ) String () string {
return "log"
}
func MakeLogPacket () * LogPacketType {
return & LogPacketType { Type : LogPacketStr , Ts : time . Now (). UnixMilli ()}
}
type ShellStatePacketType struct {
Type string `json:"type"`
ShellType string `json:"shelltype"`
RespId string `json:"respid,omitempty"`
State * ShellState `json:"state"`
Error string `json:"error,omitempty"`
}
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-10 21:37:21 -07:00
type MessagePacketType struct {
2022-09-06 12:57:54 -07:00
Type string `json:"type"`
CK base . CommandKey `json:"ck,omitempty"`
Message string `json:"message"`
2022-06-10 21:37:21 -07:00
}
func ( * MessagePacketType ) GetType () string {
return MessagePacketStr
}
2022-06-24 23:42:00 -07:00
func ( p * MessagePacketType ) String () string {
return fmt . Sprintf ( "messsage[%s]" , p . Message )
}
2022-06-10 21:37:21 -07:00
func MakeMessagePacket ( message string ) * MessagePacketType {
return & MessagePacketType { Type : MessagePacketStr , Message : message }
}
2022-06-16 01:10:56 -07:00
func FmtMessagePacket ( fmtStr string , args ... interface {}) * MessagePacketType {
message := fmt . Sprintf ( fmtStr , args ... )
return & MessagePacketType { Type : MessagePacketStr , Message : message }
}
2022-06-23 12:48:45 -07:00
type InitPacketType struct {
2024-01-16 16:11:04 -08: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-14 22:16:58 -07:00
}
2022-06-23 12:48:45 -07:00
func ( * InitPacketType ) GetType () string {
return InitPacketStr
2022-06-14 22:16:58 -07:00
}
2022-10-25 12:31:07 -07:00
func ( pk * InitPacketType ) GetResponseId () string {
return pk . RespId
}
func ( pk * InitPacketType ) GetResponseDone () bool {
return true
}
2022-06-23 12:48:45 -07:00
func MakeInitPacket () * InitPacketType {
return & InitPacketType { Type : InitPacketStr }
2022-06-14 22:16:58 -07:00
}
2022-06-10 00:35:24 -07:00
type DonePacketType struct {
Type string `json:"type"`
}
func ( * DonePacketType ) GetType () string {
return DonePacketStr
}
func MakeDonePacket () * DonePacketType {
return & DonePacketType { Type : DonePacketStr }
}
2022-11-27 13:47:18 -08: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-10 21:37:21 -07:00
type CmdDonePacketType struct {
2022-11-27 13:47:18 -08: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"`
2022-06-10 00:35:24 -07:00
}
2022-06-10 21:37:21 -07:00
func ( * CmdDonePacketType ) GetType () string {
return CmdDonePacketStr
2022-06-10 00:35:24 -07:00
}
2022-06-27 12:03:47 -07:00
func ( p * CmdDonePacketType ) GetCK () base . CommandKey {
return p . CK
}
2022-07-05 23:14:14 -07:00
func MakeCmdDonePacket ( ck base . CommandKey ) * CmdDonePacketType {
return & CmdDonePacketType { Type : CmdDonePacketStr , CK : ck }
2022-06-10 21:37:21 -07:00
}
type CmdStartPacketType struct {
2022-06-27 12:03:47 -07:00
Type string `json:"type"`
2023-05-08 18:00:46 -07:00
RespId string `json:"respid,omitempty"`
2022-06-27 12:03:47 -07:00
Ts int64 `json:"ts"`
CK base . CommandKey `json:"ck"`
2023-05-08 18:00:46 -07:00
Pid int `json:"pid,omitempty"`
MShellPid int `json:"mshellpid,omitempty"`
2022-06-10 21:37:21 -07:00
}
func ( * CmdStartPacketType ) GetType () string {
return CmdStartPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * CmdStartPacketType ) GetResponseId () string {
return p . RespId
2022-06-27 12:03:47 -07:00
}
2022-07-05 23:14:14 -07:00
func ( * CmdStartPacketType ) GetResponseDone () bool {
return true
}
func MakeCmdStartPacket ( reqId string ) * CmdStartPacketType {
return & CmdStartPacketType { Type : CmdStartPacketStr , RespId : reqId }
2022-06-10 00:35:24 -07:00
}
2022-07-06 14:06:58 -07:00
type TermOpts struct {
2022-08-19 15:28:32 -07:00
Rows int `json:"rows"`
Cols int `json:"cols"`
Term string `json:"term"`
MaxPtySize int64 `json:"maxptysize,omitempty"`
2023-12-12 14:24:09 -08:00
FlexRows bool `json:"flexrows,omitempty"`
2022-06-23 10:16:54 -07:00
}
type RemoteFd struct {
2022-06-28 21:57:30 -07: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 10:16:54 -07:00
}
2022-06-10 00:35:24 -07:00
type RunPacketType struct {
2022-10-16 23:46:59 -07:00
Type string `json:"type"`
ReqId string `json:"reqid"`
CK base . CommandKey `json:"ck"`
2024-01-16 16:11:04 -08:00
ShellType string `json:"shelltype"` // new in v0.6.0 (either "bash" or "zsh") (set by remote.go)
2022-10-16 23:46:59 -07:00
Command string `json:"command"`
2022-11-27 13:47:18 -08:00
State * ShellState `json:"state,omitempty"`
StateDiff * ShellStateDiff `json:"statediff,omitempty"`
2022-10-16 23:46:59 -07: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 14:45:31 -07:00
ReturnState bool `json:"returnstate,omitempty"`
2022-06-10 00:35:24 -07:00
}
2022-06-20 17:51:28 -07:00
func ( * RunPacketType ) GetType () string {
2022-06-10 00:35:24 -07:00
return RunPacketStr
}
2022-07-05 16:53:31 -07:00
func ( p * RunPacketType ) GetReqId () string {
return p . ReqId
2022-06-27 12:03:47 -07:00
}
2022-06-14 14:17:36 -07:00
func MakeRunPacket () * RunPacketType {
return & RunPacketType { Type : RunPacketStr }
}
2023-05-08 18:00:46 -07:00
type OpenAIUsageType struct {
PromptTokens int `json:"prompt_tokens,omitempty"`
CompletionTokens int `json:"completion_tokens,omitempty"`
TotalTokens int `json:"total_tokens,omitempty"`
}
2024-01-11 17:34:23 -08: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-08 18:00:46 -07: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 00:35:24 -07:00
type BarePacketType struct {
Type string `json:"type"`
}
2022-07-05 17:45:46 -07:00
type CmdErrorPacketType struct {
Type string `json:"type"`
CK base . CommandKey `json:"ck"`
Error string `json:"error"`
2022-06-10 00:35:24 -07:00
}
2022-07-05 17:45:46 -07:00
func ( * CmdErrorPacketType ) GetType () string {
return CmdErrorPacketStr
2022-06-10 00:35:24 -07:00
}
2022-07-05 17:45:46 -07:00
func ( p * CmdErrorPacketType ) GetCK () base . CommandKey {
return p . CK
}
func ( p * CmdErrorPacketType ) String () string {
2022-07-05 16:53:31 -07:00
return fmt . Sprintf ( "error[%s]" , p . Error )
2022-06-28 22:05:47 -07:00
}
2022-07-05 17:45:46 -07:00
func MakeCmdErrorPacket ( ck base . CommandKey , err error ) * CmdErrorPacketType {
return & CmdErrorPacketType { Type : CmdErrorPacketStr , CK : ck , Error : err . Error ()}
2022-06-10 00:35:24 -07:00
}
2023-08-31 22:03:38 -07: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-11 17:34:23 -08: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-15 22:43:59 -08: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 00:35:24 -07:00
type PacketType interface {
GetType () string
}
2022-06-24 23:42:00 -07:00
func AsString ( pk PacketType ) string {
2022-08-31 12:45:59 -07:00
if pk == nil {
return "nil"
}
2022-06-24 23:42:00 -07:00
if s , ok := pk .( fmt . Stringer ); ok {
return s . String ()
}
return fmt . Sprintf ( "%s[]" , pk . GetType ())
}
2022-06-23 10:16:54 -07:00
type RpcPacketType interface {
GetType () string
2022-07-05 16:53:31 -07:00
GetReqId () string
}
type RpcResponsePacketType interface {
GetType () string
GetResponseId () string
2022-07-05 23:14:14 -07:00
GetResponseDone () bool
2022-06-23 10:16:54 -07:00
}
2022-06-27 12:03:47 -07:00
type CommandPacketType interface {
GetType () string
GetCK () base . CommandKey
}
2022-06-28 15:04:08 -07:00
func AsExtType ( pk PacketType ) string {
if rpcPacket , ok := pk .( RpcPacketType ); ok {
2022-07-05 16:53:31 -07:00
return fmt . Sprintf ( "%s[%s]" , rpcPacket . GetType (), rpcPacket . GetReqId ())
2022-06-28 15:04:08 -07:00
} else if cmdPacket , ok := pk .( CommandPacketType ); ok {
return fmt . Sprintf ( "%s[%s]" , cmdPacket . GetType (), cmdPacket . GetCK ())
} else {
return pk . GetType ()
}
}
2022-06-10 00:35:24 -07: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 14:17:36 -07:00
pk , err := MakePacket ( bareCmd . Type )
if err != nil {
return nil , err
2022-06-10 00:35:24 -07:00
}
2022-06-14 14:17:36 -07:00
err = json . Unmarshal ( jsonBuf , pk )
if err != nil {
2022-11-22 22:59:29 -08:00
return nil , fmt . Errorf ( "unmarshaling %q packet: %v" , bareCmd . Type , err )
2022-06-10 00:35:24 -07:00
}
2022-06-14 14:17:36 -07:00
return pk , nil
2022-06-10 00:35:24 -07:00
}
2022-11-27 13:47:18 -08: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-05 22:26:13 -08:00
return fmt . Sprintf ( "SendPacket write-error packet[%s]: %v" , e . PacketType , e . Err )
2022-11-27 13:47:18 -08:00
} else {
return e . Err . Error ()
}
}
2023-05-08 18:00:46 -07:00
func MarshalPacket ( packet PacketType ) ([] byte , error ) {
2022-06-10 00:35:24 -07:00
if packet == nil {
2023-05-08 18:00:46 -07:00
return nil , fmt . Errorf ( "invalid nil packet" )
2022-06-10 00:35:24 -07:00
}
2022-06-15 16:29:39 -07:00
jsonBytes , err := json . Marshal ( packet )
2022-06-10 00:35:24 -07:00
if err != nil {
2023-05-08 18:00:46 -07:00
return nil , & SendError { IsMarshalError : true , PacketType : packet . GetType (), Err : err }
2022-06-10 00:35:24 -07:00
}
2022-06-15 16:29:39 -07:00
var outBuf bytes . Buffer
outBuf . WriteByte ( '\n' )
outBuf . WriteString ( fmt . Sprintf ( "##%d" , len ( jsonBytes )))
outBuf . Write ( jsonBytes )
outBuf . WriteByte ( '\n' )
2023-05-08 18:00:46 -07: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 13:25:09 -07:00
if GlobalDebug {
2022-12-05 22:26:13 -08:00
base . Logf ( "SEND> %s\n" , AsString ( packet ))
2022-06-24 13:25:09 -07:00
}
2022-06-29 14:29:38 -07:00
_ , err = w . Write ( outBytes )
2022-06-10 00:35:24 -07:00
if err != nil {
2022-11-27 13:47:18 -08:00
return & SendError { IsWriteError : true , PacketType : packet . GetType (), Err : err }
2022-06-10 00:35:24 -07:00
}
return nil
}
2022-07-05 17:45:46 -07:00
func SendCmdError ( w io . Writer , ck base . CommandKey , err error ) error {
return SendPacket ( w , MakeCmdErrorPacket ( ck , err ))
2022-06-10 00:35:24 -07:00
}
2022-06-10 21:37:21 -07:00
type PacketSender struct {
2022-11-27 13:47:18 -08:00
Lock * sync . Mutex
SendCh chan PacketType
Done bool
DoneCh chan bool
ErrHandler func ( * PacketSender , PacketType , error )
2022-12-05 22:26:13 -08:00
ExitErr error
2022-06-10 21:37:21 -07:00
}
2022-11-27 13:47:18 -08:00
func MakePacketSender ( output io . Writer , errHandler func ( * PacketSender , PacketType , error )) * PacketSender {
2022-06-10 21:37:21 -07:00
sender := & PacketSender {
2022-11-27 13:47:18 -08:00
Lock : & sync . Mutex {},
SendCh : make ( chan PacketType , PacketSenderQueueSize ),
DoneCh : make ( chan bool ),
ErrHandler : errHandler ,
2022-06-10 21:37:21 -07:00
}
go func () {
2022-06-28 15:04:08 -07:00
defer close ( sender . DoneCh )
defer sender . Close ()
2022-06-10 21:37:21 -07:00
for pk := range sender . SendCh {
err := SendPacket ( output , pk )
if err != nil {
2022-11-27 13:47:18 -08: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-05 22:26:13 -08:00
sender . Lock . Lock ()
sender . ExitErr = err
sender . Lock . Unlock ()
2022-06-10 21:37:21 -07:00
return
}
}
}()
return sender
}
2022-11-27 13:47:18 -08: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-01 17:37:37 -07: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-28 15:04:08 -07:00
func ( sender * PacketSender ) Close () {
sender . Lock . Lock ()
defer sender . Lock . Unlock ()
if sender . Done {
return
}
sender . Done = true
2022-06-10 21:37:21 -07:00
close ( sender . SendCh )
}
2022-12-05 22:26:13 -08:00
// returns ExitErr if set
func ( sender * PacketSender ) WaitForDone () error {
2022-06-10 21:37:21 -07:00
<- sender . DoneCh
2022-12-05 22:26:13 -08:00
sender . Lock . Lock ()
defer sender . Lock . Unlock ()
return sender . ExitErr
2022-06-10 21:37:21 -07:00
}
2022-12-05 22:26:13 -08: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-10 21:37:21 -07: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 14:35:27 -07: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-10 21:37:21 -07:00
func ( sender * PacketSender ) SendPacket ( pk PacketType ) error {
err := sender . checkStatus ()
if err != nil {
return err
}
sender . SendCh <- pk
return nil
}
2022-07-05 17:45:46 -07:00
func ( sender * PacketSender ) SendCmdError ( ck base . CommandKey , err error ) error {
return sender . SendPacket ( MakeCmdErrorPacket ( ck , err ))
2022-06-10 21:37:21 -07:00
}
2022-07-05 17:45:46 -07:00
func ( sender * PacketSender ) SendErrorResponse ( reqId string , err error ) error {
pk := MakeErrorResponsePacket ( reqId , err )
return sender . SendPacket ( pk )
}
func ( sender * PacketSender ) SendResponse ( reqId string , data interface {}) error {
pk := MakeResponsePacket ( reqId , data )
return sender . SendPacket ( pk )
2022-06-28 19:01:33 -07:00
}
2022-11-27 13:47:18 -08:00
func ( sender * PacketSender ) SendMessageFmt ( fmtStr string , args ... interface {}) error {
2022-06-14 22:16:58 -07:00
return sender . SendPacket ( MakeMessagePacket ( fmt . Sprintf ( fmtStr , args ... )))
}
2022-06-28 19:01:33 -07:00
type UnknownPacketReporter interface {
UnknownPacket ( pk PacketType )
2022-06-16 01:10:56 -07:00
}
2022-06-28 19:01:33 -07:00
type DefaultUPR struct {}
func ( DefaultUPR ) UnknownPacket ( pk PacketType ) {
2022-07-05 17:45:46 -07:00
if pk . GetType () == CmdErrorPacketStr {
errPacket := pk .( * CmdErrorPacketType )
2022-06-28 19:01:33 -07:00
// at this point, just send the error packet to stderr rather than try to do something special
fmt . Fprintf ( os . Stderr , "[error] %s\n" , errPacket . Error )
} else if pk . GetType () == RawPacketStr {
rawPacket := pk .( * RawPacketType )
fmt . Fprintf ( os . Stderr , "%s\n" , rawPacket . Data )
2022-07-01 17:37:37 -07:00
} else if pk . GetType () == CmdStartPacketStr {
return // do nothing
2022-06-28 19:01:33 -07:00
} else {
fmt . Fprintf ( os . Stderr , "[error] invalid packet received '%s'" , AsExtType ( pk ))
}
2022-09-06 12:57:54 -07:00
}
2022-06-28 19:01:33 -07:00
2022-09-06 12:57:54 -07:00
type MessageUPR struct {
CK base . CommandKey
Sender * PacketSender
}
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 01:10:56 -07:00
}
2022-06-28 21:57:30 -07: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 14:29:38 -07:00
if len ( runPacket . RunData ) == 0 {
return true , runPacket
}
2022-06-28 21:57:30 -07: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
}