You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

96 lines
2.6 KiB

package directstream
import (
"bytes"
"encoding/json"
"errors"
"io"
)
const (
Subprotocol = "tera.direct.v1"
MaxControlFrameBytes = 4 * 1024
MaxDataFrameBytes = 64 * 1024
AccessViewer = "viewer"
AccessWriter = "writer"
ControlAuthenticate = "authenticate"
ControlWriterRequest = "writer.request"
ControlWriterRelease = "writer.release"
)
var (
ErrInvalidControlFrame = errors.New("invalid direct stream control frame")
ErrInvalidDataFrame = errors.New("invalid direct stream data frame")
ErrStreamUnauthenticated = errors.New("direct stream is not authenticated")
ErrWriterRequired = errors.New("direct stream writer access is required")
ErrInvalidChannel = errors.New("direct stream channel must be CH01 through CH48")
ErrInvalidAccess = errors.New("direct stream access must be viewer or writer")
)
type ControlFrame struct {
Type string `json:"type"`
Ticket string `json:"ticket,omitempty"`
}
func DecodeControlFrame(payload []byte) (ControlFrame, error) {
if len(payload) == 0 || len(payload) > MaxControlFrameBytes {
return ControlFrame{}, ErrInvalidControlFrame
}
decoder := json.NewDecoder(bytes.NewReader(payload))
decoder.DisallowUnknownFields()
var frame ControlFrame
if err := decoder.Decode(&frame); err != nil {
return ControlFrame{}, ErrInvalidControlFrame
}
var extra any
if err := decoder.Decode(&extra); !errors.Is(err, io.EOF) {
return ControlFrame{}, ErrInvalidControlFrame
}
switch frame.Type {
case ControlAuthenticate:
if frame.Ticket == "" {
return ControlFrame{}, ErrInvalidControlFrame
}
case ControlWriterRequest, ControlWriterRelease:
if frame.Ticket != "" {
return ControlFrame{}, ErrInvalidControlFrame
}
default:
return ControlFrame{}, ErrInvalidControlFrame
}
return frame, nil
}
func ValidateClientData(access string, authenticated bool, payload []byte) error {
if !authenticated {
return ErrStreamUnauthenticated
}
if access != AccessWriter {
return ErrWriterRequired
}
if len(payload) == 0 || len(payload) > MaxDataFrameBytes {
return ErrInvalidDataFrame
}
return nil
}
func ValidateChannel(channel string) error {
if len(channel) != 4 || channel[0] != 'C' || channel[1] != 'H' || channel[2] < '0' || channel[2] > '9' || channel[3] < '0' || channel[3] > '9' {
return ErrInvalidChannel
}
number := int(channel[2]-'0')*10 + int(channel[3]-'0')
if number < 1 || number > 48 {
return ErrInvalidChannel
}
return nil
}
func ValidateAccess(access string) error {
if access != AccessViewer && access != AccessWriter {
return ErrInvalidAccess
}
return nil
}