feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更: - RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、 backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API - Windows SMB 文件传输:backend/pkg/winsmb - 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情 - Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs - 服务器导入助手:server_import_helpers、ImportCredentialSettings - 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块) - 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-* - .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
777d9e4e71
commit
76ec9387f0
202 files changed
+16555
-2543
No files matched your search
@@ -0,0 +1,264 @@
|
||||
package rdp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"ezops/pkg/rdp/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
fastPathOutputCompressionUsed = 0xC0
|
||||
fastPathFragmentSingle = 0x00
|
||||
fastPathFragmentLast = 0x10
|
||||
fastPathFragmentFirst = 0x20
|
||||
fastPathFragmentNext = 0x30
|
||||
)
|
||||
|
||||
// FastPathReceiver 解析服务端 Fast-Path 更新并产出位图块 // Logan.Li
|
||||
type FastPathReceiver struct {
|
||||
mppc *MppcDecompressor
|
||||
fragments bytes.Buffer
|
||||
frameIDs []uint32
|
||||
updateStats map[byte]int
|
||||
}
|
||||
|
||||
func NewFastPathReceiver() *FastPathReceiver {
|
||||
return &FastPathReceiver{mppc: NewMppcDecompressor(), updateStats: make(map[byte]int)}
|
||||
}
|
||||
|
||||
func (f *FastPathReceiver) Handle(secFlag byte, payload []byte) ([]BitmapRect, error) {
|
||||
_ = secFlag
|
||||
r := bytes.NewReader(payload)
|
||||
var rects []BitmapRect
|
||||
for r.Len() > 0 {
|
||||
updateHeader, err := readU8(r)
|
||||
if err != nil {
|
||||
return rects, err
|
||||
}
|
||||
updateCode := updateHeader & 0x0f
|
||||
fragmentation := updateHeader & 0x30
|
||||
compression := updateHeader & 0xC0
|
||||
f.updateStats[updateCode]++
|
||||
|
||||
var compressionFlags byte
|
||||
if compression == fastPathOutputCompressionUsed {
|
||||
compressionFlags, err = readU8(r)
|
||||
if err != nil {
|
||||
return rects, err
|
||||
}
|
||||
}
|
||||
size, err := readLE16(r)
|
||||
if err != nil {
|
||||
return rects, err
|
||||
}
|
||||
if f.updateStats[updateCode] <= 8 || f.updateStats[updateCode]%100 == 0 {
|
||||
trace.Logf("fastpath update code=%s(0x%x) count=%d size=%d frag=0x%02x compression=0x%02x flags=0x%02x", fastPathUpdateName(updateCode), updateCode, f.updateStats[updateCode], size, fragmentation, compression, compressionFlags)
|
||||
}
|
||||
block := make([]byte, int(size))
|
||||
if _, err = r.Read(block); err != nil {
|
||||
return rects, err
|
||||
}
|
||||
|
||||
if fragmentation != fastPathFragmentSingle {
|
||||
if fragmentation == fastPathFragmentFirst {
|
||||
f.fragments.Reset()
|
||||
}
|
||||
f.fragments.Write(block)
|
||||
if fragmentation != fastPathFragmentLast {
|
||||
continue
|
||||
}
|
||||
block = append([]byte(nil), f.fragments.Bytes()...)
|
||||
}
|
||||
if compressionFlags != 0 {
|
||||
decompressed, err := f.mppc.Decompress(compressionFlags, block)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
block = decompressed
|
||||
}
|
||||
|
||||
switch updateCode {
|
||||
case fastPathUpdateBitmap:
|
||||
bs, err := parseFastPathBitmap(block)
|
||||
if err != nil {
|
||||
return rects, err
|
||||
}
|
||||
rects = append(rects, bs...)
|
||||
case fastPathUpdateSurfaceCmds:
|
||||
bs, frameIDs, err := parseSurfaceCommands(block)
|
||||
if err != nil {
|
||||
return rects, err
|
||||
}
|
||||
f.frameIDs = append(f.frameIDs, frameIDs...)
|
||||
rects = append(rects, bs...)
|
||||
default:
|
||||
trace.Logf("fastpath skip update code=%s(0x%x) size=%d", fastPathUpdateName(updateCode), updateCode, len(block))
|
||||
}
|
||||
}
|
||||
return rects, nil
|
||||
}
|
||||
|
||||
func fastPathUpdateName(code byte) string {
|
||||
switch code {
|
||||
case 0x0:
|
||||
return "orders"
|
||||
case fastPathUpdateBitmap:
|
||||
return "bitmap"
|
||||
case 0x2:
|
||||
return "palette"
|
||||
case 0x3:
|
||||
return "synchronize"
|
||||
case fastPathUpdateSurfaceCmds:
|
||||
return "surface"
|
||||
case 0x5:
|
||||
return "ptr_null"
|
||||
case 0x6:
|
||||
return "ptr_default"
|
||||
case 0x8:
|
||||
return "ptr_position"
|
||||
case 0x9:
|
||||
return "color"
|
||||
case 0x0a:
|
||||
return "ptr_cached"
|
||||
case 0x0b:
|
||||
return "pointer"
|
||||
case 0x0c:
|
||||
return "large_pointer"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// TakeFrameIDs 取出需要确认的 Surface frame,避免服务端因队列满停止推帧 // Logan.Li
|
||||
func (f *FastPathReceiver) TakeFrameIDs() []uint32 {
|
||||
if len(f.frameIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := append([]uint32(nil), f.frameIDs...)
|
||||
f.frameIDs = f.frameIDs[:0]
|
||||
return out
|
||||
}
|
||||
|
||||
func (f *FastPathReceiver) HandleSlowPath(payload []byte) ([]BitmapRect, error) {
|
||||
ind, err := parseMCSDataIndication(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ind.payload) < 6 {
|
||||
return nil, nil
|
||||
}
|
||||
return parseSlowPathBitmap(ind.payload[4:])
|
||||
}
|
||||
|
||||
func parseSurfaceCommands(data []byte) ([]BitmapRect, []uint32, error) {
|
||||
r := bytes.NewReader(data)
|
||||
var out []BitmapRect
|
||||
var frameIDs []uint32
|
||||
for r.Len() >= 2 {
|
||||
cmdType, err := readLE16(r)
|
||||
if err != nil {
|
||||
return out, frameIDs, err
|
||||
}
|
||||
switch cmdType {
|
||||
case 0x0001, 0x0006:
|
||||
wb, err := readSurfaceBits(r)
|
||||
if err != nil {
|
||||
return out, frameIDs, err
|
||||
}
|
||||
if rect, ok := decodeWireBitmap(wb); ok {
|
||||
out = append(out, rect)
|
||||
}
|
||||
case 0x0004:
|
||||
frameAction, err := readLE16(r)
|
||||
if err != nil {
|
||||
return out, frameIDs, err
|
||||
}
|
||||
frameID, err := readLE32(r)
|
||||
if err != nil {
|
||||
return out, frameIDs, err
|
||||
}
|
||||
trace.Logf("surface frame marker action=%d frameID=%d", frameAction, frameID)
|
||||
if frameAction == 0x0001 {
|
||||
frameIDs = append(frameIDs, frameID)
|
||||
}
|
||||
default:
|
||||
return out, frameIDs, fmt.Errorf("未知 SurfaceCmd: 0x%04x", cmdType)
|
||||
}
|
||||
}
|
||||
return out, frameIDs, nil
|
||||
}
|
||||
|
||||
func readSurfaceBits(r *bytes.Reader) (wireBitmap, error) {
|
||||
destLeft, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
destTop, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
destRight, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
destBottom, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
bpp, err := readU8(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
flags, err := readU8(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
if _, err = readU8(r); err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
codecID, err := readU8(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
width, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
height, err := readLE16(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
dataLen, err := readLE32(r)
|
||||
if err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
if flags&0x01 != 0 {
|
||||
if dataLen < 24 {
|
||||
return wireBitmap{}, fmt.Errorf("SurfaceBits 扩展头长度非法: %d", dataLen)
|
||||
}
|
||||
if _, err = r.Seek(24, 1); err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
dataLen -= 24
|
||||
}
|
||||
data := make([]byte, int(dataLen))
|
||||
if _, err = r.Read(data); err != nil {
|
||||
return wireBitmap{}, err
|
||||
}
|
||||
if codecID != 0 {
|
||||
trace.Logf("surface skip unsupported codec=%d rect=%dx%d@%d,%d data=%d flags=0x%02x", codecID, width, height, destLeft, destTop, dataLen, flags)
|
||||
return wireBitmap{}, nil
|
||||
}
|
||||
trace.Logf("surface bits codec=%d rect=%dx%d@%d,%d data=%d flags=0x%02x", codecID, width, height, destLeft, destTop, dataLen, flags)
|
||||
return wireBitmap{
|
||||
DestLeft: destLeft, DestTop: destTop, DestRight: destRight, DestBottom: destBottom,
|
||||
Width: width, Height: height, BitsPerPixel: uint16(bpp), Flags: uint16(flags) | bitmapNoProcessing,
|
||||
BitmapDataStream: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readU8(r *bytes.Reader) (byte, error) {
|
||||
b, err := r.ReadByte()
|
||||
return b, err
|
||||
}
|
||||
Reference in new issue
Block a user