Negotiate Lower Bandwidth / Higher Density Packets for Peers #428

Merged
erinn merged 5 commits from fastercwtch into master 2022-01-26 20:02:50 +00:00
2 changed files with 52 additions and 35 deletions
Showing only changes of commit ff4249e2bc - Show all commits

View File

@ -1,11 +1,9 @@
package connections
import (
"bytes"
"cwtch.im/cwtch/event"
model2 "cwtch.im/cwtch/protocol/model"
"encoding/json"
"errors"
"git.openprivacy.ca/cwtch.im/tapir"
"git.openprivacy.ca/cwtch.im/tapir/applications"
"git.openprivacy.ca/openprivacy/log"
@ -103,39 +101,14 @@ func (pa *PeerApp) listen() {
if pa.version.Load() == 0x01 {
err = json.Unmarshal(message, &packet)
} else if pa.version.Load() == 0x02 {
// 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,
}
}
}
parsePacket, parseErr := model2.ParsePeerMessage(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)
sarah marked this conversation as resolved Outdated
Outdated
Review

this is a big chunk, might be best moved to a function?

this is a big chunk, might be best moved to a function?
} else {
packet = *parsePacket
}
sarah marked this conversation as resolved Outdated
Outdated
Review

I'm a little nervous mixing unspecified Ids, event IDs are strings, even tho they should be populated by int -> strings only? its not type specified anywhere so someone could make it binary or strings and either could generate a '|', contexts are strings that right now use '.' as seperators...
we have a lot of string manipulation based on not well documented seperators and we're mixing it with binary data.

could we use Pascal style strings here? neither id nor context should exceed 256 bytes so just have each lead with a byte of length to parse?

I'm a little nervous mixing unspecified Ids, event IDs are strings, even tho they should be populated by int -> strings only? its not type specified anywhere so someone could make it binary or strings and either could generate a '|', contexts are strings that right now use '.' as seperators... we have a lot of string manipulation based on not well documented seperators and we're mixing it with binary data. could we use Pascal style strings here? neither id nor context should exceed 256 bytes so just have each lead with a byte of length to parse?
} else {
log.Errorf("invalid version")
pa.OnClose(pa.connection.Hostname())
@ -170,7 +143,7 @@ func (pa *PeerApp) SendMessage(message model2.PeerMessage) error {
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)
serialized = append(append([]byte(message.ID+"|"), []byte(message.Context+"|")...), message.Data...)
serialized = message.Serialize()
} else {
serialized, err = json.Marshal(message)
}

View File

@ -1,8 +1,52 @@
package model
import (
"bytes"
"errors"
)
// PeerMessage is an encapsulation that can be used by higher level applications
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
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")
}