mirror of
https://github.com/pikami/cosmium.git
synced 2026-06-12 07:17:06 +01:00
213 lines
6.2 KiB
Go
213 lines
6.2 KiB
Go
package rntbd
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/pikami/cosmium/internal/logger"
|
|
)
|
|
|
|
type RntbdFrame struct {
|
|
ResourceType RntbdResourceType
|
|
OperationType RntbdOperationType
|
|
ActivityId []byte
|
|
RequestHeaders map[RntbdRequestHeader]any
|
|
ResponseHeaders map[RntbdResponseHeaderType]any
|
|
ContextHeaders map[RntbdContextHeader]any
|
|
Payload []byte
|
|
}
|
|
|
|
func ReadFrame(reader *bufio.Reader) (*RntbdFrame, error) {
|
|
sizeBytes := readBytes(reader, 4)
|
|
size := binary.LittleEndian.Uint32(sizeBytes)
|
|
|
|
payload := readBytes(reader, int(size)-4)
|
|
|
|
frame, err := parseFrame_Int(payload, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if payloadPresent, ok := frame.RequestHeaders[RntbdRequestHeaderPayloadPresent]; ok && payloadPresent.([]byte)[0] == 1 {
|
|
payloadSize := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
payload := readBytes(reader, int(payloadSize))
|
|
frame.Payload = payload
|
|
}
|
|
|
|
if payloadPresent, ok := frame.ResponseHeaders[RntbdResponseHeaderPayloadPresent]; ok && payloadPresent.([]byte)[0] == 1 {
|
|
payloadSize := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
payload := readBytes(reader, int(payloadSize))
|
|
frame.Payload = payload
|
|
}
|
|
|
|
return frame, nil
|
|
}
|
|
|
|
func ParseFrame(data []byte, isResponse bool) (*RntbdFrame, error) {
|
|
if len(data) < 4 {
|
|
return nil, fmt.Errorf("data too short")
|
|
}
|
|
|
|
reader := bufio.NewReader(bytes.NewReader(data))
|
|
sizeBytes := readBytes(reader, 4)
|
|
size := binary.LittleEndian.Uint32(sizeBytes)
|
|
|
|
payload := readBytes(reader, int(size)-4)
|
|
frame, err := parseFrame_Int(payload, isResponse)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if payloadPresent, ok := frame.RequestHeaders[RntbdRequestHeaderPayloadPresent]; ok && payloadPresent.([]byte)[0] == 1 {
|
|
payloadSize := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
payload := readBytes(reader, int(payloadSize))
|
|
frame.Payload = payload
|
|
}
|
|
|
|
if payloadPresent, ok := frame.ResponseHeaders[RntbdResponseHeaderPayloadPresent]; ok && payloadPresent.([]byte)[0] == 1 {
|
|
payloadSize := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
payload := readBytes(reader, int(payloadSize))
|
|
frame.Payload = payload
|
|
}
|
|
|
|
leftOverBytes, err := io.ReadAll(reader)
|
|
if err != nil {
|
|
logger.ErrorLn("Error reading leftOverBytes:", err)
|
|
}
|
|
|
|
if len(leftOverBytes) > 0 {
|
|
logger.ErrorLn("Left over bytes:", hex.EncodeToString(leftOverBytes))
|
|
}
|
|
|
|
return frame, nil
|
|
}
|
|
|
|
func parseFrame_Int(data []byte, isResponse bool) (*RntbdFrame, error) {
|
|
payloadReader := bufio.NewReader(bytes.NewReader(data))
|
|
|
|
resourceTypeBytes := readBytes(payloadReader, 2)
|
|
resourceType := binary.LittleEndian.Uint16(resourceTypeBytes)
|
|
|
|
operationTypeBytes := readBytes(payloadReader, 2)
|
|
operationType := RntbdOperationType(binary.LittleEndian.Uint16(operationTypeBytes))
|
|
|
|
activityIdBytes := readBytes(payloadReader, 16)
|
|
|
|
requestHeaders := make(map[RntbdRequestHeader]any)
|
|
responseHeaders := make(map[RntbdResponseHeaderType]any)
|
|
contextHeaders := make(map[RntbdContextHeader]any)
|
|
for {
|
|
if _, err := payloadReader.Peek(1); err != nil {
|
|
break
|
|
}
|
|
|
|
headerIdBytes := readBytes(payloadReader, 2)
|
|
headerId := binary.LittleEndian.Uint16(headerIdBytes)
|
|
|
|
token, err := parseRntbdToken(payloadReader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resourceType == uint16(RntbdResourceTypeConnection) {
|
|
contextHeaders[RntbdContextHeader(headerId)] = token
|
|
} else if isResponse {
|
|
responseHeaders[RntbdResponseHeaderType(headerId)] = token
|
|
} else {
|
|
requestHeaders[RntbdRequestHeader(headerId)] = token
|
|
}
|
|
}
|
|
|
|
return &RntbdFrame{
|
|
ResourceType: RntbdResourceType(resourceType),
|
|
OperationType: RntbdOperationType(operationType),
|
|
ActivityId: activityIdBytes,
|
|
RequestHeaders: requestHeaders,
|
|
ResponseHeaders: responseHeaders,
|
|
ContextHeaders: contextHeaders,
|
|
}, nil
|
|
}
|
|
|
|
func parseRntbdToken(reader *bufio.Reader) (any, error) {
|
|
tokenTypeBytes := readBytes(reader, 1)
|
|
tokenType := RntbdTokenType(tokenTypeBytes[0])
|
|
|
|
switch tokenType {
|
|
case RntbdTokenTypeByte:
|
|
token := readBytes(reader, 1)
|
|
return token, nil
|
|
case RntbdTokenTypeUShort:
|
|
token := binary.LittleEndian.Uint16(readBytes(reader, 2))
|
|
return token, nil
|
|
case RntbdTokenTypeULong:
|
|
token := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
return token, nil
|
|
case RntbdTokenTypeLong:
|
|
token := int32(binary.LittleEndian.Uint32(readBytes(reader, 4)))
|
|
return token, nil
|
|
case RntbdTokenTypeULongLong:
|
|
token := binary.LittleEndian.Uint64(readBytes(reader, 8))
|
|
return token, nil
|
|
case RntbdTokenTypeLongLong:
|
|
token := int64(binary.LittleEndian.Uint64(readBytes(reader, 8)))
|
|
return token, nil
|
|
case RntbdTokenTypeGuid:
|
|
token := readBytes(reader, 16)
|
|
return token, nil
|
|
case RntbdTokenTypeSmallString:
|
|
lengthBytes := readBytes(reader, 1)
|
|
length := uint8(lengthBytes[0])
|
|
token := readBytes(reader, int(length))
|
|
return string(token), nil
|
|
case RntbdTokenTypeString:
|
|
length := binary.LittleEndian.Uint16(readBytes(reader, 2))
|
|
token := readBytes(reader, int(length))
|
|
return string(token), nil
|
|
case RntbdTokenTypeULongString:
|
|
length := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
token := readBytes(reader, int(length))
|
|
return string(token), nil
|
|
case RntbdTokenTypeSmallBytes:
|
|
lengthBytes := readBytes(reader, 1)
|
|
length := uint8(lengthBytes[0])
|
|
token := readBytes(reader, int(length))
|
|
return token, nil
|
|
case RntbdTokenTypeBytes:
|
|
length := binary.LittleEndian.Uint16(readBytes(reader, 2))
|
|
token := readBytes(reader, int(length))
|
|
return token, nil
|
|
case RntbdTokenTypeULongBytes:
|
|
length := binary.LittleEndian.Uint32(readBytes(reader, 4))
|
|
token := readBytes(reader, int(length))
|
|
return token, nil
|
|
case RntbdTokenTypeFloat:
|
|
// I can't be bothered to implement this, let's just return a byte array
|
|
token := readBytes(reader, 4)
|
|
return token, nil
|
|
case RntbdTokenTypeDouble:
|
|
// I can't be bothered to implement this, let's just return a byte array
|
|
token := readBytes(reader, 8)
|
|
return token, nil
|
|
case RntbdTokenTypeInvalid:
|
|
return nil, fmt.Errorf("invalid token type")
|
|
}
|
|
|
|
return nil, fmt.Errorf("invalid token type")
|
|
}
|
|
|
|
func readBytes(reader *bufio.Reader, n int) []byte {
|
|
bytes := make([]byte, n)
|
|
_, err := io.ReadFull(reader, bytes)
|
|
if err != nil {
|
|
logger.ErrorLn("Error reading bytes:", err)
|
|
os.Exit(0)
|
|
}
|
|
|
|
return bytes
|
|
}
|