- 替换 sqlite 驱动为 github.com/glebarez/sqlite

- 修复数据库锁定的问题
- 修复部分代码不完善的问题
- 修复策略显示不完整的问题
- 修复编辑文件换行符的问题
- 优化guacd连接
This commit is contained in:
dushixiang
2022-03-29 22:31:08 +08:00
parent 03114b486c
commit d393d28e5e
42 changed files with 435 additions and 567 deletions

View File

@ -168,10 +168,7 @@ func (api AccountApi) LoginWithTotpEndpoint(c echo.Context) error {
func (api AccountApi) LogoutEndpoint(c echo.Context) error {
token := GetToken(c)
err := service.UserService.LogoutByToken(token)
if err != nil {
return err
}
service.UserService.Logout(token)
return Success(c, nil)
}
@ -317,6 +314,10 @@ func (api AccountApi) AccountAssetEndpoint(c echo.Context) error {
if err != nil {
return err
}
for i := range items {
items[i].IP = ""
items[i].Port = 0
}
return Success(c, Map{
"total": total,

View File

@ -28,7 +28,7 @@ func (assetApi AssetApi) AssetCreateEndpoint(c echo.Context) error {
account, _ := GetCurrentAccount(c)
m["owner"] = account.ID
if _, err := service.AssetService.Create(m); err != nil {
if _, err := service.AssetService.Create(context.TODO(), m); err != nil {
return err
}

View File

@ -25,7 +25,7 @@ func (api BackupApi) BackupExportEndpoint(c echo.Context) error {
if err != nil {
return err
}
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=next-terminal_backup_%s.json", time.Now().Format("20060102150405")))
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=backup_%s.json", time.Now().Format("20060102150405")))
return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(jsonBytes))
}

View File

@ -64,7 +64,7 @@ func (api CredentialApi) CredentialCreateEndpoint(c echo.Context) error {
item.Encrypted = true
if err := service.CredentialService.Create(&item); err != nil {
if err := service.CredentialService.Create(context.TODO(), &item); err != nil {
return err
}

View File

@ -159,6 +159,7 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
guacamoleHandler := NewGuacamoleHandler(ws, guacdTunnel)
guacamoleHandler.Start()
defer guacamoleHandler.Stop()
for {
_, message, err := ws.ReadMessage()
@ -168,7 +169,6 @@ func (api GuacamoleApi) Guacamole(c echo.Context) error {
_ = guacdTunnel.Close()
service.SessionService.CloseSessionById(sessionId, Normal, "用户正常退出")
guacamoleHandler.Stop()
return nil
}
_, err = guacdTunnel.WriteAndFlush(message)
@ -193,7 +193,7 @@ func (api GuacamoleApi) setAssetConfig(attributes map[string]string, s model.Ses
}
realPath := path.Join(service.StorageService.GetBaseDrivePath(), storageId)
configuration.SetParameter(guacd.EnableDrive, "true")
configuration.SetParameter(guacd.DriveName, "Next Terminal Filesystem")
configuration.SetParameter(guacd.DriveName, "Filesystem")
configuration.SetParameter(guacd.DrivePath, realPath)
log.Debugf("[%v] 会话 %v:%v 映射目录地址为 %v", s.ID, s.IP, s.Port, realPath)
} else {
@ -258,6 +258,7 @@ func (api GuacamoleApi) GuacamoleMonitor(c echo.Context) error {
guacamoleHandler := NewGuacamoleHandler(ws, guacdTunnel)
guacamoleHandler.Start()
defer guacamoleHandler.Stop()
for {
_, message, err := ws.ReadMessage()
@ -269,7 +270,6 @@ func (api GuacamoleApi) GuacamoleMonitor(c echo.Context) error {
observerId := nextSession.ID
forObsSession.Observer.Del <- observerId
log.Debugf("[%v:%v] 观察者[%v]退出会话", sessionId, connectionId, observerId)
guacamoleHandler.Stop()
return nil
}
_, err = guacdTunnel.WriteAndFlush(message)

View File

@ -2,7 +2,6 @@ package api
import (
"context"
"time"
"next-terminal/server/guacd"
"next-terminal/server/log"
@ -12,73 +11,47 @@ import (
)
type GuacamoleHandler struct {
ws *websocket.Conn
tunnel *guacd.Tunnel
ctx context.Context
cancel context.CancelFunc
dataChan chan []byte
tick *time.Ticker
ws *websocket.Conn
tunnel *guacd.Tunnel
ctx context.Context
cancel context.CancelFunc
}
func NewGuacamoleHandler(ws *websocket.Conn, tunnel *guacd.Tunnel) *GuacamoleHandler {
ctx, cancel := context.WithCancel(context.Background())
tick := time.NewTicker(time.Millisecond * time.Duration(60))
return &GuacamoleHandler{
ws: ws,
tunnel: tunnel,
ctx: ctx,
cancel: cancel,
dataChan: make(chan []byte),
tick: tick,
ws: ws,
tunnel: tunnel,
ctx: ctx,
cancel: cancel,
}
}
func (r GuacamoleHandler) Start() {
go r.readFormTunnel()
go r.writeToWebsocket()
}
func (r GuacamoleHandler) Stop() {
r.tick.Stop()
r.cancel()
}
func (r GuacamoleHandler) readFormTunnel() {
for {
select {
case <-r.ctx.Done():
return
default:
instruction, err := r.tunnel.Read()
if err != nil {
utils.Disconnect(r.ws, TunnelClosed, "远程连接已关闭")
go func() {
for {
select {
case <-r.ctx.Done():
return
}
if len(instruction) == 0 {
continue
}
r.dataChan <- instruction
}
}
}
func (r GuacamoleHandler) writeToWebsocket() {
var buf []byte
for {
select {
case <-r.ctx.Done():
return
case <-r.tick.C:
if len(buf) > 0 {
err := r.ws.WriteMessage(websocket.TextMessage, buf)
default:
instruction, err := r.tunnel.Read()
if err != nil {
utils.Disconnect(r.ws, TunnelClosed, "远程连接已关闭")
return
}
if len(instruction) == 0 {
continue
}
err = r.ws.WriteMessage(websocket.TextMessage, instruction)
if err != nil {
log.Debugf("WebSocket写入失败即将关闭Guacd连接...")
return
}
buf = []byte{}
}
case data := <-r.dataChan:
buf = append(buf, data...)
}
}
}()
}
func (r GuacamoleHandler) Stop() {
r.cancel()
}

View File

@ -25,7 +25,7 @@ func (api JobApi) JobCreateEndpoint(c echo.Context) error {
item.ID = utils.UUID()
item.Created = utils.NowJsonTime()
if err := service.JobService.Create(&item); err != nil {
if err := service.JobService.Create(context.TODO(), &item); err != nil {
return err
}
return Success(c, "")

View File

@ -2,6 +2,7 @@ package api
import (
"context"
"next-terminal/server/service"
"next-terminal/server/dto"
"next-terminal/server/repository"
@ -42,7 +43,7 @@ func (api ResourceSharerApi) ResourceAddByUserIdAssignEndPoint(c echo.Context) e
return err
}
if err := repository.ResourceSharerRepository.AddSharerResources(ru.UserGroupId, ru.UserId, ru.StrategyId, ru.ResourceType, ru.ResourceIds); err != nil {
if err := service.UserService.AddSharerResources(context.TODO(), ru.UserGroupId, ru.UserId, ru.StrategyId, ru.ResourceType, ru.ResourceIds); err != nil {
return err
}

View File

@ -312,16 +312,16 @@ func (api SessionApi) SessionDownloadEndpoint(c echo.Context) error {
if s.Download != "1" {
return errors.New("禁止操作")
}
remoteFile := c.QueryParam("file")
file := c.QueryParam("file")
// 获取带后缀的文件名称
filenameWithSuffix := path.Base(remoteFile)
filenameWithSuffix := path.Base(file)
if "ssh" == s.Protocol {
nextSession := session.GlobalSessionManager.GetById(sessionId)
if nextSession == nil {
return errors.New("获取会话失败")
}
dstFile, err := nextSession.NextTerminal.SftpClient.Open(remoteFile)
dstFile, err := nextSession.NextTerminal.SftpClient.Open(file)
if err != nil {
return err
}
@ -337,7 +337,7 @@ func (api SessionApi) SessionDownloadEndpoint(c echo.Context) error {
return c.Stream(http.StatusOK, echo.MIMEOctetStream, bytes.NewReader(buff.Bytes()))
} else if "rdp" == s.Protocol {
storageId := s.StorageId
return service.StorageService.StorageDownload(c, remoteFile, storageId)
return service.StorageService.StorageDownload(c, file, storageId)
}
return err
@ -541,7 +541,9 @@ func (api SessionApi) SessionRecordingEndpoint(c echo.Context) error {
_ = repository.SessionRepository.UpdateReadByIds(context.TODO(), true, []string{sessionId})
log.Debugf("读取录屏文件:%v,是否存在: %v, 是否为文件: %v", recording, utils.FileExists(recording), utils.IsFile(recording))
return c.File(recording)
http.ServeFile(c.Response(), c.Request(), recording)
return nil
}
func (api SessionApi) SessionGetEndpoint(c echo.Context) error {

View File

@ -134,7 +134,7 @@ func (api StorageApi) StorageDeleteEndpoint(c echo.Context) error {
split := strings.Split(ids, ",")
for i := range split {
id := split[i]
if err := service.StorageService.DeleteStorageById(id, false); err != nil {
if err := service.StorageService.DeleteStorageById(context.TODO(), id, false); err != nil {
return err
}
}
@ -173,8 +173,8 @@ func (api StorageApi) StorageDownloadEndpoint(c echo.Context) error {
if err := api.PermissionCheck(c, storageId); err != nil {
return err
}
remoteFile := c.QueryParam("file")
return service.StorageService.StorageDownload(c, remoteFile, storageId)
file := c.QueryParam("file")
return service.StorageService.StorageDownload(c, file, storageId)
}
func (api StorageApi) StorageUploadEndpoint(c echo.Context) error {

View File

@ -157,6 +157,7 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error {
termHandler := NewTermHandler(sessionId, isRecording, ws, nextTerminal)
termHandler.Start()
defer termHandler.Stop()
for {
_, message, err := ws.ReadMessage()
@ -164,7 +165,6 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error {
// web socket会话关闭后主动关闭ssh会话
log.Debugf("WebSocket已关闭")
service.SessionService.CloseSessionById(sessionId, Normal, "用户正常退出")
termHandler.Stop()
break
}

View File

@ -20,7 +20,7 @@ func (userGroupApi UserGroupApi) UserGroupCreateEndpoint(c echo.Context) error {
return err
}
if _, err := service.UserGroupService.Create(item.Name, item.Members); err != nil {
if _, err := service.UserGroupService.Create(context.TODO(), item.Name, item.Members); err != nil {
return err
}

View File

@ -2,7 +2,7 @@ package api
import (
"context"
"fmt"
"strconv"
"strings"
@ -141,7 +141,11 @@ func (userApi UserApi) UserChangePasswordEndpoint(c echo.Context) error {
}
if user.Mail != "" {
go service.MailService.SendMail(user.Mail, "[Next Terminal] 密码修改通知", "你好,"+user.Nickname+"。管理员已将你的密码修改为:"+password)
subject := "密码修改通知"
text := fmt.Sprintf(`您好,%s。
管理员已将你的密码修改为:%s。
`, user.Username, password)
go service.MailService.SendMail(user.Mail, subject, text)
}
return Success(c, "")