optimize: desktop viewer

This commit is contained in:
XZB-1248
2023-02-02 16:44:27 +08:00
parent 08059e95da
commit 73c1b26b7e
12 changed files with 342 additions and 227 deletions

View File

@@ -43,12 +43,12 @@ func isPrivateIP(ip _net.IP) bool {
func GetLocalIP() (string, error) {
ifaces, err := _net.Interfaces()
if err != nil {
return `Unknown`, err
return `<UNKNOWN>`, err
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
return `Unknown`, err
return `<UNKNOWN>`, err
}
for _, addr := range addrs {
@@ -68,7 +68,7 @@ func GetLocalIP() (string, error) {
}
}
}
return `Unknown`, errors.New(`no IP address found`)
return `<UNKNOWN>`, errors.New(`no IP address found`)
}
func GetMacAddress() (string, error) {
@@ -179,16 +179,16 @@ func GetDevice() (*modules.Device, error) {
}
localIP, err := GetLocalIP()
if err != nil {
localIP = `<unknown>`
localIP = `<UNKNOWN>`
}
macAddr, err := GetMacAddress()
if err != nil {
macAddr = `<unknown>`
macAddr = `<UNKNOWN>`
}
cpuInfo, err := GetCPUInfo()
if err != nil {
cpuInfo = modules.CPU{
Model: `<unknown>`,
Model: `<UNKNOWN>`,
Usage: 0,
}
}
@@ -221,11 +221,11 @@ func GetDevice() (*modules.Device, error) {
}
hostname, err := os.Hostname()
if err != nil {
hostname = `<unknown>`
hostname = `<UNKNOWN>`
}
username, err := user.Current()
if err != nil {
username = &user.User{Username: `<unknown>`}
username = &user.User{Username: `<UNKNOWN>`}
} else {
slashIndex := strings.Index(username.Username, `\`)
if slashIndex > -1 && slashIndex+1 < len(username.Username) {
@@ -252,7 +252,7 @@ func GetPartialInfo() (*modules.Device, error) {
cpuInfo, err := GetCPUInfo()
if err != nil {
cpuInfo = modules.CPU{
Model: `<unknown>`,
Model: `<UNKNOWN>`,
Usage: 0,
}
}

View File

@@ -33,8 +33,7 @@ type message struct {
frame *[]*[]byte
}
// packet explanation:
// frame packet format:
// +---------+---------+----------+-------------+----------+---------+---------+---------+---------+-------+
// | magic | op code | event id | body length | img type | x | y | width | height | image |
// +---------+---------+----------+-------------+----------+---------+---------+---------+---------+-------+
@@ -54,9 +53,9 @@ type message struct {
// 0: raw image
// 1: compressed image (jpeg)
const fpsLimit = 10
const compress = true
const blockSize = 64
const compress = 1
const fpsLimit = 24
const blockSize = 96
const frameBuffer = 3
const displayIndex = 0
const imageQuality = 70
@@ -66,7 +65,7 @@ var working = false
var sessions = cmap.New()
var prevDesktop *image.RGBA
var displayBounds image.Rectangle
var ErrNoImage = errors.New(`DESKTOP.NO_IMAGE_YET`)
var errNoImage = errors.New(`DESKTOP.NO_IMAGE_YET`)
func init() {
go healthCheck()
@@ -84,34 +83,50 @@ func worker() {
lock.Unlock()
var (
screen screen
numErrors int
screen Screen
img *image.RGBA
err error
errors int
)
screen.init(displayIndex)
screen.Init(displayIndex, displayBounds)
for working {
if sessions.Count() == 0 {
lock.Lock()
working = false
lock.Unlock()
break
}
img = image.NewRGBA(displayBounds)
err = screen.capture(img, displayBounds)
img, err = screen.Capture()
if err != nil {
if err == ErrNoImage {
return
if err == errNoImage {
<-time.After(time.Second / fpsLimit)
continue
}
errors++
if errors > 10 {
numErrors++
if numErrors > 10 {
break
}
} else {
errors = 0
numErrors = 0
diff := imageCompare(img, prevDesktop, compress)
if diff != nil && len(diff) > 0 {
prevDesktop = img
sendImageDiff(diff)
}
<-time.After(time.Second / fpsLimit)
}
}
img = nil
prevDesktop = nil
if numErrors > 10 {
quitAllDesktop(err.Error())
}
lock.Lock()
working = false
lock.Unlock()
screen.Release()
runtime.UnlockOSThread()
go runtime.GC()
}
func sendImageDiff(diff []*[]byte) {
sessions.IterCb(func(uuid string, t any) bool {
desktop := t.(*session)
desktop.lock.Lock()
@@ -128,21 +143,8 @@ func worker() {
return true
})
}
<-time.After(time.Second / fpsLimit)
}
}
prevDesktop = nil
if errors > 10 {
quitAll(err.Error())
}
lock.Lock()
working = false
lock.Unlock()
screen.release()
runtime.UnlockOSThread()
}
func quitAll(info string) {
func quitAllDesktop(info string) {
keys := make([]string, 0)
sessions.IterCb(func(uuid string, t any) bool {
keys = append(keys, uuid)
@@ -157,7 +159,7 @@ func quitAll(info string) {
lock.Unlock()
}
func imageCompare(img, prev *image.RGBA, compress bool) []*[]byte {
func imageCompare(img, prev *image.RGBA, compress int) []*[]byte {
result := make([]*[]byte, 0)
if prev == nil {
return splitFullImage(img, compress)
@@ -168,24 +170,13 @@ func imageCompare(img, prev *image.RGBA, compress bool) []*[]byte {
}
for _, rect := range diff {
block := getImageBlock(img, rect, compress)
buf := make([]byte, 12)
binary.BigEndian.PutUint16(buf[0:2], uint16(len(block)+10))
if compress {
binary.BigEndian.PutUint16(buf[2:4], uint16(1))
} else {
binary.BigEndian.PutUint16(buf[2:4], uint16(0))
}
binary.BigEndian.PutUint16(buf[4:6], uint16(rect.Min.X))
binary.BigEndian.PutUint16(buf[6:8], uint16(rect.Min.Y))
binary.BigEndian.PutUint16(buf[8:10], uint16(rect.Size().X))
binary.BigEndian.PutUint16(buf[10:12], uint16(rect.Size().Y))
buf = append(buf, block...)
result = append(result, &buf)
block = makeImageBlock(block, rect, compress)
result = append(result, &block)
}
return result
}
func splitFullImage(img *image.RGBA, compress bool) []*[]byte {
func splitFullImage(img *image.RGBA, compress int) []*[]byte {
if img == nil {
return nil
}
@@ -197,26 +188,16 @@ func splitFullImage(img *image.RGBA, compress bool) []*[]byte {
height := utils.If(y+blockSize > imgHeight, imgHeight-y, blockSize)
for x := rect.Min.X; x < rect.Max.X; x += blockSize {
width := utils.If(x+blockSize > imgWidth, imgWidth-x, blockSize)
block := getImageBlock(img, image.Rect(x, y, x+width, y+height), compress)
buf := make([]byte, 12)
binary.BigEndian.PutUint16(buf[0:2], uint16(len(block)+10))
if compress {
binary.BigEndian.PutUint16(buf[2:4], uint16(1))
} else {
binary.BigEndian.PutUint16(buf[2:4], uint16(0))
}
binary.BigEndian.PutUint16(buf[4:6], uint16(x))
binary.BigEndian.PutUint16(buf[6:8], uint16(y))
binary.BigEndian.PutUint16(buf[8:10], uint16(width))
binary.BigEndian.PutUint16(buf[10:12], uint16(height))
buf = append(buf, block...)
result = append(result, &buf)
blockRect := image.Rect(x, y, x+width, y+height)
block := getImageBlock(img, blockRect, compress)
block = makeImageBlock(block, blockRect, compress)
result = append(result, &block)
}
}
return result
}
func getImageBlock(img *image.RGBA, rect image.Rectangle, compress bool) []byte {
func getImageBlock(img *image.RGBA, rect image.Rectangle, compress int) []byte {
width := rect.Dx()
height := rect.Dy()
buf := make([]byte, width*height*4)
@@ -227,9 +208,10 @@ func getImageBlock(img *image.RGBA, rect image.Rectangle, compress bool) []byte
bufPos += width * 4
imgPos += img.Stride
}
if !compress {
switch compress {
case 0:
return buf
}
case 1:
subImg := &image.RGBA{
Pix: buf,
Stride: width * 4,
@@ -239,6 +221,20 @@ func getImageBlock(img *image.RGBA, rect image.Rectangle, compress bool) []byte
jpeg.Encode(writer, subImg, &jpeg.Options{Quality: imageQuality})
return writer.Bytes()
}
return nil
}
func makeImageBlock(block []byte, rect image.Rectangle, compress int) []byte {
buf := make([]byte, 12)
binary.BigEndian.PutUint16(buf[0:2], uint16(len(block)+10))
binary.BigEndian.PutUint16(buf[2:4], uint16(compress))
binary.BigEndian.PutUint16(buf[4:6], uint16(rect.Min.X))
binary.BigEndian.PutUint16(buf[6:8], uint16(rect.Min.Y))
binary.BigEndian.PutUint16(buf[8:10], uint16(rect.Size().X))
binary.BigEndian.PutUint16(buf[10:12], uint16(rect.Size().Y))
buf = append(buf, block...)
return buf
}
func getDiff(img, prev *image.RGBA) []image.Rectangle {
imgWidth := img.Rect.Dx()
@@ -312,7 +308,7 @@ func InitDesktop(pack modules.Packet) error {
rawEvent: rawEvent,
lastPack: utils.Unix,
escape: false,
channel: make(chan message, 3),
channel: make(chan message, 5),
lock: &sync.Mutex{},
}
{
@@ -350,9 +346,7 @@ func PingDesktop(pack modules.Packet) {
} else {
uuid = val.(string)
}
if val, ok := sessions.Get(uuid); !ok {
return
} else {
if val, ok := sessions.Get(uuid); ok {
desktop = val.(*session)
desktop.lastPack = utils.Unix
}
@@ -442,11 +436,10 @@ func handleDesktop(pack modules.Packet, uuid string, desktop *session) {
binary.BigEndian.PutUint16(data[4:6], uint16(displayBounds.Dy()))
buf = append(buf, data...)
common.WSConn.SendData(buf)
break
continue
}
case <-time.After(time.Second * 5):
default:
time.Sleep(50 * time.Millisecond)
case <-time.After(7 * time.Second):
continue
}
}
}

View File

@@ -0,0 +1,23 @@
//go:build !windows
// +build !windows
package desktop
import (
"github.com/kbinani/screenshot"
"image"
)
type Screen struct {
rect image.Rectangle
}
func (s *Screen) Init(_ uint, rect image.Rectangle) {
s.rect = rect
}
func (s *Screen) Capture() (*image.RGBA, error) {
return screenshot.CaptureRect(s.rect)
}
func (s *Screen) Release() {}

View File

@@ -0,0 +1,198 @@
package desktop
import (
"errors"
"github.com/kirides/go-d3d/d3d11"
"github.com/kirides/go-d3d/outputduplication"
"github.com/kirides/go-d3d/outputduplication/swizzle"
winDXGI "github.com/kirides/go-d3d/win"
winGDI "github.com/lxn/win"
"image"
"syscall"
"unsafe"
)
var (
libUser32, _ = syscall.LoadLibrary("user32.dll")
funcGetDesktopWindow, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetDesktopWindow")
funcEnumDisplayMonitors, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "EnumDisplayMonitors")
funcGetMonitorInfo, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetMonitorInfoW")
funcEnumDisplaySettings, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "EnumDisplaySettingsW")
)
type Screen struct {
screen ScreenCapture
}
type ScreenCapture interface {
Init(uint, image.Rectangle) error
Capture() (*image.RGBA, error)
Release()
}
type ScreenDXGI struct {
rect image.Rectangle
device *d3d11.ID3D11Device
deviceCtx *d3d11.ID3D11DeviceContext
ddup *outputduplication.OutputDuplicator
}
type ScreenGDI struct {
rect image.Rectangle
width int
height int
hwnd winGDI.HWND
hdc winGDI.HDC
memoryDevice winGDI.HDC
bitmap winGDI.HBITMAP
bitmapInfo winGDI.BITMAPINFOHEADER
bitmapDataSize uintptr
hmem winGDI.HGLOBAL
memptr unsafe.Pointer
}
func (s *Screen) Init(displayIndex uint, rect image.Rectangle) {
dxgi := ScreenDXGI{}
if dxgi.Init(displayIndex, rect) == nil {
s.screen = &dxgi
} else {
gdi := ScreenGDI{}
gdi.Init(displayIndex, rect)
s.screen = &gdi
}
}
func (s *Screen) Capture() (*image.RGBA, error) {
return s.screen.Capture()
}
func (s *Screen) Release() {
s.screen.Release()
}
func (s *ScreenDXGI) Init(displayIndex uint, rect image.Rectangle) error {
s.rect = rect
var err error
if !winDXGI.IsValidDpiAwarenessContext(winDXGI.DpiAwarenessContextPerMonitorAwareV2) {
return errors.New("no valid DPI awareness context")
}
_, err = winDXGI.SetThreadDpiAwarenessContext(winDXGI.DpiAwarenessContextPerMonitorAwareV2)
if err != nil {
return err
}
s.device, s.deviceCtx, err = d3d11.NewD3D11Device()
s.ddup, err = outputduplication.NewIDXGIOutputDuplication(s.device, s.deviceCtx, displayIndex)
if err != nil {
s.device.Release()
s.deviceCtx.Release()
return err
}
return nil
}
func (s *ScreenDXGI) Capture() (*image.RGBA, error) {
img := image.NewRGBA(image.Rect(0, 0, s.rect.Dx(), s.rect.Dy()))
err := s.ddup.GetImage(img, 100)
if err == outputduplication.ErrNoImageYet {
return nil, errNoImage
}
return img, err
}
func (s *ScreenDXGI) Release() {
if s.ddup != nil {
s.ddup.Release()
s.ddup = nil
}
if s.device != nil {
s.device.Release()
s.device = nil
}
if s.deviceCtx != nil {
s.deviceCtx.Release()
s.deviceCtx = nil
}
}
func (s *ScreenGDI) Init(_ uint, rect image.Rectangle) error {
s.rect = rect
s.width = rect.Dx()
s.height = rect.Dy()
s.hwnd = getDesktopWindow()
s.hdc = winGDI.GetDC(s.hwnd)
if s.hdc == 0 {
s.Release()
return errors.New("GetDC failed")
}
s.memoryDevice = winGDI.CreateCompatibleDC(s.hdc)
if s.memoryDevice == 0 {
s.Release()
return errors.New("CreateCompatibleDC failed")
}
s.bitmap = winGDI.CreateCompatibleBitmap(s.hdc, int32(s.width), int32(s.height))
if s.bitmap == 0 {
s.Release()
return errors.New("CreateCompatibleBitmap failed")
}
s.bitmapInfo = winGDI.BITMAPINFOHEADER{}
s.bitmapInfo.BiSize = uint32(unsafe.Sizeof(s.bitmapInfo))
s.bitmapInfo.BiPlanes = 1
s.bitmapInfo.BiBitCount = 32
s.bitmapInfo.BiWidth = int32(s.width)
s.bitmapInfo.BiHeight = -int32(s.height)
s.bitmapInfo.BiCompression = winGDI.BI_RGB
s.bitmapInfo.BiSizeImage = uint32(s.width * s.height * 4)
s.bitmapDataSize = uintptr(((int64(s.width)*int64(s.bitmapInfo.BiBitCount) + 31) / 32) * 4 * int64(s.height))
s.hmem = winGDI.GlobalAlloc(winGDI.GMEM_MOVEABLE, s.bitmapDataSize)
if s.hmem == 0 {
s.Release()
return errors.New("GlobalAlloc failed")
}
s.memptr = winGDI.GlobalLock(s.hmem)
if s.memptr == nil {
s.Release()
return errors.New("GlobalLock failed")
}
return nil
}
func (s *ScreenGDI) Capture() (*image.RGBA, error) {
old := winGDI.SelectObject(s.memoryDevice, winGDI.HGDIOBJ(s.bitmap))
if old == 0 {
return nil, errors.New("SelectObject failed")
}
if !winGDI.BitBlt(s.memoryDevice, 0, 0, int32(s.width), int32(s.height), s.hdc, int32(s.rect.Min.X), int32(s.rect.Min.Y), winGDI.SRCCOPY) {
return nil, errors.New("BitBlt failed")
}
if winGDI.GetDIBits(s.hdc, s.bitmap, 0, uint32(s.height), (*uint8)(s.memptr), (*winGDI.BITMAPINFO)(unsafe.Pointer(&s.bitmapInfo)), winGDI.DIB_RGB_COLORS) == 0 {
return nil, errors.New("GetDIBits failed")
}
img := image.NewRGBA(image.Rect(0, 0, s.width, s.height))
imageBytes := ((*[1 << 30]byte)(unsafe.Pointer(s.memptr)))[:s.bitmapDataSize:s.bitmapDataSize]
copy(img.Pix[:s.bitmapDataSize], imageBytes)
swizzle.BGRA(img.Pix)
return img, nil
}
func (s *ScreenGDI) Release() {
if s.hdc != 0 {
winGDI.ReleaseDC(s.hwnd, s.hdc)
s.hdc = 0
}
if s.memoryDevice != 0 {
winGDI.DeleteDC(s.memoryDevice)
s.memoryDevice = 0
}
if s.bitmap != 0 {
winGDI.DeleteObject(winGDI.HGDIOBJ(s.bitmap))
s.bitmap = 0
}
if s.hmem != 0 {
winGDI.GlobalUnlock(s.hmem)
winGDI.GlobalFree(s.hmem)
s.hmem = 0
}
}
func getDesktopWindow() winGDI.HWND {
ret, _, _ := syscall.SyscallN(funcGetDesktopWindow)
return winGDI.HWND(ret)
}

View File

@@ -1,28 +0,0 @@
//go:build !windows
// +build !windows
package desktop
import (
"github.com/kbinani/screenshot"
"image"
)
type screen struct {
displayIndex int
}
func (s *screen) init(displayIndex int) {
s.displayIndex = displayIndex
}
func (s *screen) capture(img *image.RGBA, _ image.Rectangle) error {
image, err := screenshot.CaptureDisplay(displayIndex)
if err == nil {
*img = *image
}
return err
}
func (s *screen) release() {
}

View File

@@ -1,66 +0,0 @@
//go:build windows
// +build windows
package desktop
import (
"github.com/kirides/screencapture/d3d"
"github.com/kirides/screencapture/screenshot"
"github.com/kirides/screencapture/win"
"image"
)
type screen struct {
dxgi bool
ddup *d3d.OutputDuplicator
device *d3d.ID3D11Device
deviceCtx *d3d.ID3D11DeviceContext
displayIndex int
}
func (s *screen) init(displayIndex int) {
var err error
s.displayIndex = displayIndex
s.dxgi = false
return
if win.IsValidDpiAwarenessContext(win.DpiAwarenessContextPerMonitorAwareV2) {
_, err = win.SetThreadDpiAwarenessContext(win.DpiAwarenessContextPerMonitorAwareV2)
s.dxgi = err == nil
}
if s.dxgi {
s.device, s.deviceCtx, err = d3d.NewD3D11Device()
s.ddup, err = d3d.NewIDXGIOutputDuplication(s.device, s.deviceCtx, uint(displayIndex))
if err != nil {
s.dxgi = false
s.device.Release()
s.deviceCtx.Release()
}
}
}
func (s *screen) capture(img *image.RGBA, bounds image.Rectangle) error {
var err error
if s.dxgi {
err = s.ddup.GetImage(img, 100)
if err != nil {
if err == d3d.ErrNoImageYet {
return ErrNoImage
}
return err
}
return nil
}
return screenshot.CaptureImg(img, 0, 0, bounds.Dx(), bounds.Dy())
}
func (s *screen) release() {
if s.ddup != nil {
s.ddup.Release()
}
if s.device != nil {
s.device.Release()
}
if s.deviceCtx != nil {
s.deviceCtx.Release()
}
}

View File

@@ -16,7 +16,7 @@ func ListProcesses() ([]Process, error) {
for i := 0; i < len(processes); i++ {
name, err := processes[i].Name()
if err != nil {
name = `<Unknown>`
name = `<UNKNOWN>`
}
result = append(result, Process{Name: name, Pid: processes[i].Pid})
}

13
go.mod
View File

@@ -11,14 +11,15 @@ require (
github.com/json-iterator/go v1.1.12
github.com/kataras/golog v0.1.7
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329
github.com/kirides/go-d3d v1.0.0
github.com/lxn/win v0.0.0-20210218163916-a377121e959e
github.com/rakyll/statik v0.1.7
github.com/shirou/gopsutil/v3 v3.22.2
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
)
require github.com/kirides/screencapture v0.0.0-20211101142135-282f3f7e0f33
require (
github.com/gen2brain/shm v0.0.0-20210511105953-083dbc7d9d83 // indirect
github.com/gen2brain/shm v0.0.0-20221026125803-c33c9e32b1c8 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.13.0 // indirect
@@ -27,11 +28,10 @@ require (
github.com/golang/protobuf v1.3.3 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect
github.com/jezek/xgb v1.1.0 // indirect
github.com/kataras/pio v0.0.10 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -40,9 +40,8 @@ require (
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/net v0.0.0-20220111093109-d55c255bac03 // indirect
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)

14
go.sum
View File

@@ -6,8 +6,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/gen2brain/shm v0.0.0-20210511105953-083dbc7d9d83 h1:fRNwUddc/xxdx5kQ38X4+q/Grnqlp9zfV/ssKzSzVk0=
github.com/gen2brain/shm v0.0.0-20210511105953-083dbc7d9d83/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/gen2brain/shm v0.0.0-20221026125803-c33c9e32b1c8 h1:u4/UVF0sNxlqDwCptjIUTUkZW4UoZDrcHzvd2kNnF/k=
github.com/gen2brain/shm v0.0.0-20221026125803-c33c9e32b1c8/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
@@ -36,8 +36,9 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/imroc/req/v3 v3.8.2 h1:wFZ7B0dclCQyjClP5GwXRboUGIek5l0mCpodrGgT01c=
github.com/imroc/req/v3 v3.8.2/go.mod h1:3JIicOKEDHfCSYYNLb/ObZNpx64EV5y40VlHMwhUCzU=
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 h1:dy+DS31tGEGCsZzB45HmJJNHjur8GDgtRNX9U7HnSX4=
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240/go.mod h1:3P4UH/k22rXyHIJD2w4h2XMqPX4Of/eySEZq9L6wqc4=
github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk=
github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
@@ -47,8 +48,8 @@ github.com/kataras/pio v0.0.10 h1:b0qtPUqOpM2O+bqa5wr2O6dN4cQNwSmFd6HQqgVae0g=
github.com/kataras/pio v0.0.10/go.mod h1:gS3ui9xSD+lAUpbYnjOGiQyY7sUMJO+EHpiRzhtZ5no=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o=
github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4=
github.com/kirides/screencapture v0.0.0-20211101142135-282f3f7e0f33 h1:DXPbp2f7LBZzkWnpPGUG+H1+82++20vNIpalTamWv6E=
github.com/kirides/screencapture v0.0.0-20211101142135-282f3f7e0f33/go.mod h1:fMSGsolzmMhah/U24dXBHSf/6Ue/mXVSIb4wRU7U4Ts=
github.com/kirides/go-d3d v1.0.0 h1:i1XycQ+8KCZqToyGq7o6I92EwcJDXgIICSVjLhmHuaM=
github.com/kirides/go-d3d v1.0.0/go.mod h1:KUNIIJoB+psyPedDBv8TY4gKXmPJT3K1+F2nL2pKDPQ=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
@@ -100,8 +101,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=

View File

@@ -359,7 +359,7 @@ func checkAuth() gin.HandlerFunc {
if ctx.IsAborted() {
blocked.Set(addr, now+1)
user = utils.If(len(user) == 0, `EMPTY`, user)
user = utils.If(len(user) == 0, `<EMPTY>`, user)
common.Warn(ctx, `LOGIN_ATTEMPT`, `fail`, ``, map[string]any{
`user`: user,
})

View File

@@ -15,9 +15,10 @@ import (
)
var (
JSON = jsoniter.Config{EscapeHTML: false, SortMapKeys: true, ValidateJsonRawMessage: true}.Froze()
ErrEntityInvalid = errors.New(`common.ENTITY_INVALID`)
ErrFailedVerification = errors.New(`common.ENTITY_CHECK_FAILED`)
JSON = jsoniter.ConfigCompatibleWithStandardLibrary
)
func If[T any](b bool, t, f T) T {

View File

@@ -41,6 +41,7 @@ function ScreenModal(props) {
function initCanvas() {
if (!canvas) return;
ctx = canvas.getContext('2d', {alpha: false});
ctx.imageSmoothingEnabled = false;
}
function construct() {
if (ctx !== null) {
@@ -87,24 +88,11 @@ function ScreenModal(props) {
}
}
function fullScreen() {
try {
canvas.requestFullscreen();
} catch {}
try {
canvas.webkitRequestFullscreen();
} catch {}
try {
canvas.mozRequestFullScreen();
} catch {}
try {
canvas.msRequestFullscreen();
} catch {}
canvas.requestFullscreen().catch(console.error);
}
function refresh() {
if (canvas && props.open) {
if (!conn) {
canvas.width = 1920;
canvas.height = 1080;
initCanvas(canvas);
construct(canvas);
} else {
@@ -150,13 +138,18 @@ function ScreenModal(props) {
dv = null;
}
function updateImage(ab, it, dx, dy, bw, bh, canvasCtx) {
if (it === 0) {
switch (it) {
case 0:
canvasCtx.putImageData(new ImageData(new Uint8ClampedArray(ab), bw, bh), dx, dy, 0, 0, bw, bh);
} else {
createImageBitmap(new Blob([ab]), 0, 0, bw, bh)
.then((ib) => {
break;
case 1:
createImageBitmap(new Blob([ab]), 0, 0, bw, bh, {
premultiplyAlpha: 'none',
colorSpaceConversion: 'none'
}).then((ib) => {
canvasCtx.drawImage(ib, 0, 0, bw, bh, dx, dy, bw, bh);
});
break;
}
}
function handleJSON(ab) {