feat(gateway): repair native Apollo provider path
This commit is contained in:
+112
-18
@@ -3,36 +3,130 @@ package gateway
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var ErrInputMalformed = errors.New("input event malformed")
|
||||
|
||||
const (
|
||||
gatewayInputHeaderSize = 6
|
||||
gatewayInputKeyboard = 1
|
||||
gatewayInputMouse = 2
|
||||
gatewayInputRelative = 3
|
||||
gatewayInputUTF8 = 4
|
||||
gatewayInputController = 5
|
||||
)
|
||||
|
||||
func EncodeInputEvent(event InputEvent) ([]byte, error) {
|
||||
if len(event.Device) == 0 || len(event.Device) > 64 || len(event.Payload) > 1024 {
|
||||
switch event.Device {
|
||||
case "keyboard":
|
||||
if event.Code < 1 || event.Code > 0xffff || len(event.Payload) > 1 {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, gatewayInputHeaderSize+4)
|
||||
copy(encoded, "VGI1")
|
||||
encoded[4], encoded[5], encoded[6] = gatewayInputKeyboard, 4, 0
|
||||
if event.Pressed {
|
||||
encoded[6] = 1
|
||||
}
|
||||
if len(event.Payload) == 1 {
|
||||
encoded[7] = event.Payload[0]
|
||||
}
|
||||
binary.BigEndian.PutUint16(encoded[8:10], uint16(event.Code))
|
||||
return encoded, nil
|
||||
case "mouse-button":
|
||||
if event.Code < 1 || event.Code > 5 || len(event.Payload) != 0 {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, gatewayInputHeaderSize+3)
|
||||
copy(encoded, "VGI1")
|
||||
encoded[4], encoded[5], encoded[7] = gatewayInputMouse, 3, byte(event.Code)
|
||||
if event.Pressed {
|
||||
encoded[6] = 1
|
||||
}
|
||||
return encoded, nil
|
||||
case "mouse-relative":
|
||||
if event.Pressed || event.Code != 0 || len(event.Payload) != 4 {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, gatewayInputHeaderSize+4)
|
||||
copy(encoded, "VGI1")
|
||||
encoded[4], encoded[5] = gatewayInputRelative, 4
|
||||
copy(encoded[6:], event.Payload)
|
||||
return encoded, nil
|
||||
case "utf8":
|
||||
if event.Pressed || event.Code != 0 || len(event.Payload) == 0 || len(event.Payload) > utf8.UTFMax || !utf8.Valid(event.Payload) || utf8.RuneCount(event.Payload) != 1 {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, gatewayInputHeaderSize+len(event.Payload))
|
||||
copy(encoded, "VGI1")
|
||||
encoded[4], encoded[5] = gatewayInputUTF8, byte(len(event.Payload))
|
||||
copy(encoded[6:], event.Payload)
|
||||
return encoded, nil
|
||||
case "controller":
|
||||
if event.Code < 0 || event.Code > 15 || len(event.Payload) != 16 {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
active := binary.BigEndian.Uint16(event.Payload[:2])
|
||||
if (!event.Pressed && anyNonzero(event.Payload)) || (event.Pressed && active == 0) {
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, gatewayInputHeaderSize+17)
|
||||
copy(encoded, "VGI1")
|
||||
encoded[4], encoded[5], encoded[6] = gatewayInputController, 17, byte(event.Code)
|
||||
copy(encoded[7:], event.Payload)
|
||||
return encoded, nil
|
||||
default:
|
||||
return nil, ErrInputMalformed
|
||||
}
|
||||
encoded := make([]byte, 16+len(event.Device)+len(event.Payload))
|
||||
copy(encoded[:4], "INP1")
|
||||
binary.BigEndian.PutUint32(encoded[4:8], event.Sequence)
|
||||
binary.BigEndian.PutUint32(encoded[8:12], uint32(event.Code))
|
||||
if event.Pressed {
|
||||
encoded[12] = 1
|
||||
}
|
||||
encoded[13] = byte(len(event.Device))
|
||||
binary.BigEndian.PutUint16(encoded[14:16], uint16(len(event.Payload)))
|
||||
copy(encoded[16:16+len(event.Device)], event.Device)
|
||||
copy(encoded[16+len(event.Device):], event.Payload)
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func DecodeInputEvent(data []byte) (InputEvent, error) {
|
||||
if len(data) < 16 || len(data) > 1179 || string(data[:4]) != "INP1" || (data[12] != 0 && data[12] != 1) {
|
||||
if len(data) < gatewayInputHeaderSize || len(data) > 1179 || string(data[:4]) != "VGI1" || len(data) != gatewayInputHeaderSize+int(data[5]) {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
deviceLength := int(data[13])
|
||||
payloadLength := int(binary.BigEndian.Uint16(data[14:16]))
|
||||
if deviceLength == 0 || deviceLength > 64 || payloadLength > 1024 || len(data) != 16+deviceLength+payloadLength {
|
||||
kind, body := data[4], data[gatewayInputHeaderSize:]
|
||||
switch kind {
|
||||
case gatewayInputKeyboard:
|
||||
if len(body) != 4 || body[0] > 1 || binary.BigEndian.Uint16(body[2:4]) == 0 {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Device: "keyboard", Code: int32(binary.BigEndian.Uint16(body[2:4])), Pressed: body[0] == 1, Payload: []byte{body[1]}}, nil
|
||||
case gatewayInputMouse:
|
||||
if len(body) != 3 || body[0] > 1 || body[1] < 1 || body[1] > 5 || body[2] != 0 {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Device: "mouse-button", Code: int32(body[1]), Pressed: body[0] == 1}, nil
|
||||
case gatewayInputRelative:
|
||||
if len(body) != 4 {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Device: "mouse-relative", Payload: append([]byte(nil), body...)}, nil
|
||||
case gatewayInputUTF8:
|
||||
if len(body) == 0 || len(body) > utf8.UTFMax || !utf8.Valid(body) || utf8.RuneCount(body) != 1 {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Device: "utf8", Payload: append([]byte(nil), body...)}, nil
|
||||
case gatewayInputController:
|
||||
if len(body) != 17 || body[0] > 15 {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
payload := append([]byte(nil), body[1:]...)
|
||||
active := binary.BigEndian.Uint16(payload[:2])
|
||||
if active == 0 && anyNonzero(payload[2:]) {
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Device: "controller", Code: int32(body[0]), Pressed: active != 0, Payload: payload}, nil
|
||||
default:
|
||||
return InputEvent{}, ErrInputMalformed
|
||||
}
|
||||
return InputEvent{Sequence: binary.BigEndian.Uint32(data[4:8]), Code: int32(binary.BigEndian.Uint32(data[8:12])), Pressed: data[12] == 1, Device: string(data[16 : 16+deviceLength]), Payload: append([]byte(nil), data[16+deviceLength:]...)}, nil
|
||||
}
|
||||
|
||||
func anyNonzero(data []byte) bool {
|
||||
for _, value := range data {
|
||||
if value != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user