Initial RNTBD server implementation

This commit is contained in:
Pijus Kamandulis
2026-06-11 22:43:05 +03:00
parent 36fd7f48cc
commit be761badae
12 changed files with 1477 additions and 1 deletions
+138
View File
@@ -0,0 +1,138 @@
package rntbd
import (
"bytes"
"encoding/binary"
)
type RntbdResponseFrame struct {
StatusCode uint16
ResourceType RntbdResourceType
ActivityId []byte
ResponseHeaders []RntbdResponseHeader
Payload []byte
}
type RntbdResponseHeader struct {
HeaderId uint16
TokenType RntbdTokenType
TokenValue any
}
type RntbdResponseFrameBuilder struct {
frame RntbdResponseFrame
}
func (b *RntbdResponseFrameBuilder) AddHeader(headerId uint16, tokenType RntbdTokenType, tokenValue any) {
b.frame.ResponseHeaders = append(b.frame.ResponseHeaders, RntbdResponseHeader{
HeaderId: headerId,
TokenType: tokenType,
TokenValue: tokenValue,
})
}
func (b *RntbdResponseFrameBuilder) AddPayload(payload []byte) {
b.frame.Payload = payload
}
func (b *RntbdResponseFrameBuilder) SetStatusCode(statusCode uint16) {
b.frame.StatusCode = statusCode
}
func (b *RntbdResponseFrameBuilder) SetResourceType(resourceType RntbdResourceType) {
b.frame.ResourceType = resourceType
}
func (b *RntbdResponseFrameBuilder) SetActivityId(activityId []byte) {
b.frame.ActivityId = activityId
}
func (b *RntbdResponseFrameBuilder) Build() *RntbdResponseFrame {
return &b.frame
}
func (f *RntbdResponseFrame) ToBytes() []byte {
var buffer bytes.Buffer
binary.Write(&buffer, binary.LittleEndian, f.StatusCode)
binary.Write(&buffer, binary.LittleEndian, uint16(f.ResourceType))
binary.Write(&buffer, binary.LittleEndian, f.ActivityId)
for _, header := range f.ResponseHeaders {
binary.Write(&buffer, binary.LittleEndian, header.HeaderId)
binary.Write(&buffer, binary.LittleEndian, uint8(header.TokenType))
switch header.TokenType {
case RntbdTokenTypeByte:
buffer.Write(header.TokenValue.([]byte))
case RntbdTokenTypeUShort:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(uint16))
case RntbdTokenTypeULong:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(uint32))
case RntbdTokenTypeLong:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(int32))
case RntbdTokenTypeULongLong:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(uint64))
case RntbdTokenTypeLongLong:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(int64))
case RntbdTokenTypeGuid:
buffer.Write(header.TokenValue.([]byte))
case RntbdTokenTypeSmallString:
binary.Write(&buffer, binary.LittleEndian, uint8(len(header.TokenValue.(string))))
buffer.WriteString(header.TokenValue.(string))
case RntbdTokenTypeString:
binary.Write(&buffer, binary.LittleEndian, uint16(len(header.TokenValue.(string))))
buffer.WriteString(header.TokenValue.(string))
case RntbdTokenTypeULongString:
binary.Write(&buffer, binary.LittleEndian, uint32(len(header.TokenValue.(string))))
buffer.WriteString(header.TokenValue.(string))
case RntbdTokenTypeSmallBytes:
binary.Write(&buffer, binary.LittleEndian, uint8(len(header.TokenValue.([]byte))))
buffer.Write(header.TokenValue.([]byte))
case RntbdTokenTypeBytes:
binary.Write(&buffer, binary.LittleEndian, uint16(len(header.TokenValue.([]byte))))
buffer.Write(header.TokenValue.([]byte))
case RntbdTokenTypeULongBytes:
binary.Write(&buffer, binary.LittleEndian, uint32(len(header.TokenValue.([]byte))))
buffer.Write(header.TokenValue.([]byte))
case RntbdTokenTypeFloat:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(float32))
case RntbdTokenTypeDouble:
binary.Write(&buffer, binary.LittleEndian, header.TokenValue.(float64))
case RntbdTokenTypeInvalid:
panic("invalid token type")
default:
panic("invalid token type")
}
}
payloadSize := uint32(0)
if len(f.Payload) > 0 {
payloadSize = uint32(len(f.Payload)) + 4
}
frameSize := uint32(buffer.Len()) + 4
result := make([]byte, frameSize+payloadSize)
binary.LittleEndian.PutUint32(result, frameSize)
copy(result[4:], buffer.Bytes())
if len(f.Payload) > 0 {
binary.LittleEndian.PutUint32(result[frameSize:], payloadSize-4)
copy(result[frameSize+4:], f.Payload)
}
return result
}
func buildContextFrame(requestFrame *RntbdFrame) []byte {
builder := RntbdResponseFrameBuilder{}
builder.SetStatusCode(200)
builder.SetResourceType(RntbdResourceTypeConnection)
builder.SetActivityId(requestFrame.ActivityId)
builder.AddHeader(uint16(RntbdContextHeaderServerAgent), RntbdTokenTypeSmallString, "DocumentDB Server")
builder.AddHeader(uint16(RntbdContextHeaderServerVersion), RntbdTokenTypeSmallString, " version=2.14.0.0")
builder.AddHeader(uint16(RntbdContextHeaderIdleTimeoutInSeconds), RntbdTokenTypeULong, uint32(120))
builder.AddHeader(uint16(RntbdContextHeaderUnauthenticatedTimeoutInSeconds), RntbdTokenTypeULong, uint32(25))
return builder.Build().ToBytes()
}