Factor out serialization/parsing code into protocol.Model
This commit is contained in:
parent
6bb510e39e
commit
ff4249e2bc
|
@ -1,11 +1,9 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"cwtch.im/cwtch/event"
|
"cwtch.im/cwtch/event"
|
||||||
model2 "cwtch.im/cwtch/protocol/model"
|
model2 "cwtch.im/cwtch/protocol/model"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"git.openprivacy.ca/cwtch.im/tapir"
|
"git.openprivacy.ca/cwtch.im/tapir"
|
||||||
"git.openprivacy.ca/cwtch.im/tapir/applications"
|
"git.openprivacy.ca/cwtch.im/tapir/applications"
|
||||||
"git.openprivacy.ca/openprivacy/log"
|
"git.openprivacy.ca/openprivacy/log"
|
||||||
|
@ -103,39 +101,14 @@ func (pa *PeerApp) listen() {
|
||||||
if pa.version.Load() == 0x01 {
|
if pa.version.Load() == 0x01 {
|
||||||
err = json.Unmarshal(message, &packet)
|
err = json.Unmarshal(message, &packet)
|
||||||
} else if pa.version.Load() == 0x02 {
|
} else if pa.version.Load() == 0x02 {
|
||||||
|
parsePacket, parseErr := model2.ParsePeerMessage(message)
|
||||||
// assume the encoding is invalid
|
|
||||||
err = errors.New("invalid message")
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
err = nil
|
|
||||||
|
|
||||||
// check that we have data
|
|
||||||
dataBegin := contextbegin + contextTerminator + 1
|
|
||||||
var data []byte
|
|
||||||
if dataBegin < len(message) {
|
|
||||||
data = message[dataBegin:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile the message
|
|
||||||
packet = model2.PeerMessage{
|
|
||||||
ID: string(message[0:idTerminator]),
|
|
||||||
Context: string(message[contextbegin : contextbegin+contextTerminator]),
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if all else fails...attempt to process this message as a version 1 message
|
// if all else fails...attempt to process this message as a version 1 message
|
||||||
if err != nil {
|
if parseErr != nil {
|
||||||
err = json.Unmarshal(message, &packet)
|
err = json.Unmarshal(message, &packet)
|
||||||
|
} else {
|
||||||
|
packet = *parsePacket
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("invalid version")
|
log.Errorf("invalid version")
|
||||||
pa.OnClose(pa.connection.Hostname())
|
pa.OnClose(pa.connection.Hostname())
|
||||||
|
@ -170,7 +143,7 @@ func (pa *PeerApp) SendMessage(message model2.PeerMessage) error {
|
||||||
|
|
||||||
if pa.version.Load() == 0x02 {
|
if pa.version.Load() == 0x02 {
|
||||||
// treat data as a pre-serialized string, not as a byte array (which will be base64 encoded and bloat the packet size)
|
// treat data as a pre-serialized string, not as a byte array (which will be base64 encoded and bloat the packet size)
|
||||||
serialized = append(append([]byte(message.ID+"|"), []byte(message.Context+"|")...), message.Data...)
|
serialized = message.Serialize()
|
||||||
} else {
|
} else {
|
||||||
serialized, err = json.Marshal(message)
|
serialized, err = json.Marshal(message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,52 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
// PeerMessage is an encapsulation that can be used by higher level applications
|
// PeerMessage is an encapsulation that can be used by higher level applications
|
||||||
type PeerMessage struct {
|
type PeerMessage struct {
|
||||||
ID string // A unique Message ID (primarily used for acknowledgments)
|
// 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
|
Context string // A unique context identifier i.e. im.cwtch.chat
|
||||||
Data []byte // A data packet.
|
|
||||||
|
// Data can contain anything
|
||||||
|
Data []byte // A data packet.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize constructs an efficient serialized representation
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue