54 lines
1.6 KiB
Go
54 lines
1.6 KiB
Go
package model
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
)
|
|
|
|
// PeerMessage is an encapsulation that can be used by higher level applications
|
|
type PeerMessage struct {
|
|
// ID **must** only contain alphanumeric characters separated by period.
|
|
ID string // A unique Message ID (primarily used for acknowledgments)
|
|
|
|
// Context **must** only contain alphanumeric characters separated by period.
|
|
Context string // A unique context identifier i.e. im.cwtch.chat
|
|
|
|
// Data can contain anything
|
|
Data []byte // A data packet.
|
|
}
|
|
|
|
// Serialize constructs an efficient serialized representation
|
|
// Format: [ID String] | [Context String] | Binary Data
|
|
func (m *PeerMessage) Serialize() []byte {
|
|
return append(append([]byte(m.ID+"|"), []byte(m.Context+"|")...), m.Data...)
|
|
}
|
|
|
|
// ParsePeerMessage returns either a deserialized PeerMessage or an error if it is malformed
|
|
func ParsePeerMessage(message []byte) (*PeerMessage, error) {
|
|
|
|
// find the identifier prefix
|
|
idTerminator := bytes.IndexByte(message, '|')
|
|
if idTerminator != -1 && idTerminator+1 < len(message) {
|
|
// find the context terminator prefix
|
|
contextbegin := idTerminator + 1
|
|
contextTerminator := bytes.IndexByte(message[contextbegin:], '|')
|
|
if contextTerminator != -1 {
|
|
|
|
// check that we have data
|
|
dataBegin := contextbegin + contextTerminator + 1
|
|
var data []byte
|
|
if dataBegin < len(message) {
|
|
data = message[dataBegin:]
|
|
}
|
|
|
|
// compile the message
|
|
return &PeerMessage{
|
|
ID: string(message[0:idTerminator]),
|
|
Context: string(message[contextbegin : contextbegin+contextTerminator]),
|
|
Data: data,
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, errors.New("invalid message")
|
|
}
|