mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-23 16:58:27 +01:00
webshare selected line, sync webupdate for screen:new, fix line resolver for hidden items
This commit is contained in:
parent
652c820844
commit
274697039a
@ -7,6 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
@ -1641,6 +1642,10 @@ func SessionOpenCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func makeExternLink(urlStr string) string {
|
||||
return fmt.Sprintf(`https://extern?%s`, url.QueryEscape(urlStr))
|
||||
}
|
||||
|
||||
func ScreenWebShareCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Screen)
|
||||
if err != nil {
|
||||
@ -1655,6 +1660,7 @@ func ScreenWebShareCommand(ctx context.Context, pk *scpacket.FeCommandPacketType
|
||||
return nil, err
|
||||
}
|
||||
var infoMsg string
|
||||
var infoWebShareLink bool
|
||||
if shouldShare {
|
||||
viewKeyBytes := make([]byte, 9)
|
||||
_, err = rand.Read(viewKeyBytes)
|
||||
@ -1663,11 +1669,24 @@ func ScreenWebShareCommand(ctx context.Context, pk *scpacket.FeCommandPacketType
|
||||
}
|
||||
viewKey := base64.RawURLEncoding.EncodeToString(viewKeyBytes)
|
||||
webShareOpts := sstore.ScreenWebShareOpts{ShareName: shareName, ViewKey: viewKey}
|
||||
screen, err := sstore.GetScreenById(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get screen: %v", err)
|
||||
}
|
||||
err = sstore.CanScreenWebShare(screen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webUpdate := pcloud.MakeScreenNewUpdate(screen, webShareOpts)
|
||||
err = pcloud.DoSyncWebUpdate(webUpdate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error starting webshare, error contacting prompt cloud server: %v", err)
|
||||
}
|
||||
err = sstore.ScreenWebShareStart(ctx, ids.ScreenId, webShareOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot web-share screen: %v", err)
|
||||
return nil, fmt.Errorf("cannot webshare screen, error updating: %v", err)
|
||||
}
|
||||
infoMsg = fmt.Sprintf("screen is now shared to the web at %s", GetWebShareUrl(ids.ScreenId, viewKey))
|
||||
infoWebShareLink = true
|
||||
} else {
|
||||
err = sstore.ScreenWebShareStop(ctx, ids.ScreenId)
|
||||
if err != nil {
|
||||
@ -1682,7 +1701,8 @@ func ScreenWebShareCommand(ctx context.Context, pk *scpacket.FeCommandPacketType
|
||||
update := sstore.ModelUpdate{
|
||||
Screens: []*sstore.ScreenType{screen},
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoMsg: infoMsg,
|
||||
InfoMsg: infoMsg,
|
||||
WebShareLink: infoWebShareLink,
|
||||
},
|
||||
}
|
||||
return update, nil
|
||||
|
@ -186,6 +186,22 @@ func defaultError(err error, estr string) error {
|
||||
return errors.New(estr)
|
||||
}
|
||||
|
||||
func MakeScreenNewUpdate(screen *sstore.ScreenType, webShareOpts sstore.ScreenWebShareOpts) *WebShareUpdateType {
|
||||
rtn := &WebShareUpdateType{
|
||||
ScreenId: screen.ScreenId,
|
||||
UpdateId: -1,
|
||||
UpdateType: sstore.UpdateType_ScreenNew,
|
||||
UpdateTs: time.Now().UnixMilli(),
|
||||
}
|
||||
rtn.Screen = &WebShareScreenType{
|
||||
ScreenId: screen.ScreenId,
|
||||
SelectedLine: int(screen.SelectedLine),
|
||||
ShareName: webShareOpts.ShareName,
|
||||
ViewKey: webShareOpts.ViewKey,
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
|
||||
func makeWebShareUpdate(ctx context.Context, update *sstore.ScreenUpdateType) (*WebShareUpdateType, error) {
|
||||
rtn := &WebShareUpdateType{
|
||||
ScreenId: update.ScreenId,
|
||||
@ -208,15 +224,19 @@ func makeWebShareUpdate(ctx context.Context, update *sstore.ScreenUpdateType) (*
|
||||
case sstore.UpdateType_ScreenDel:
|
||||
break
|
||||
|
||||
case sstore.UpdateType_ScreenName:
|
||||
case sstore.UpdateType_ScreenName, sstore.UpdateType_ScreenSelectedLine:
|
||||
screen, err := sstore.GetScreenById(ctx, update.ScreenId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting screen: %v", err)
|
||||
}
|
||||
if screen == nil || screen.WebShareOpts == nil || screen.WebShareOpts.ShareName == "" {
|
||||
return nil, fmt.Errorf("invalid screen sharename (makeWebScreenUpdate)")
|
||||
if screen == nil || screen.WebShareOpts == nil {
|
||||
return nil, fmt.Errorf("invalid screen, not webshared (makeWebScreenUpdate)")
|
||||
}
|
||||
if update.UpdateType == sstore.UpdateType_ScreenName {
|
||||
rtn.SVal = screen.WebShareOpts.ShareName
|
||||
} else if update.UpdateType == sstore.UpdateType_ScreenSelectedLine {
|
||||
rtn.IVal = int64(screen.SelectedLine)
|
||||
}
|
||||
rtn.SVal = screen.WebShareOpts.ShareName
|
||||
|
||||
case sstore.UpdateType_LineNew:
|
||||
line, cmd, err := sstore.GetLineCmdByLineId(ctx, update.ScreenId, update.LineId)
|
||||
@ -332,7 +352,7 @@ type webShareResponseType struct {
|
||||
Data []*WebShareUpdateResponseType `json:"data"`
|
||||
}
|
||||
|
||||
func DoWebScreenUpdates(authInfo AuthInfo, updateArr []*sstore.ScreenUpdateType) error {
|
||||
func convertUpdates(updateArr []*sstore.ScreenUpdateType) []*WebShareUpdateType {
|
||||
var webUpdates []*WebShareUpdateType
|
||||
for _, update := range updateArr {
|
||||
webUpdate, err := makeWebShareUpdate(context.Background(), update)
|
||||
@ -352,9 +372,43 @@ func DoWebScreenUpdates(authInfo AuthInfo, updateArr []*sstore.ScreenUpdateType)
|
||||
}
|
||||
webUpdates = append(webUpdates, webUpdate)
|
||||
}
|
||||
return webUpdates
|
||||
}
|
||||
|
||||
func DoSyncWebUpdate(webUpdate *WebShareUpdateType) error {
|
||||
authInfo, err := getAuthInfo(context.Background())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get authinfo for request: %v", err)
|
||||
}
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), PCloudDefaultTimeout)
|
||||
defer cancelFn()
|
||||
req, err := makeAuthPostReq(ctx, WebShareUpdateUrl, authInfo, []*WebShareUpdateType{webUpdate})
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create auth-post-req for %s: %v", WebShareUpdateUrl, err)
|
||||
}
|
||||
var resp webShareResponseType
|
||||
_, err = doRequest(req, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.Data) == 0 {
|
||||
return fmt.Errorf("invalid response received from server")
|
||||
}
|
||||
urt := resp.Data[0]
|
||||
if urt.Error != "" {
|
||||
return errors.New(urt.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DoWebUpdates(webUpdates []*WebShareUpdateType) error {
|
||||
if len(webUpdates) == 0 {
|
||||
return nil
|
||||
}
|
||||
authInfo, err := getAuthInfo(context.Background())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get authinfo for request: %v", err)
|
||||
}
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), PCloudDefaultTimeout)
|
||||
defer cancelFn()
|
||||
req, err := makeAuthPostReq(ctx, WebShareUpdateUrl, authInfo, webUpdates)
|
||||
@ -377,7 +431,9 @@ func DoWebScreenUpdates(authInfo AuthInfo, updateArr []*sstore.ScreenUpdateType)
|
||||
if resp == nil {
|
||||
resp = &WebShareUpdateResponseType{Success: false, Error: "resp not found"}
|
||||
}
|
||||
log.Printf("[pcloud] updateid:%d, type:%s %s/%s success:%v err:%v\n", update.UpdateId, update.UpdateType, update.ScreenId, update.LineId, resp.Success, resp.Error)
|
||||
if resp.Error != "" {
|
||||
log.Printf("[pcloud] error updateid:%d, type:%s %s/%s err:%v\n", update.UpdateId, update.UpdateType, update.ScreenId, update.LineId, resp.Error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -447,8 +503,8 @@ func runWebShareUpdateWriter() {
|
||||
continue
|
||||
}
|
||||
numErrors = 0
|
||||
authInfo, err := getAuthInfo(context.Background())
|
||||
err = DoWebScreenUpdates(authInfo, updateArr)
|
||||
webUpdates := convertUpdates(updateArr)
|
||||
err = DoWebUpdates(webUpdates)
|
||||
if err != nil {
|
||||
numSendErrors++
|
||||
backoffTime := computeBackoff(numSendErrors)
|
||||
|
@ -34,6 +34,7 @@ type WebShareUpdateType struct {
|
||||
Cmd *WebShareCmdType `json:"cmd,omitempty"`
|
||||
PtyData *WebSharePtyData `json:"ptydata,omitempty"`
|
||||
SVal string `json:"sval,omitempty"`
|
||||
IVal int64 `json:"ival,omitempty"`
|
||||
BVal bool `json:"bval,omitempty"`
|
||||
DoneInfo *sstore.CmdDoneInfo `json:"doneinfo,omitempty"`
|
||||
TermOpts *sstore.TermOpts `json:"termopts,omitempty"`
|
||||
@ -59,9 +60,10 @@ type WebShareRemote struct {
|
||||
}
|
||||
|
||||
type WebShareScreenType struct {
|
||||
ScreenId string `json:"screenid"`
|
||||
ShareName string `json:"sharename"`
|
||||
ViewKey string `json:"viewkey"`
|
||||
ScreenId string `json:"screenid"`
|
||||
ShareName string `json:"sharename"`
|
||||
ViewKey string `json:"viewkey"`
|
||||
SelectedLine int `json:"selectedline"`
|
||||
}
|
||||
|
||||
func webRemoteFromRemote(rptr sstore.RemotePtrType, r *sstore.RemoteType) *WebShareRemote {
|
||||
@ -91,7 +93,7 @@ func webScreenFromScreen(s *sstore.ScreenType) (*WebShareScreenType, error) {
|
||||
} else {
|
||||
shareName = s.Name
|
||||
}
|
||||
return &WebShareScreenType{ScreenId: s.ScreenId, ShareName: shareName, ViewKey: s.WebShareOpts.ViewKey}, nil
|
||||
return &WebShareScreenType{ScreenId: s.ScreenId, ShareName: shareName, ViewKey: s.WebShareOpts.ViewKey, SelectedLine: int(s.SelectedLine)}, nil
|
||||
}
|
||||
|
||||
type WebShareLineType struct {
|
||||
|
@ -1114,6 +1114,7 @@ func PurgeScreen(ctx context.Context, screenId string, sessionDel bool) (UpdateP
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM line WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
insertScreenDelUpdate(tx, screenId)
|
||||
return nil
|
||||
})
|
||||
if txErr != nil {
|
||||
@ -1715,6 +1716,9 @@ func UpdateScreen(ctx context.Context, screenId string, editMap map[string]inter
|
||||
if sline, found := editMap[ScreenField_SelectedLine]; found {
|
||||
query = `UPDATE screen SET selectedline = ? WHERE screenid = ?`
|
||||
tx.Exec(query, sline, screenId)
|
||||
if isWebShare(tx, screenId) {
|
||||
insertScreenUpdate(tx, screenId, UpdateType_ScreenSelectedLine)
|
||||
}
|
||||
}
|
||||
if focusType, found := editMap[ScreenField_Focus]; found {
|
||||
query = `UPDATE screen SET focustype = ? WHERE screenid = ?`
|
||||
@ -1743,7 +1747,7 @@ func UpdateScreen(ctx context.Context, screenId string, editMap map[string]inter
|
||||
func GetLineResolveItems(ctx context.Context, screenId string) ([]ResolveItem, error) {
|
||||
var rtn []ResolveItem
|
||||
txErr := WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT lineid as id, linenum as num FROM line WHERE screenid = ? ORDER BY linenum`
|
||||
query := `SELECT lineid as id, linenum as num, archived as hidden FROM line WHERE screenid = ? ORDER BY linenum`
|
||||
tx.Select(&rtn, query, screenId)
|
||||
return nil
|
||||
})
|
||||
@ -2411,6 +2415,19 @@ func PurgeHistoryByIds(ctx context.Context, historyIds []string) ([]*HistoryItem
|
||||
})
|
||||
}
|
||||
|
||||
func CanScreenWebShare(screen *ScreenType) error {
|
||||
if screen == nil {
|
||||
return fmt.Errorf("cannot share screen, not found")
|
||||
}
|
||||
if screen.ShareMode == ShareModeWeb {
|
||||
return fmt.Errorf("screen is already shared to web")
|
||||
}
|
||||
if screen.ShareMode != ShareModeLocal {
|
||||
return fmt.Errorf("screen cannot be shared, invalid current share mode %q (must be local)", screen.ShareMode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ScreenWebShareStart(ctx context.Context, screenId string, shareOpts ScreenWebShareOpts) error {
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `SELECT screenid FROM screen WHERE screenid = ?`
|
||||
@ -2424,17 +2441,9 @@ func ScreenWebShareStart(ctx context.Context, screenId string, shareOpts ScreenW
|
||||
if shareMode != ShareModeLocal {
|
||||
return fmt.Errorf("screen cannot be shared, invalid current share mode %q (must be local)", shareMode)
|
||||
}
|
||||
nowTs := time.Now().UnixMilli()
|
||||
query = `UPDATE screen SET sharemode = ?, webshareopts = ? WHERE screenid = ?`
|
||||
tx.Exec(query, ShareModeWeb, quickJson(shareOpts), screenId)
|
||||
insertScreenUpdate(tx, screenId, UpdateType_ScreenNew)
|
||||
query = `INSERT INTO screenupdate (screenid, lineid, updatetype, updatets)
|
||||
SELECT screenid, lineid, ?, ? FROM line WHERE screenid = ? AND NOT archived ORDER BY linenum`
|
||||
tx.Exec(query, UpdateType_LineNew, nowTs, screenId)
|
||||
query = `INSERT INTO screenupdate (screenid, lineid, updatetype, updatets)
|
||||
SELECT c.screenid, l.lineid, ?, ? FROM cmd c, line l WHERE c.screenid = ? AND l.cmdid = c.cmdid AND NOT l.archived`
|
||||
tx.Exec(query, UpdateType_PtyPos, nowTs, screenId)
|
||||
NotifyUpdateWriter()
|
||||
insertScreenNewUpdate(tx, screenId)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -2451,11 +2460,7 @@ func ScreenWebShareStop(ctx context.Context, screenId string) error {
|
||||
}
|
||||
query = `UPDATE screen SET sharemode = ?, webshareopts = ? WHERE screenid = ?`
|
||||
tx.Exec(query, ShareModeLocal, "null", screenId)
|
||||
query = `DELETE FROM screenupdate WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM webptypos WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
insertScreenUpdate(tx, screenId, UpdateType_ScreenDel)
|
||||
insertScreenDelUpdate(tx, screenId)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@ -2469,11 +2474,31 @@ func insertScreenUpdate(tx *TxWrap, screenId string, updateType string) {
|
||||
tx.SetErr(errors.New("invalid screen-update, screenid is empty"))
|
||||
return
|
||||
}
|
||||
nowTs := time.Now().UnixMilli()
|
||||
query := `INSERT INTO screenupdate (screenid, lineid, updatetype, updatets) VALUES (?, ?, ?, ?)`
|
||||
tx.Exec(query, screenId, "", updateType, time.Now().UnixMilli())
|
||||
tx.Exec(query, screenId, "", updateType, nowTs)
|
||||
NotifyUpdateWriter()
|
||||
}
|
||||
|
||||
func insertScreenNewUpdate(tx *TxWrap, screenId string) {
|
||||
nowTs := time.Now().UnixMilli()
|
||||
query := `INSERT INTO screenupdate (screenid, lineid, updatetype, updatets)
|
||||
SELECT screenid, lineid, ?, ? FROM line WHERE screenid = ? AND NOT archived ORDER BY linenum`
|
||||
tx.Exec(query, UpdateType_LineNew, nowTs, screenId)
|
||||
query = `INSERT INTO screenupdate (screenid, lineid, updatetype, updatets)
|
||||
SELECT c.screenid, l.lineid, ?, ? FROM cmd c, line l WHERE c.screenid = ? AND l.cmdid = c.cmdid AND NOT l.archived`
|
||||
tx.Exec(query, UpdateType_PtyPos, nowTs, screenId)
|
||||
NotifyUpdateWriter()
|
||||
}
|
||||
|
||||
func insertScreenDelUpdate(tx *TxWrap, screenId string) {
|
||||
query := `DELETE FROM screenupdate WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
query = `DELETE FROM webptypos WHERE screenid = ?`
|
||||
tx.Exec(query, screenId)
|
||||
insertScreenUpdate(tx, screenId, UpdateType_ScreenDel)
|
||||
}
|
||||
|
||||
func insertScreenLineUpdate(tx *TxWrap, screenId string, lineId string, updateType string) {
|
||||
if screenId == "" {
|
||||
tx.SetErr(errors.New("invalid screen-update, screenid is empty"))
|
||||
@ -2521,6 +2546,9 @@ func GetScreenUpdates(ctx context.Context, maxNum int) ([]*ScreenUpdateType, err
|
||||
}
|
||||
|
||||
func RemoveScreenUpdate(ctx context.Context, updateId int64) error {
|
||||
if updateId < 0 {
|
||||
return nil // in-memory updates (not from DB)
|
||||
}
|
||||
return WithTx(ctx, func(tx *TxWrap) error {
|
||||
query := `DELETE FROM screenupdate WHERE updateid = ?`
|
||||
tx.Exec(query, updateId)
|
||||
|
@ -81,17 +81,18 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
UpdateType_ScreenNew = "screen:new"
|
||||
UpdateType_ScreenDel = "screen:del"
|
||||
UpdateType_ScreenName = "screen:sharename"
|
||||
UpdateType_LineNew = "line:new"
|
||||
UpdateType_LineDel = "line:del"
|
||||
UpdateType_LineRenderer = "line:renderer"
|
||||
UpdateType_CmdStatus = "cmd:status"
|
||||
UpdateType_CmdTermOpts = "cmd:termopts"
|
||||
UpdateType_CmdDoneInfo = "cmd:doneinfo"
|
||||
UpdateType_CmdRtnState = "cmd:rtnstate"
|
||||
UpdateType_PtyPos = "pty:pos"
|
||||
UpdateType_ScreenNew = "screen:new"
|
||||
UpdateType_ScreenDel = "screen:del"
|
||||
UpdateType_ScreenSelectedLine = "screen:selectedline"
|
||||
UpdateType_ScreenName = "screen:sharename"
|
||||
UpdateType_LineNew = "line:new"
|
||||
UpdateType_LineDel = "line:del"
|
||||
UpdateType_LineRenderer = "line:renderer"
|
||||
UpdateType_CmdStatus = "cmd:status"
|
||||
UpdateType_CmdTermOpts = "cmd:termopts"
|
||||
UpdateType_CmdDoneInfo = "cmd:doneinfo"
|
||||
UpdateType_CmdRtnState = "cmd:rtnstate"
|
||||
UpdateType_PtyPos = "pty:pos"
|
||||
)
|
||||
|
||||
const MaxTzNameLen = 50
|
||||
|
@ -100,6 +100,8 @@ type InfoMsgType struct {
|
||||
InfoTitle string `json:"infotitle"`
|
||||
InfoError string `json:"infoerror,omitempty"`
|
||||
InfoMsg string `json:"infomsg,omitempty"`
|
||||
InfoMsgHtml bool `json:"infomsghtml,omitempty"`
|
||||
WebShareLink bool `json:"websharelink,omitempty"`
|
||||
InfoComps []string `json:"infocomps,omitempty"`
|
||||
InfoCompsMore bool `json:"infocompssmore,omitempty"`
|
||||
InfoLines []string `json:"infolines,omitempty"`
|
||||
|
Loading…
Reference in New Issue
Block a user