use timecache

This commit is contained in:
Jeromy 2016-09-10 20:47:12 -07:00
parent 17e835cd17
commit f3f2cb2c82
7 changed files with 430 additions and 138 deletions

21
.travis.yml Normal file
View File

@ -0,0 +1,21 @@
os:
- linux
- osx
language: go
go:
- 1.7
install: true
script:
- make deps
- go test ./...
cache:
directories:
- $GOPATH/src/gx
notifications:
email: false

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Jeromy Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
gx:
go get -u github.com/whyrusleeping/gx
go get -u github.com/whyrusleeping/gx-go
deps: gx
gx --verbose install --global
gx-go rewrite

View File

@ -3,6 +3,7 @@ package floodsub
import ( import (
"bufio" "bufio"
"context" "context"
"encoding/binary"
"fmt" "fmt"
"io" "io"
"sync" "sync"
@ -17,6 +18,7 @@ import (
host "github.com/libp2p/go-libp2p/p2p/host" host "github.com/libp2p/go-libp2p/p2p/host"
inet "github.com/libp2p/go-libp2p/p2p/net" inet "github.com/libp2p/go-libp2p/p2p/net"
protocol "github.com/libp2p/go-libp2p/p2p/protocol" protocol "github.com/libp2p/go-libp2p/p2p/protocol"
timecache "github.com/whyrusleeping/timecache"
) )
const ID = protocol.ID("/floodsub/1.0.0") const ID = protocol.ID("/floodsub/1.0.0")
@ -33,16 +35,16 @@ type PubSub struct {
host host.Host host host.Host
incoming chan *RPC incoming chan *RPC
outgoing chan *RPC publish chan *Message
newPeers chan inet.Stream newPeers chan inet.Stream
peerDead chan peer.ID peerDead chan peer.ID
myTopics map[string]chan *Message myTopics map[string]chan *Message
pubsubLk sync.Mutex pubsubLk sync.Mutex
topics map[string]map[peer.ID]struct{} topics map[string]map[peer.ID]struct{}
peers map[peer.ID]chan *RPC peers map[peer.ID]chan *RPC
lastMsg map[peer.ID]uint64 seenMessages *timecache.TimeCache
addSub chan *addSub addSub chan *addSub
@ -66,17 +68,17 @@ type RPC struct {
func NewFloodSub(ctx context.Context, h host.Host) *PubSub { func NewFloodSub(ctx context.Context, h host.Host) *PubSub {
ps := &PubSub{ ps := &PubSub{
host: h, host: h,
ctx: ctx, ctx: ctx,
incoming: make(chan *RPC, 32), incoming: make(chan *RPC, 32),
outgoing: make(chan *RPC), publish: make(chan *Message),
newPeers: make(chan inet.Stream), newPeers: make(chan inet.Stream),
peerDead: make(chan peer.ID), peerDead: make(chan peer.ID),
addSub: make(chan *addSub), addSub: make(chan *addSub),
myTopics: make(map[string]chan *Message), myTopics: make(map[string]chan *Message),
topics: make(map[string]map[peer.ID]struct{}), topics: make(map[string]map[peer.ID]struct{}),
peers: make(map[peer.ID]chan *RPC), peers: make(map[peer.ID]chan *RPC),
lastMsg: make(map[peer.ID]uint64), seenMessages: timecache.NewTimeCache(time.Second * 30),
} }
h.SetStreamHandler(ID, ps.handleNewStream) h.SetStreamHandler(ID, ps.handleNewStream)
@ -90,9 +92,12 @@ func NewFloodSub(ctx context.Context, h host.Host) *PubSub {
func (p *PubSub) getHelloPacket() *RPC { func (p *PubSub) getHelloPacket() *RPC {
var rpc RPC var rpc RPC
for t, _ := range p.myTopics { for t, _ := range p.myTopics {
rpc.Topics = append(rpc.Topics, t) as := &pb.RPC_SubOpts{
Topicid: proto.String(t),
Subscribe: proto.Bool(true),
}
rpc.Subscriptions = append(rpc.Subscriptions, as)
} }
rpc.Type = &AddSubMessageType
return &rpc return &rpc
} }
@ -188,23 +193,15 @@ func (p *PubSub) processLoop(ctx context.Context) {
if err != nil { if err != nil {
log.Error("handling RPC: ", err) log.Error("handling RPC: ", err)
} }
case rpc := <-p.outgoing: case msg := <-p.publish:
switch rpc.GetType() { err := p.recvMessage(msg.Message)
case AddSubMessageType, UnsubMessageType: if err != nil {
for _, mch := range p.peers { log.Error("error receiving message: ", err)
mch <- rpc }
}
case PubMessageType:
//fmt.Println("publishing outgoing message")
err := p.recvMessage(rpc)
if err != nil {
log.Error("error receiving message: ", err)
}
err = p.publishMessage(rpc) err = p.publishMessage(p.host.ID(), msg.Message)
if err != nil { if err != nil {
log.Error("publishing message: ", err) log.Error("publishing message: ", err)
}
} }
case <-ctx.Done(): case <-ctx.Done():
log.Info("pubsub processloop shutting down") log.Info("pubsub processloop shutting down")
@ -213,22 +210,14 @@ func (p *PubSub) processLoop(ctx context.Context) {
} }
} }
func (p *PubSub) handleSubscriptionChange(sub *addSub) { func (p *PubSub) handleSubscriptionChange(sub *addSub) {
ch, ok := p.myTopics[sub.topic]
out := &RPC{ subopt := pb.RPC_SubOpts{
RPC: pb.RPC{ Topicid: &sub.topic,
Topics: []string{sub.topic}, Subscribe: &sub.sub,
},
} }
if sub.cancel { ch, ok := p.myTopics[sub.topic]
if !ok { if sub.sub {
return
}
close(ch)
delete(p.myTopics, sub.topic)
out.Type = &UnsubMessageType
} else {
if ok { if ok {
// we don't allow multiple subs per topic at this point // we don't allow multiple subs per topic at this point
sub.resp <- nil sub.resp <- nil
@ -238,27 +227,58 @@ func (p *PubSub) handleSubscriptionChange(sub *addSub) {
resp := make(chan *Message, 16) resp := make(chan *Message, 16)
p.myTopics[sub.topic] = resp p.myTopics[sub.topic] = resp
sub.resp <- resp sub.resp <- resp
out.Type = &AddSubMessageType } else {
if !ok {
return
}
close(ch)
delete(p.myTopics, sub.topic)
} }
go func() { out := &RPC{
p.outgoing <- out RPC: pb.RPC{
}() Subscriptions: []*pb.RPC_SubOpts{
&subopt,
},
},
}
for _, peer := range p.peers {
peer <- out
}
} }
func (p *PubSub) recvMessage(rpc *RPC) error { func (p *PubSub) recvMessage(msg *pb.Message) error {
subch, ok := p.myTopics[rpc.Msg.GetTopic()] if len(msg.GetTopicIDs()) > 1 {
return fmt.Errorf("Dont yet handle multiple topics per message")
}
if len(msg.GetTopicIDs()) == 0 {
return fmt.Errorf("no topic on received message")
}
topic := msg.GetTopicIDs()[0]
subch, ok := p.myTopics[topic]
if ok { if ok {
//fmt.Println("writing out to subscriber!") subch <- &Message{msg}
subch <- &Message{rpc.Msg} } else {
log.Error("received message we we'rent subscribed to")
} }
return nil return nil
} }
func (p *PubSub) seenMessage(id string) bool {
return p.seenMessages.Has(id)
}
func (p *PubSub) markSeen(id string) {
p.seenMessages.Add(id)
}
func (p *PubSub) handleIncomingRPC(rpc *RPC) error { func (p *PubSub) handleIncomingRPC(rpc *RPC) error {
switch rpc.GetType() { for _, subopt := range rpc.GetSubscriptions() {
case AddSubMessageType: t := subopt.GetTopicid()
for _, t := range rpc.Topics { if subopt.GetSubscribe() {
tmap, ok := p.topics[t] tmap, ok := p.topics[t]
if !ok { if !ok {
tmap = make(map[peer.ID]struct{}) tmap = make(map[peer.ID]struct{})
@ -266,28 +286,22 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) error {
} }
tmap[rpc.from] = struct{}{} tmap[rpc.from] = struct{}{}
} } else {
case UnsubMessageType:
for _, t := range rpc.Topics {
tmap, ok := p.topics[t] tmap, ok := p.topics[t]
if !ok { if !ok {
return nil continue
} }
delete(tmap, rpc.from) delete(tmap, rpc.from)
} }
case PubMessageType: }
if rpc.Msg == nil {
return fmt.Errorf("nil pub message")
}
msg := &Message{rpc.Msg} for _, pmsg := range rpc.GetPublish() {
msg := &Message{pmsg}
// Note: Obviously this is an incredibly insecure way of id := msg.Message.GetFrom() + string(msg.GetSeqno())
// filtering out "messages we've already seen". But it works for a
// cool demo, so i'm not gonna waste time thinking about it any more if p.seenMessage(id) {
if p.lastMsg[msg.GetFrom()] >= msg.GetSeqno() { continue
//log.Error("skipping 'old' message")
return nil
} }
if msg.GetFrom() == p.host.ID() { if msg.GetFrom() == p.host.ID() {
@ -295,13 +309,13 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) error {
return nil return nil
} }
p.lastMsg[msg.GetFrom()] = msg.GetSeqno() p.markSeen(id)
if err := p.recvMessage(rpc); err != nil { if err := p.recvMessage(pmsg); err != nil {
log.Error("error receiving message: ", err) log.Error("error receiving message: ", err)
} }
err := p.publishMessage(rpc) err := p.publishMessage(rpc.from, pmsg)
if err != nil { if err != nil {
log.Error("publish message: ", err) log.Error("publish message: ", err)
} }
@ -309,14 +323,20 @@ func (p *PubSub) handleIncomingRPC(rpc *RPC) error {
return nil return nil
} }
func (p *PubSub) publishMessage(rpc *RPC) error { func (p *PubSub) publishMessage(from peer.ID, msg *pb.Message) error {
tmap, ok := p.topics[rpc.Msg.GetTopic()] if len(msg.GetTopicIDs()) != 1 {
return fmt.Errorf("don't support publishing to multiple topics in a single message")
}
tmap, ok := p.topics[msg.GetTopicIDs()[0]]
if !ok { if !ok {
return nil return nil
} }
out := &RPC{RPC: pb.RPC{Publish: []*pb.Message{msg}}}
for pid, _ := range tmap { for pid, _ := range tmap {
if pid == rpc.from || pid == peer.ID(rpc.Msg.GetFrom()) { if pid == from || pid == peer.ID(msg.GetFrom()) {
continue continue
} }
@ -325,23 +345,38 @@ func (p *PubSub) publishMessage(rpc *RPC) error {
continue continue
} }
go func() { mch <- rpc }() go func() { mch <- out }()
} }
return nil return nil
} }
type addSub struct { type addSub struct {
topic string topic string
cancel bool sub bool
resp chan chan *Message resp chan chan *Message
} }
func (p *PubSub) Subscribe(topic string) (<-chan *Message, error) { func (p *PubSub) Subscribe(topic string) (<-chan *Message, error) {
return p.SubscribeComplicated(&pb.TopicDescriptor{
Name: proto.String(topic),
})
}
func (p *PubSub) SubscribeComplicated(td *pb.TopicDescriptor) (<-chan *Message, error) {
if td.GetAuth().GetMode() != pb.TopicDescriptor_AuthOpts_NONE {
return nil, fmt.Errorf("Auth method not yet supported")
}
if td.GetEnc().GetMode() != pb.TopicDescriptor_EncOpts_NONE {
return nil, fmt.Errorf("Encryption method not yet supported")
}
resp := make(chan chan *Message) resp := make(chan chan *Message)
p.addSub <- &addSub{ p.addSub <- &addSub{
topic: topic, topic: td.GetName(),
resp: resp, resp: resp,
sub: true,
} }
outch := <-resp outch := <-resp
@ -354,22 +389,21 @@ func (p *PubSub) Subscribe(topic string) (<-chan *Message, error) {
func (p *PubSub) Unsub(topic string) { func (p *PubSub) Unsub(topic string) {
p.addSub <- &addSub{ p.addSub <- &addSub{
topic: topic, topic: topic,
cancel: true, sub: false,
} }
} }
func (p *PubSub) Publish(topic string, data []byte) error { func (p *PubSub) Publish(topic string, data []byte) error {
seqno := uint64(time.Now().UnixNano()) seqno := make([]byte, 8)
p.outgoing <- &RPC{ binary.BigEndian.PutUint64(seqno, uint64(time.Now().UnixNano()))
RPC: pb.RPC{
Msg: &pb.Message{ p.publish <- &Message{
Data: data, &pb.Message{
Topic: &topic, Data: data,
From: proto.String(string(p.host.ID())), TopicIDs: []string{topic},
Seqno: &seqno, From: proto.String(string(p.host.ID())),
}, Seqno: seqno,
Type: &PubMessageType,
}, },
} }
return nil return nil

View File

@ -18,6 +18,12 @@
"hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV", "hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV",
"name": "gogo-protobuf", "name": "gogo-protobuf",
"version": "0.0.0" "version": "0.0.0"
},
{
"author": "whyrusleeping",
"hash": "QmYftoT56eEfUBTD3erR6heXuPSUhGRezSmhSU8LeczP8b",
"name": "timecache",
"version": "1.0.0"
} }
], ],
"gxVersion": "0.9.0", "gxVersion": "0.9.0",

View File

@ -11,6 +11,7 @@ It is generated from these files:
It has these top-level messages: It has these top-level messages:
RPC RPC
Message Message
TopicDescriptor
*/ */
package floodsub_pb package floodsub_pb
@ -23,44 +24,132 @@ var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
type TopicDescriptor_AuthOpts_AuthMode int32
const (
TopicDescriptor_AuthOpts_NONE TopicDescriptor_AuthOpts_AuthMode = 0
TopicDescriptor_AuthOpts_KEY TopicDescriptor_AuthOpts_AuthMode = 1
TopicDescriptor_AuthOpts_WOT TopicDescriptor_AuthOpts_AuthMode = 2
)
var TopicDescriptor_AuthOpts_AuthMode_name = map[int32]string{
0: "NONE",
1: "KEY",
2: "WOT",
}
var TopicDescriptor_AuthOpts_AuthMode_value = map[string]int32{
"NONE": 0,
"KEY": 1,
"WOT": 2,
}
func (x TopicDescriptor_AuthOpts_AuthMode) Enum() *TopicDescriptor_AuthOpts_AuthMode {
p := new(TopicDescriptor_AuthOpts_AuthMode)
*p = x
return p
}
func (x TopicDescriptor_AuthOpts_AuthMode) String() string {
return proto.EnumName(TopicDescriptor_AuthOpts_AuthMode_name, int32(x))
}
func (x *TopicDescriptor_AuthOpts_AuthMode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(TopicDescriptor_AuthOpts_AuthMode_value, data, "TopicDescriptor_AuthOpts_AuthMode")
if err != nil {
return err
}
*x = TopicDescriptor_AuthOpts_AuthMode(value)
return nil
}
type TopicDescriptor_EncOpts_EncMode int32
const (
TopicDescriptor_EncOpts_NONE TopicDescriptor_EncOpts_EncMode = 0
TopicDescriptor_EncOpts_SHAREDKEY TopicDescriptor_EncOpts_EncMode = 1
TopicDescriptor_EncOpts_WOT TopicDescriptor_EncOpts_EncMode = 2
)
var TopicDescriptor_EncOpts_EncMode_name = map[int32]string{
0: "NONE",
1: "SHAREDKEY",
2: "WOT",
}
var TopicDescriptor_EncOpts_EncMode_value = map[string]int32{
"NONE": 0,
"SHAREDKEY": 1,
"WOT": 2,
}
func (x TopicDescriptor_EncOpts_EncMode) Enum() *TopicDescriptor_EncOpts_EncMode {
p := new(TopicDescriptor_EncOpts_EncMode)
*p = x
return p
}
func (x TopicDescriptor_EncOpts_EncMode) String() string {
return proto.EnumName(TopicDescriptor_EncOpts_EncMode_name, int32(x))
}
func (x *TopicDescriptor_EncOpts_EncMode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(TopicDescriptor_EncOpts_EncMode_value, data, "TopicDescriptor_EncOpts_EncMode")
if err != nil {
return err
}
*x = TopicDescriptor_EncOpts_EncMode(value)
return nil
}
type RPC struct { type RPC struct {
Type *string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` Subscriptions []*RPC_SubOpts `protobuf:"bytes,1,rep,name=subscriptions" json:"subscriptions,omitempty"`
Topics []string `protobuf:"bytes,2,rep,name=topics" json:"topics,omitempty"` Publish []*Message `protobuf:"bytes,2,rep,name=publish" json:"publish,omitempty"`
Msg *Message `protobuf:"bytes,3,opt,name=msg" json:"msg,omitempty"` XXX_unrecognized []byte `json:"-"`
XXX_unrecognized []byte `json:"-"`
} }
func (m *RPC) Reset() { *m = RPC{} } func (m *RPC) Reset() { *m = RPC{} }
func (m *RPC) String() string { return proto.CompactTextString(m) } func (m *RPC) String() string { return proto.CompactTextString(m) }
func (*RPC) ProtoMessage() {} func (*RPC) ProtoMessage() {}
func (m *RPC) GetType() string { func (m *RPC) GetSubscriptions() []*RPC_SubOpts {
if m != nil && m.Type != nil { if m != nil {
return *m.Type return m.Subscriptions
}
return nil
}
func (m *RPC) GetPublish() []*Message {
if m != nil {
return m.Publish
}
return nil
}
type RPC_SubOpts struct {
Subscribe *bool `protobuf:"varint,1,opt,name=subscribe" json:"subscribe,omitempty"`
Topicid *string `protobuf:"bytes,2,opt,name=topicid" json:"topicid,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *RPC_SubOpts) Reset() { *m = RPC_SubOpts{} }
func (m *RPC_SubOpts) String() string { return proto.CompactTextString(m) }
func (*RPC_SubOpts) ProtoMessage() {}
func (m *RPC_SubOpts) GetSubscribe() bool {
if m != nil && m.Subscribe != nil {
return *m.Subscribe
}
return false
}
func (m *RPC_SubOpts) GetTopicid() string {
if m != nil && m.Topicid != nil {
return *m.Topicid
} }
return "" return ""
} }
func (m *RPC) GetTopics() []string {
if m != nil {
return m.Topics
}
return nil
}
func (m *RPC) GetMsg() *Message {
if m != nil {
return m.Msg
}
return nil
}
type Message struct { type Message struct {
From *string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` From *string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"`
Seqno *uint64 `protobuf:"varint,3,opt,name=seqno" json:"seqno,omitempty"` Seqno []byte `protobuf:"bytes,3,opt,name=seqno" json:"seqno,omitempty"`
Topic *string `protobuf:"bytes,4,opt,name=topic" json:"topic,omitempty"` TopicIDs []string `protobuf:"bytes,4,rep,name=topicIDs" json:"topicIDs,omitempty"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
} }
func (m *Message) Reset() { *m = Message{} } func (m *Message) Reset() { *m = Message{} }
@ -81,21 +170,108 @@ func (m *Message) GetData() []byte {
return nil return nil
} }
func (m *Message) GetSeqno() uint64 { func (m *Message) GetSeqno() []byte {
if m != nil && m.Seqno != nil { if m != nil {
return *m.Seqno return m.Seqno
} }
return 0 return nil
} }
func (m *Message) GetTopic() string { func (m *Message) GetTopicIDs() []string {
if m != nil && m.Topic != nil { if m != nil {
return *m.Topic return m.TopicIDs
}
return nil
}
// topicID = hash(topicDescriptor); (not the topic.name)
type TopicDescriptor struct {
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Auth *TopicDescriptor_AuthOpts `protobuf:"bytes,2,opt,name=auth" json:"auth,omitempty"`
Enc *TopicDescriptor_EncOpts `protobuf:"bytes,3,opt,name=enc" json:"enc,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *TopicDescriptor) Reset() { *m = TopicDescriptor{} }
func (m *TopicDescriptor) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor) ProtoMessage() {}
func (m *TopicDescriptor) GetName() string {
if m != nil && m.Name != nil {
return *m.Name
} }
return "" return ""
} }
func (m *TopicDescriptor) GetAuth() *TopicDescriptor_AuthOpts {
if m != nil {
return m.Auth
}
return nil
}
func (m *TopicDescriptor) GetEnc() *TopicDescriptor_EncOpts {
if m != nil {
return m.Enc
}
return nil
}
type TopicDescriptor_AuthOpts struct {
Mode *TopicDescriptor_AuthOpts_AuthMode `protobuf:"varint,1,opt,name=mode,enum=floodsub.pb.TopicDescriptor_AuthOpts_AuthMode" json:"mode,omitempty"`
Keys [][]byte `protobuf:"bytes,2,rep,name=keys" json:"keys,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *TopicDescriptor_AuthOpts) Reset() { *m = TopicDescriptor_AuthOpts{} }
func (m *TopicDescriptor_AuthOpts) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor_AuthOpts) ProtoMessage() {}
func (m *TopicDescriptor_AuthOpts) GetMode() TopicDescriptor_AuthOpts_AuthMode {
if m != nil && m.Mode != nil {
return *m.Mode
}
return TopicDescriptor_AuthOpts_NONE
}
func (m *TopicDescriptor_AuthOpts) GetKeys() [][]byte {
if m != nil {
return m.Keys
}
return nil
}
type TopicDescriptor_EncOpts struct {
Mode *TopicDescriptor_EncOpts_EncMode `protobuf:"varint,1,opt,name=mode,enum=floodsub.pb.TopicDescriptor_EncOpts_EncMode" json:"mode,omitempty"`
KeyHashes [][]byte `protobuf:"bytes,2,rep,name=keyHashes" json:"keyHashes,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *TopicDescriptor_EncOpts) Reset() { *m = TopicDescriptor_EncOpts{} }
func (m *TopicDescriptor_EncOpts) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor_EncOpts) ProtoMessage() {}
func (m *TopicDescriptor_EncOpts) GetMode() TopicDescriptor_EncOpts_EncMode {
if m != nil && m.Mode != nil {
return *m.Mode
}
return TopicDescriptor_EncOpts_NONE
}
func (m *TopicDescriptor_EncOpts) GetKeyHashes() [][]byte {
if m != nil {
return m.KeyHashes
}
return nil
}
func init() { func init() {
proto.RegisterType((*RPC)(nil), "floodsub.pb.RPC") proto.RegisterType((*RPC)(nil), "floodsub.pb.RPC")
proto.RegisterType((*RPC_SubOpts)(nil), "floodsub.pb.RPC.SubOpts")
proto.RegisterType((*Message)(nil), "floodsub.pb.Message") proto.RegisterType((*Message)(nil), "floodsub.pb.Message")
proto.RegisterType((*TopicDescriptor)(nil), "floodsub.pb.TopicDescriptor")
proto.RegisterType((*TopicDescriptor_AuthOpts)(nil), "floodsub.pb.TopicDescriptor.AuthOpts")
proto.RegisterType((*TopicDescriptor_EncOpts)(nil), "floodsub.pb.TopicDescriptor.EncOpts")
proto.RegisterEnum("floodsub.pb.TopicDescriptor_AuthOpts_AuthMode", TopicDescriptor_AuthOpts_AuthMode_name, TopicDescriptor_AuthOpts_AuthMode_value)
proto.RegisterEnum("floodsub.pb.TopicDescriptor_EncOpts_EncMode", TopicDescriptor_EncOpts_EncMode_name, TopicDescriptor_EncOpts_EncMode_value)
} }

View File

@ -1,20 +1,47 @@
package floodsub.pb; package floodsub.pb;
message RPC { message RPC {
optional string type = 1; repeated SubOpts subscriptions = 1;
repeated Message publish = 2;
repeated string topics = 2; message SubOpts {
optional bool subscribe = 1; // subscribe or unsubcribe
optional Message msg = 3; optional string topicid = 2;
}
} }
message Message { message Message {
optional string from = 1; optional string from = 1;
optional bytes data = 2; optional bytes data = 2;
optional bytes seqno = 3;
optional uint64 seqno = 3; repeated string topicIDs = 4;
optional string topic = 4;
} }
// topicID = hash(topicDescriptor); (not the topic.name)
message TopicDescriptor {
optional string name = 1;
optional AuthOpts auth = 2;
optional EncOpts enc = 3;
message AuthOpts {
optional AuthMode mode = 1;
repeated bytes keys = 2; // root keys to trust
enum AuthMode {
NONE = 0; // no authentication, anyone can publish
KEY = 1; // only messages signed by keys in the topic descriptor are accepted
WOT = 2; // web of trust, certificates can allow publisher set to grow
}
}
message EncOpts {
optional EncMode mode = 1;
repeated bytes keyHashes = 2; // the hashes of the shared keys used (salted)
enum EncMode {
NONE = 0; // no encryption, anyone can read
SHAREDKEY = 1; // messages are encrypted with shared key
WOT = 2; // web of trust, certificates can allow publisher set to grow
}
}
}