├── .gitignore ├── LICENSE ├── README.md ├── flags.go ├── log └── .gitignore ├── main.go ├── multilogue.go ├── multilogue_test.go ├── node.go ├── pb ├── p2p.pb.go └── p2p.proto └── ui.go /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | Multilogue 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multilogue 2 | Multilogue: non-simultaneous p2p chat protocol 3 | 4 | 5 | ## Summary: 6 | - One user can speak in a channel at a time. 7 | - Users must request a transmission before starting their turn. 8 | - After certain conditions are met (time limit, message limit, etc), the user's turn ends. 9 | - The user can also voluntarily end their turn. 10 | - After each users turn, they are subject to a cooldown in which their requests are deprioritized. 11 | 12 | ## How to use: 13 | Clone the project 14 | make deps 15 | go build 16 | 17 | ./Multilogue -user {username} -channel {channel} : Create and join new channel. 18 | 19 | Multiadress listed on title bar. 20 | 21 | ./Multilogue -user {username} -channel {channel} -host {multiaddress} : Join channel at that specific multiadress 22 | 23 | ## Controls: 24 | [Insert] : Start turn 25 | [End] : End Turn 26 | [CTRL+C] : Exit program 27 | 28 | ## Multilogue Protocol Functions: 29 | ``` 30 | // Host functions 31 | CreateChannel(clientPeer *Peer, channelId string, config *ChannelConfig) 32 | 33 | // Client functions 34 | JoinChannel(clientPeer *Peer, hostPeerID peer.ID, channelId string) 35 | LeaveChannel(clientPeer *Peer, hostPeerID peer.ID, channelId string) 36 | 37 | SendTransmissionRequest(clientPeer *Peer, hostPeerID peer.ID, channelId string) 38 | EndTransmission(clientPeer *Peer, hostPeerID peer.ID, channelId string) 39 | 40 | SendMessage(clientPeer *Peer, hostPeerID peer.ID, channelId string, message string) 41 | ``` 42 | 43 | Requests that require an asynchronous response are handled as follows 44 | 45 | ``` 46 | select { 47 | case <-request.success: 48 | ... 49 | case <-request.fail: 50 | ... 51 | } 52 | ``` 53 | 54 | Each request channel returns a Response struct, which contains the rror code for the 55 | request. 56 | 57 | See ui.go and main.go for examples. 58 | -------------------------------------------------------------------------------- /flags.go: -------------------------------------------------------------------------------- 1 | // From: github.com/libp2p/go-libp2p-examples/blob/master/chat-with-rendezvous/flags.go 2 | // Authors 3 | // Abhishek Upperwal 4 | // Mantas Vidutis 5 | // TODO: Read config file form here too 6 | package main 7 | 8 | import ( 9 | "flag" 10 | "strconv" 11 | "strings" 12 | "time" 13 | 14 | maddr "github.com/multiformats/go-multiaddr" 15 | ) 16 | 17 | // A new type we need for writing a custom flag parser 18 | type addrList []maddr.Multiaddr 19 | 20 | func (al *addrList) String() string { 21 | strs := make([]string, len(*al)) 22 | for i, addr := range *al { 23 | strs[i] = addr.String() 24 | } 25 | return strings.Join(strs, ",") 26 | } 27 | 28 | func (al *addrList) Set(value string) error { 29 | addr, err := maddr.NewMultiaddr(value) 30 | if err != nil { 31 | return err 32 | } 33 | *al = append(*al, addr) 34 | return nil 35 | } 36 | 37 | // IPFS bootstrap nodes. Used to find other peers in the network. 38 | var defaultBootstrapAddrStrings = []string{ 39 | "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", 40 | "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", 41 | "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", 42 | "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", 43 | "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", 44 | } 45 | 46 | func StringsToAddrs(addrStrings []string) (maddrs []maddr.Multiaddr, err error) { 47 | for _, addrString := range addrStrings { 48 | addr, err := maddr.NewMultiaddr(addrString) 49 | if err != nil { 50 | return maddrs, err 51 | } 52 | maddrs = append(maddrs, addr) 53 | } 54 | return 55 | } 56 | 57 | type Config struct { 58 | RendezvousString string 59 | BootstrapPeers addrList 60 | ListenAddresses addrList 61 | ProtocolID string 62 | HostMultiAddress string 63 | ChannelConfigFile string 64 | ChannelName string 65 | Username string 66 | } 67 | 68 | func ParseFlags() (Config, error) { 69 | timestamp := strconv.FormatInt(time.Now().Unix(), 10) 70 | 71 | config := Config{} 72 | flag.StringVar(&config.RendezvousString, "rendezvous", "gravitation", 73 | "Unique string to identify group of nodes. Share this with your friends to let them connect with you") 74 | flag.Var(&config.BootstrapPeers, "peer", "Adds a peer multiaddress to the bootstrap list") 75 | flag.Var(&config.ListenAddresses, "listen", "Adds a multiaddress to the listen list") 76 | flag.StringVar(&config.ProtocolID, "pid", "/chat/1.1.0", "Sets a protocol id for stream headers") 77 | flag.StringVar(&config.HostMultiAddress, "host", "", "MultiAddress of host") 78 | flag.StringVar(&config.ChannelName, "channel", "test", "Name of channel to be joined.") 79 | flag.StringVar(&config.ChannelConfigFile, "config", "", "Channel config file.") 80 | flag.StringVar(&config.Username, "user", timestamp, "Username.") 81 | 82 | flag.Parse() 83 | 84 | if len(config.BootstrapPeers) == 0 { 85 | bootstrapPeerAddrs, err := StringsToAddrs(defaultBootstrapAddrStrings) 86 | if err != nil { 87 | return config, err 88 | } 89 | config.BootstrapPeers = bootstrapPeerAddrs 90 | } 91 | 92 | return config, nil 93 | } 94 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | libp2p "github.com/libp2p/go-libp2p" 7 | crypto "github.com/libp2p/go-libp2p-crypto" 8 | peerstore "github.com/libp2p/go-libp2p-peerstore" 9 | multiaddr "github.com/multiformats/go-multiaddr" 10 | ) 11 | 12 | func makeHost(config Config) *Node { 13 | ctx := context.Background() 14 | 15 | // libp2p.New constructs a new libp2p Host. Other options can be added 16 | // here. 17 | priv, _, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) 18 | 19 | host, err := libp2p.New( 20 | ctx, 21 | libp2p.ListenAddrs([]multiaddr.Multiaddr(config.ListenAddresses)...), 22 | libp2p.Identity(priv), 23 | libp2p.DisableRelay(), 24 | ) 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | return NewNode(host) 30 | } 31 | 32 | func startMultilogue(config Config) { 33 | client := makeHost(config) 34 | 35 | clientPeer := &Peer{ 36 | peerID: client.ID(), 37 | username: config.Username} 38 | 39 | var chatUI *ChatUI 40 | if config.HostMultiAddress != "" { 41 | maddr, err := multiaddr.NewMultiaddr(config.HostMultiAddress) 42 | if err != nil { 43 | client.debugPrintln(err) 44 | panic(err) 45 | } 46 | 47 | info, err := peerstore.InfoFromP2pAddr(maddr) 48 | if err != nil { 49 | client.debugPrintln(err) 50 | panic(err) 51 | } 52 | 53 | client.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL) 54 | 55 | client.JoinChannel(clientPeer, info.ID, config.ChannelName) 56 | chatUI = NewChatUI(client, config.ChannelName, clientPeer, info.ID, config.HostMultiAddress) 57 | } else { 58 | host := makeHost(config) 59 | hostID := host.ID() 60 | 61 | host.Peerstore().AddAddrs(client.ID(), client.Addrs(), peerstore.PermanentAddrTTL) 62 | client.Peerstore().AddAddrs(host.ID(), host.Addrs(), peerstore.PermanentAddrTTL) 63 | 64 | var channelConfig *ChannelConfig 65 | if config.ChannelConfigFile == "" { 66 | channelConfig = DefaultChannelConfig() 67 | } else { 68 | ReadChannelConfigs(config.ChannelConfigFile, channelConfig) 69 | } 70 | host.CreateChannel(clientPeer, config.ChannelName, channelConfig) 71 | client.JoinChannel(clientPeer, hostID, config.ChannelName) 72 | hostIDStr := host.ID().Pretty() 73 | addresses := "" 74 | for _, element := range host.Addrs() { 75 | // index is the index where we are 76 | // element is the element from someSlice for where we are 77 | addresses = addresses + element.String() + "/p2p/" + hostIDStr + " " 78 | } 79 | 80 | chatUI = NewChatUI(client, config.ChannelName, clientPeer, hostID, addresses) 81 | } 82 | 83 | chatUI.StartUI() 84 | // there was a way to enter peer id lol 85 | select {} 86 | } 87 | 88 | func main() { 89 | // // Parse flags 90 | config, err := ParseFlags() 91 | if err != nil { 92 | panic(err) 93 | } 94 | 95 | startMultilogue(config) 96 | } 97 | -------------------------------------------------------------------------------- /multilogue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "encoding/json" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "reflect" 11 | "sync" 12 | "time" 13 | 14 | p2p "github.com/assemblaj/Multilogue/pb" 15 | "github.com/gogo/protobuf/proto" 16 | protobufCodec "github.com/multiformats/go-multicodec/protobuf" 17 | 18 | uuid "github.com/google/uuid" 19 | inet "github.com/libp2p/go-libp2p-net" 20 | peer "github.com/libp2p/go-libp2p-peer" 21 | ) 22 | 23 | // pattern: /protocol-name/request-or-response-message/version 24 | const clientJoinChannel = "/multilogue/clientjoinchannel/0.0.1" 25 | const clientLeaveChannel = "/multilogue/clientleavechannel/0.0.1" 26 | const clientSendMessage = "/multilogue/clientsendmessage/0.0.1" 27 | const clientTransmissionStart = "/multilogue/clienttransmissionstart/0.0.1" 28 | const clientTransmissionEnd = "/multilogue/clienttransmissionend/0.0.1" 29 | 30 | const hostAcceptClient = "/multilogue/hostacceptclient/0.0.1" 31 | const hostDenyClient = "/multilogue/hostdenyclient/0.0.1" 32 | const hostAcceptTransmission = "/multilogue/hostaccepttransmission/0.0.1" 33 | const hostDenyTransmission = "/multilogue/hostdenytransmission/0.0.1" 34 | const hostBroadcastMessage = "/multilogue/hostbroadcastmessage/0.0.1" 35 | 36 | // might add more data for statistics later 37 | // join timestamp 38 | // total messages 39 | // etc etc 40 | type Peer struct { 41 | peerID peer.ID 42 | username string 43 | lastMessage time.Time // unix timestamp of last message 44 | lastTransmission time.Time // unix timestamp of last transmission 45 | } 46 | 47 | type Message struct { 48 | peer *Peer 49 | timestamp time.Time 50 | text string 51 | } 52 | 53 | func NewMessage(peer *Peer, message string) *Message { 54 | return &Message{ 55 | peer: peer, 56 | timestamp: time.Now(), 57 | text: message} 58 | } 59 | 60 | type SyncedMap struct { 61 | lock sync.RWMutex 62 | values map[string]interface{} 63 | valueType reflect.Type 64 | } 65 | 66 | func newSyncedMap(v interface{}) *SyncedMap { 67 | return &SyncedMap{ 68 | values: make(map[string]interface{}), 69 | valueType: reflect.TypeOf(v)} 70 | } 71 | 72 | func (t *SyncedMap) Get(key string) (interface{}, bool) { 73 | t.lock.RLock() 74 | defer t.lock.RUnlock() 75 | value, found := t.values[key] 76 | return value, found 77 | } 78 | 79 | func (t *SyncedMap) Size() int { 80 | t.lock.RLock() 81 | defer t.lock.RUnlock() 82 | return len(t.values) 83 | } 84 | 85 | func (t *SyncedMap) Delete(key string) { 86 | t.lock.Lock() 87 | defer t.lock.Unlock() 88 | delete(t.values, key) 89 | } 90 | 91 | func (t *SyncedMap) Put(key string, value interface{}) { 92 | if reflect.TypeOf(value) == t.valueType { 93 | t.lock.Lock() 94 | defer t.lock.Unlock() 95 | t.values[key] = value 96 | } 97 | } 98 | 99 | func (t *SyncedMap) Range(f func(key, value interface{})) { 100 | t.lock.RLock() 101 | defer t.lock.RUnlock() 102 | for k, v := range t.values { 103 | t.lock.RUnlock() 104 | f(k, v) 105 | t.lock.RLock() 106 | } 107 | } 108 | 109 | type OutputSession struct { 110 | messageQueue chan *Message 111 | queueSize int 112 | } 113 | 114 | func NewOutputSession(queueSize int) *OutputSession { 115 | os := new(OutputSession) 116 | os.queueSize = queueSize 117 | os.messageQueue = make(chan *Message, os.queueSize) 118 | return os 119 | } 120 | 121 | type Transmission struct { 122 | channelId string 123 | peer *Peer 124 | totalMsgs int 125 | startTime time.Time 126 | done chan bool // notifies timer when transmission is ended 127 | timeEnded bool 128 | sync.RWMutex 129 | } 130 | 131 | type Channel struct { 132 | channelId string 133 | history []string // peer Ids of users who last spoke 134 | peers *SyncedMap // slice of peer objects 135 | // probably need a map of peerId to cooldown 136 | currentTransmission *Transmission 137 | output *OutputSession 138 | config *ChannelConfig 139 | sync.RWMutex 140 | } 141 | 142 | func NewChannel(channelId string, config *ChannelConfig) *Channel { 143 | if config == nil { 144 | config = DefaultChannelConfig() 145 | } 146 | 147 | c := &Channel{ 148 | channelId: channelId, 149 | history: []string{}, 150 | peers: newSyncedMap(&Peer{}), 151 | output: NewOutputSession(1), //TODO: Replace with some default/config 152 | config: config} 153 | return c 154 | } 155 | 156 | // Protocol Error States 157 | type ProtocolErrorState int32 158 | 159 | const ( 160 | NoError ProtocolErrorState = 100 161 | GenericError ProtocolErrorState = 200 162 | MessageLimitError ProtocolErrorState = 210 163 | TimeLimitError ProtocolErrorState = 220 164 | CooldownError ProtocolErrorState = 230 165 | HistoryError ProtocolErrorState = 240 166 | RatioError ProtocolErrorState = 250 167 | ) 168 | 169 | // Prorbably want useful statistics in this eventually too 170 | type Response struct { 171 | errorCode ProtocolErrorState 172 | } 173 | 174 | func NewResponse(errorCode ProtocolErrorState) *Response { 175 | return &Response{ 176 | errorCode: errorCode} 177 | } 178 | 179 | type Request struct { 180 | success chan *Response 181 | fail chan *Response 182 | } 183 | 184 | func NewRequest() *Request { 185 | return &Request{ 186 | success: make(chan *Response), 187 | fail: make(chan *Response)} 188 | } 189 | 190 | // MultilogueProtocol type 191 | type MultilogueProtocol struct { 192 | node *Node // local host 193 | channels *SyncedMap // channelId : *Channel 194 | requests *SyncedMap // used to access request data from response handlers 195 | debug bool 196 | logger *log.Logger 197 | } 198 | 199 | // NewMultilogueProtocol Create instance of protocol 200 | // Might want a data object 201 | func NewMultilogueProtocol(node *Node) *MultilogueProtocol { 202 | p := &MultilogueProtocol{ 203 | node: node, 204 | channels: newSyncedMap(&Channel{}), 205 | requests: newSyncedMap(&Request{}), 206 | debug: true, 207 | logger: initDebugLogger()} 208 | 209 | // Server functions 210 | node.SetStreamHandler(clientJoinChannel, p.onClientJoinChannel) 211 | node.SetStreamHandler(clientLeaveChannel, p.onClientLeaveChannel) 212 | node.SetStreamHandler(clientSendMessage, p.onClientSendMessage) 213 | node.SetStreamHandler(clientTransmissionStart, p.onClientTransmissionStart) 214 | node.SetStreamHandler(clientTransmissionEnd, p.onClientTransmissionEnd) 215 | 216 | // Client functions 217 | node.SetStreamHandler(hostAcceptClient, p.onHostAcceptClient) 218 | node.SetStreamHandler(hostDenyClient, p.onHostDenyClient) 219 | node.SetStreamHandler(hostAcceptTransmission, p.onHostAcceptTransmission) 220 | node.SetStreamHandler(hostDenyTransmission, p.onHostDenyTransmission) 221 | node.SetStreamHandler(hostBroadcastMessage, p.onHostBroadcastMessage) 222 | return p 223 | } 224 | 225 | func initDebugLogger() *log.Logger { 226 | timeStirng := time.Now().Format("1-2_2006_15-04") 227 | 228 | f, err := os.OpenFile("./log/log_"+timeStirng+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 229 | if err != nil { 230 | log.Fatalf("error opening file: %v", err) 231 | } 232 | //defer f.Close() // lets leave this to the os 233 | 234 | logger := log.New(f, "Debug:", log.Lshortfile) 235 | return logger 236 | } 237 | 238 | func (p *MultilogueProtocol) debugPrintln(v ...interface{}) { 239 | if p.debug { 240 | p.logger.Println(v...) 241 | } 242 | } 243 | 244 | func ProtocolErrorName(errorCode ProtocolErrorState) string { 245 | var errorName string 246 | switch errorCode { 247 | case NoError: 248 | errorName = "NoError" 249 | case GenericError: 250 | errorName = "GenericError" 251 | case MessageLimitError: 252 | errorName = "MessageLimitError" 253 | case TimeLimitError: 254 | errorName = "TimeLimitError" 255 | case CooldownError: 256 | errorName = "CooldownError" 257 | case HistoryError: 258 | errorName = "HistoryError" 259 | case RatioError: 260 | errorName = "RatioError" 261 | default: 262 | errorName = "UnknownError" 263 | } 264 | return errorName 265 | } 266 | 267 | type ChannelConfig struct { 268 | MessageLimit int 269 | CooldownPeriod int 270 | TimeLimit int 271 | MaxMessageRatio float64 272 | HistorySize int 273 | } 274 | 275 | func ReadChannelConfigs(fname string, config *ChannelConfig) { 276 | b, err := ioutil.ReadFile(fname) 277 | if err != nil { 278 | log.Println("Error reading data from file. ") 279 | } 280 | err = json.Unmarshal(b, config) 281 | if err != nil { 282 | log.Println("Error loading data. ") 283 | } 284 | } 285 | 286 | func DefaultChannelConfig() *ChannelConfig { 287 | 288 | defaultChannelConfig := &ChannelConfig{ 289 | MessageLimit: 5, 290 | CooldownPeriod: 200, // Seconds 291 | TimeLimit: 180, // Minutes 292 | MaxMessageRatio: 8, // for now 293 | HistorySize: 2} 294 | 295 | return defaultChannelConfig 296 | } 297 | 298 | // Handled when hosting 299 | // Validate and broadcast this message to all peers 300 | // deny if necesary 301 | func (p *MultilogueProtocol) onClientSendMessage(s inet.Stream) { 302 | p.debugPrintln("In onClientSendMessage: Message accepted.") 303 | 304 | // get request data 305 | data := &p2p.ClientSendMessage{} 306 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 307 | err := decoder.Decode(data) 308 | if err != nil { 309 | p.debugPrintln(err) 310 | return 311 | } 312 | 313 | valid := p.node.authenticateMessage(data, data.MessageData) 314 | 315 | if !valid { 316 | p.debugPrintln("Failed to authenticate message") 317 | return 318 | } 319 | 320 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 321 | clientPeerIDString := clientPeerID.String() 322 | if err != nil { 323 | p.debugPrintln("Failed to obtain Client Peer ID") 324 | return 325 | } 326 | 327 | // Protocol Logic 328 | accepted := false 329 | 330 | errorCode := GenericError 331 | var hasPeer bool 332 | var channel *Channel 333 | 334 | var currentChannelClient string 335 | var givenChannelClient string 336 | var remoteRequester string 337 | var sessionLength time.Duration 338 | var messageRatio float64 339 | 340 | value, exists := p.channels.Get(data.HostData.ChannelId) 341 | 342 | if !exists { 343 | p.debugPrintln("In onClientSendMessage: Denied because channel not found.") 344 | goto Response 345 | } 346 | 347 | channel = value.(*Channel) 348 | 349 | channel.currentTransmission.RLock() 350 | _, hasPeer = channel.peers.Get(clientPeerIDString) 351 | if !hasPeer { 352 | p.debugPrintln("In onClientSendMessage: Denied because peer not found.") 353 | goto Response 354 | } 355 | 356 | if channel.currentTransmission == nil { 357 | p.debugPrintln("In onClientSendMessage: Denied because transmission doesn't exist.") 358 | goto Response 359 | } 360 | 361 | // valid peer id 362 | currentChannelClient = channel.currentTransmission.peer.peerID.String() 363 | givenChannelClient = clientPeerIDString 364 | remoteRequester = s.Conn().RemotePeer().String() 365 | if !(currentChannelClient == givenChannelClient && currentChannelClient == remoteRequester) { 366 | p.debugPrintln("In onClientSendMessage: Denied because transmisison peer id, given peer id and remote peer id are not equal.") 367 | p.debugPrintln(currentChannelClient, " ", givenChannelClient, " ", remoteRequester) 368 | goto Response 369 | } 370 | 371 | if channel.currentTransmission.totalMsgs+1 > channel.config.MessageLimit { 372 | p.debugPrintln("In onClientSendMessage: Denied because meessage limit reached.") 373 | errorCode = MessageLimitError 374 | goto Response 375 | } 376 | 377 | sessionLength = time.Now().Sub(channel.currentTransmission.startTime) 378 | messageRatio = float64(channel.currentTransmission.totalMsgs) / sessionLength.Seconds() 379 | if messageRatio > channel.config.MaxMessageRatio { 380 | p.debugPrintln("In onClientSendMessage: Denied because message ratio passed.") 381 | errorCode = RatioError 382 | goto Response 383 | } 384 | 385 | if channel.currentTransmission.timeEnded { 386 | p.debugPrintln("In onClientSendMessage: Denied time limit for transmission passed.") 387 | errorCode = TimeLimitError 388 | goto Response 389 | } 390 | channel.currentTransmission.RUnlock() 391 | 392 | accepted = true 393 | 394 | Response: 395 | 396 | // generate response message 397 | // Returning separate messages based on accepted or not 398 | var resp proto.Message 399 | var respErr error 400 | 401 | if accepted { 402 | // Updating increment messages 403 | channel.currentTransmission.Lock() 404 | channel.currentTransmission.totalMsgs = channel.currentTransmission.totalMsgs + 1 405 | channel.currentTransmission.Unlock() 406 | 407 | //for peerID, currentPeer := range channel.peers { 408 | channel.peers.Range(func(key, value interface{}) { 409 | peerID := key 410 | currentPeer := value.(*Peer) 411 | 412 | resp = &p2p.HostBroadcastMessage{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 413 | ClientData: data.ClientData, 414 | HostData: data.HostData, 415 | Message: data.Message} 416 | 417 | // sign the data 418 | signature, err := p.node.signProtoMessage(resp) 419 | if err != nil { 420 | p.debugPrintln("failed to sign response") 421 | return 422 | } 423 | 424 | // Cannot take the above code outside of the if because I need to do the following 425 | broadcastResp := resp.(*p2p.HostBroadcastMessage) 426 | 427 | // add the signature to the message 428 | broadcastResp.MessageData.Sign = signature 429 | 430 | // Have to use the constant for the protocol message name string because reasons 431 | // So that had to be done within this if 432 | s, respErr = p.node.NewStream(context.Background(), currentPeer.peerID, hostBroadcastMessage) 433 | 434 | if respErr != nil { 435 | p.debugPrintln(respErr) 436 | return 437 | } 438 | 439 | // send the response 440 | ok := p.node.sendProtoMessage(resp, s) 441 | if ok { 442 | p.debugPrintln("%s: Message from %s recieved.", s.Conn().LocalPeer().String(), peerID) 443 | } 444 | }) 445 | } else { 446 | //peer := channel.peers[clientPeerIDString] 447 | 448 | // ending transmission 449 | channel.currentTransmission.done <- true 450 | 451 | channel.Lock() 452 | channel.currentTransmission = nil 453 | channel.Unlock() 454 | p.debugPrintln("In onClientSendMessage: Ending transmission because of denial. ") 455 | 456 | resp = &p2p.HostDenyClient{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 457 | ClientData: data.ClientData, 458 | HostData: data.HostData, 459 | ErrorCode: int32(errorCode)} 460 | 461 | // sign the data 462 | signature, err := p.node.signProtoMessage(resp) 463 | if err != nil { 464 | p.debugPrintln("failed to sign response") 465 | return 466 | } 467 | denyClientResp := resp.(*p2p.HostDenyClient) 468 | 469 | // add the signature to the message 470 | denyClientResp.MessageData.Sign = signature 471 | s, respErr = p.node.NewStream(context.Background(), s.Conn().RemotePeer(), hostDenyClient) 472 | 473 | if respErr != nil { 474 | p.debugPrintln(respErr) 475 | return 476 | } 477 | 478 | // send the response 479 | ok := p.node.sendProtoMessage(resp, s) 480 | if ok { 481 | p.debugPrintln("%s: Denying Message from %s.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) 482 | } 483 | } 484 | } 485 | 486 | // verify this and set new transmission 487 | // deny if necesary 488 | func (p *MultilogueProtocol) onClientTransmissionStart(s inet.Stream) { 489 | // get request data 490 | data := &p2p.ClientTransmissionStart{} 491 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 492 | err := decoder.Decode(data) 493 | if err != nil { 494 | p.debugPrintln(err) 495 | return 496 | } 497 | 498 | valid := p.node.authenticateMessage(data, data.MessageData) 499 | 500 | if !valid { 501 | p.debugPrintln("Failed to authenticate message") 502 | return 503 | } 504 | 505 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 506 | clientPeerIDString := clientPeerID.String() 507 | if err != nil { 508 | p.debugPrintln("Failed to obtain Client Peer ID") 509 | return 510 | } 511 | 512 | errorCode := GenericError 513 | 514 | // Protocol Logic 515 | accepted := true 516 | var channel *Channel 517 | 518 | value, exists := p.channels.Get(data.HostData.ChannelId) 519 | if exists { 520 | channel = value.(*Channel) 521 | 522 | value, hasPeer := channel.peers.Get(clientPeerIDString) 523 | var peer *Peer 524 | 525 | if !hasPeer { 526 | accepted = false 527 | p.debugPrintln("Transmission denied, peer not found on channel.") 528 | goto Response 529 | } else { 530 | peer = value.(*Peer) 531 | } 532 | 533 | if channel.currentTransmission != nil { 534 | p.debugPrintln("Transmission denied, current transmission exists.") 535 | accepted = false 536 | goto Response 537 | } 538 | 539 | if len(channel.history) > 0 { 540 | lastPeer := channel.history[len(channel.history)-1] 541 | if peer.peerID.String() == lastPeer { 542 | time.Sleep(time.Duration(channel.config.CooldownPeriod) * time.Millisecond) 543 | channel.Lock() 544 | if channel.currentTransmission != nil { 545 | p.debugPrintln("Transmission denied, other request recieved during cooldown period.") 546 | accepted = false 547 | errorCode = CooldownError 548 | } 549 | channel.Unlock() 550 | goto Response 551 | } 552 | } 553 | } else { 554 | p.debugPrintln("Transmission denied, channel doesn't exist.") 555 | accepted = false 556 | goto Response 557 | } 558 | Response: 559 | // generate response message 560 | // Returning separate messages based on accepted or not 561 | var resp proto.Message 562 | var respErr error 563 | 564 | if accepted { 565 | channel.history = append(channel.history, clientPeerIDString) 566 | value, _ := channel.peers.Get(clientPeerIDString) 567 | peer := value.(*Peer) 568 | 569 | peer.lastTransmission = time.Now() 570 | 571 | // Create new transmission 572 | channel.currentTransmission = &Transmission{ 573 | channelId: data.HostData.ChannelId, 574 | peer: peer, 575 | startTime: time.Now(), 576 | done: make(chan bool)} 577 | 578 | // Time limit handling 579 | go func() { 580 | timeLimit := time.Duration(channel.config.TimeLimit) * time.Second 581 | transmissionTimer := time.NewTimer(timeLimit) 582 | 583 | select { 584 | case <-channel.currentTransmission.done: 585 | p.debugPrintln("timer returning, transmission done") 586 | return 587 | case <-transmissionTimer.C: 588 | channel.currentTransmission.Lock() 589 | channel.currentTransmission.timeEnded = true 590 | channel.currentTransmission.Unlock() 591 | } 592 | }() 593 | 594 | resp = &p2p.HostAcceptTransmission{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 595 | ClientData: data.ClientData, 596 | HostData: data.HostData} 597 | 598 | // sign the data 599 | signature, err := p.node.signProtoMessage(resp) 600 | if err != nil { 601 | p.debugPrintln("failed to sign response") 602 | return 603 | } 604 | 605 | // Cannot take the above code outside of the if because I need to do the following 606 | acceptClientResp := resp.(*p2p.HostAcceptTransmission) 607 | 608 | // add the signature to the message 609 | acceptClientResp.MessageData.Sign = signature 610 | 611 | // Have to use the constant for the protocol message name string because reasons 612 | // So that had to be done within this if 613 | s, respErr = p.node.NewStream(context.Background(), s.Conn().RemotePeer(), hostAcceptTransmission) 614 | } else { 615 | resp = &p2p.HostDenyClient{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 616 | ClientData: data.ClientData, 617 | HostData: data.HostData, 618 | ErrorCode: int32(errorCode)} 619 | 620 | // sign the data 621 | signature, err := p.node.signProtoMessage(resp) 622 | if err != nil { 623 | p.debugPrintln("failed to sign response") 624 | return 625 | } 626 | denyClientResp := resp.(*p2p.HostDenyClient) 627 | 628 | // add the signature to the message 629 | denyClientResp.MessageData.Sign = signature 630 | s, respErr = p.node.NewStream(context.Background(), s.Conn().RemotePeer(), hostDenyClient) 631 | } 632 | if respErr != nil { 633 | p.debugPrintln(respErr) 634 | return 635 | } 636 | 637 | // send the response 638 | ok := p.node.sendProtoMessage(resp, s) 639 | 640 | if ok { 641 | p.debugPrintln("%s: Transmisison attempted from %s.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) 642 | } 643 | 644 | } 645 | 646 | // verify this and delete transmission 647 | func (p *MultilogueProtocol) onClientTransmissionEnd(s inet.Stream) { 648 | // get request data 649 | data := &p2p.ClientTransmissionEnd{} 650 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 651 | err := decoder.Decode(data) 652 | if err != nil { 653 | p.debugPrintln(err) 654 | return 655 | } 656 | 657 | p.debugPrintln("%s: User: %s (%s) ending transmission. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer()) 658 | 659 | valid := p.node.authenticateMessage(data, data.MessageData) 660 | 661 | if !valid { 662 | p.debugPrintln("Failed to authenticate message") 663 | return 664 | } 665 | 666 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 667 | clientPeerIDString := clientPeerID.String() 668 | if err != nil { 669 | p.debugPrintln("Failed to obtain Client Peer ID") 670 | return 671 | } 672 | 673 | // Protocol Logic 674 | // Leaving channel 675 | val, exists := p.channels.Get(data.HostData.ChannelId) 676 | if exists { 677 | channel := val.(*Channel) 678 | // remove request from map as we have processed it here 679 | _, hasPeer := channel.peers.Get(clientPeerIDString) 680 | if hasPeer { 681 | if channel.currentTransmission == nil { 682 | p.debugPrintln("In onClientTransmissionEnd: Transmisison doesn't exist.") 683 | return 684 | } 685 | currentChannelClient := channel.currentTransmission.peer.peerID.String() 686 | givenChannelClient := clientPeerIDString 687 | remoteRequester := s.Conn().RemotePeer().String() 688 | if currentChannelClient == givenChannelClient && currentChannelClient == remoteRequester { 689 | channel.currentTransmission.Lock() 690 | channel.currentTransmission.done <- true 691 | channel.currentTransmission.Unlock() 692 | 693 | channel.Lock() 694 | channel.currentTransmission = nil 695 | channel.Unlock() 696 | p.debugPrintln("In onClientTransmissionEnd: Ending transmission. ") 697 | 698 | } else { 699 | p.debugPrintln("In onClientTransmissionEnd: currentChannelClient, givenChannelClient , remoteRequester Not the same.") 700 | p.debugPrintln("In onClientTransmissionEnd: ", currentChannelClient, " ", givenChannelClient, " ", remoteRequester) 701 | } 702 | } else { 703 | p.debugPrintln("In onClientTransmissionEnd: Peer not found .") 704 | } 705 | } else { 706 | p.debugPrintln("In onClientTransmissionEnd: Channel not found .") 707 | 708 | } 709 | 710 | p.debugPrintln("%s: User: %s (%s) ended transmission. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer()) 711 | 712 | } 713 | 714 | // add to channel 715 | // deny if necesary 716 | func (p *MultilogueProtocol) onClientJoinChannel(s inet.Stream) { 717 | // get request data 718 | data := &p2p.ClientJoinChannel{} 719 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 720 | err := decoder.Decode(data) 721 | if err != nil { 722 | p.debugPrintln(err) 723 | return 724 | } 725 | 726 | valid := p.node.authenticateMessage(data, data.MessageData) 727 | 728 | if !valid { 729 | p.debugPrintln("Failed to authenticate message") 730 | return 731 | } 732 | 733 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 734 | clientPeerIDString := clientPeerID.String() 735 | if err != nil { 736 | p.debugPrintln("Failed to obtain Client Peer ID") 737 | return 738 | } 739 | 740 | // Protocol Logic 741 | // Adding to channel 742 | accepted := false 743 | val, exists := p.channels.Get(data.HostData.ChannelId) 744 | if exists { 745 | channel := val.(*Channel) 746 | // Accept if the peerId and username aren't already in the channel 747 | _, hasPeer := channel.peers.Get(clientPeerIDString) 748 | if !hasPeer { 749 | accepted = true 750 | channel.peers.Range(func(key, value interface{}) { 751 | peer := value.(*Peer) 752 | 753 | //for _, peer := range channel.peers { 754 | if data.ClientData.Username == peer.username { 755 | accepted = false 756 | } 757 | }) 758 | } 759 | if accepted { 760 | channel.peers.Put(clientPeerIDString, &Peer{ 761 | peerID: clientPeerID, 762 | username: data.ClientData.Username, 763 | }) 764 | } 765 | } 766 | 767 | // generate response message 768 | // Returning separate messages based on accepted or not 769 | var resp proto.Message 770 | var respErr error 771 | 772 | if accepted { 773 | resp = &p2p.HostAcceptClient{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 774 | ClientData: data.ClientData, 775 | HostData: data.HostData} 776 | 777 | // sign the data 778 | signature, err := p.node.signProtoMessage(resp) 779 | if err != nil { 780 | p.debugPrintln("failed to sign response") 781 | return 782 | } 783 | 784 | // Cannot take the above code outside of the if because I need to do the following 785 | acceptClientResp := resp.(*p2p.HostAcceptClient) 786 | 787 | // add the signature to the message 788 | acceptClientResp.MessageData.Sign = signature 789 | 790 | // Have to use the constant for the protocol message name string because reasons 791 | // So that had to be done within this if 792 | s, respErr = p.node.NewStream(context.Background(), s.Conn().RemotePeer(), hostAcceptClient) 793 | } else { 794 | resp = &p2p.HostDenyClient{MessageData: p.node.NewMessageData(data.MessageData.Id, false), 795 | ClientData: data.ClientData, 796 | HostData: data.HostData} 797 | 798 | // sign the data 799 | signature, err := p.node.signProtoMessage(resp) 800 | if err != nil { 801 | p.debugPrintln("failed to sign response") 802 | return 803 | } 804 | denyClientResp := resp.(*p2p.HostDenyClient) 805 | 806 | // add the signature to the message 807 | denyClientResp.MessageData.Sign = signature 808 | s, respErr = p.node.NewStream(context.Background(), s.Conn().RemotePeer(), hostDenyClient) 809 | } 810 | if respErr != nil { 811 | p.debugPrintln(respErr) 812 | return 813 | } 814 | 815 | // send the response 816 | ok := p.node.sendProtoMessage(resp, s) 817 | 818 | if ok { 819 | p.debugPrintln("%s: Join Channel response to %s sent.", s.Conn().LocalPeer().String(), s.Conn().RemotePeer().String()) 820 | } 821 | 822 | } 823 | 824 | // delete form channel 825 | func (p *MultilogueProtocol) onClientLeaveChannel(s inet.Stream) { 826 | // get request data 827 | data := &p2p.ClientLeaveChannel{} 828 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 829 | err := decoder.Decode(data) 830 | if err != nil { 831 | p.debugPrintln(err) 832 | return 833 | } 834 | 835 | p.debugPrintln("%s: User: %s (%s) Leaving Channel %s. (Client)", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 836 | 837 | valid := p.node.authenticateMessage(data, data.MessageData) 838 | 839 | if !valid { 840 | p.debugPrintln("Failed to authenticate message") 841 | return 842 | } 843 | 844 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 845 | clientPeerIDString := clientPeerID.String() 846 | if err != nil { 847 | p.debugPrintln("Failed to obtain Client Peer ID") 848 | return 849 | } 850 | 851 | // Protocol Logic 852 | // Leaving channel 853 | val, exists := p.channels.Get(data.HostData.ChannelId) 854 | if exists { 855 | channel := val.(*Channel) 856 | // remove request from map as we have processed it here 857 | _, hasPeer := channel.peers.Get(clientPeerIDString) 858 | if hasPeer { 859 | channel.peers.Delete(clientPeerIDString) 860 | } 861 | } 862 | 863 | p.debugPrintln("%s: User: %s (%s) Left channel %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 864 | 865 | } 866 | 867 | // Handled when Client 868 | // Start sending messages 869 | func (p *MultilogueProtocol) onHostAcceptTransmission(s inet.Stream) { 870 | // get request data 871 | data := &p2p.HostAcceptTransmission{} 872 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 873 | err := decoder.Decode(data) 874 | if err != nil { 875 | p.debugPrintln(err) 876 | return 877 | } 878 | 879 | p.debugPrintln("%s: User: %s (%s) Transmission Accepted from host on channel %s. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 880 | 881 | valid := p.node.authenticateMessage(data, data.MessageData) 882 | 883 | if !valid { 884 | p.debugPrintln("Failed to authenticate message") 885 | return 886 | } 887 | 888 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 889 | clientPeerIDString := clientPeerID.String() 890 | if err != nil { 891 | p.debugPrintln("Failed to obtain Client Peer ID") 892 | return 893 | } 894 | 895 | // If there's no request, then simply print an error and return 896 | val, requestExists := p.requests.Get(data.MessageData.Id) 897 | if !requestExists { 898 | p.debugPrintln("Request not found ") 899 | return 900 | } 901 | request := val.(*Request) 902 | 903 | // Protocol Logic 904 | // Leaving channel 905 | val, channelExists := p.channels.Get(data.HostData.ChannelId) 906 | 907 | if !channelExists { 908 | p.debugPrintln("In onHostAcceptTransmission: Denied because channel doesn't exist") 909 | request.fail <- NewResponse(GenericError) 910 | return 911 | } 912 | channel := val.(*Channel) 913 | 914 | _, hasPeer := channel.peers.Get(clientPeerIDString) 915 | if !hasPeer { 916 | p.debugPrintln("In onHostAcceptTransmission: Denied because peer doesn't exist: ", data.ClientData.PeerId) 917 | request.fail <- NewResponse(GenericError) 918 | return 919 | } 920 | p.debugPrintln("In onHostAcceptTransmission: Success") 921 | 922 | request.success <- NewResponse(NoError) 923 | 924 | // remove request from map as we have processed it here 925 | if channel.currentTransmission == nil { 926 | channel.currentTransmission = &Transmission{} 927 | } 928 | 929 | p.debugPrintln("%s: User: %s (%s) attempting transmission on channel %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 930 | 931 | } 932 | 933 | func (p *MultilogueProtocol) onHostDenyTransmission(s inet.Stream) { 934 | // get request data 935 | data := &p2p.HostDenyTransmission{} 936 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 937 | err := decoder.Decode(data) 938 | if err != nil { 939 | p.debugPrintln(err) 940 | return 941 | } 942 | 943 | p.debugPrintln("%s: User: %s (%s) Transmision denied on channel %s. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 944 | 945 | valid := p.node.authenticateMessage(data, data.MessageData) 946 | 947 | if !valid { 948 | p.debugPrintln("Failed to authenticate message") 949 | return 950 | } 951 | 952 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 953 | clientPeerIDString := clientPeerID.String() 954 | if err != nil { 955 | p.debugPrintln("Failed to obtain Client Peer ID") 956 | return 957 | } 958 | 959 | // If there's no request, then simply print an error and return 960 | val, requestExists := p.requests.Get(data.MessageData.Id) 961 | if !requestExists { 962 | p.debugPrintln("Request not found ") 963 | return 964 | } 965 | request := val.(*Request) 966 | 967 | val, channelExists := p.channels.Get(data.HostData.ChannelId) 968 | if !channelExists { 969 | request.fail <- NewResponse(GenericError) 970 | return 971 | } 972 | channel := val.(*Channel) 973 | 974 | _, hasPeer := channel.peers.Get(clientPeerIDString) 975 | if !hasPeer { 976 | request.fail <- NewResponse(GenericError) 977 | return 978 | } 979 | request.fail <- NewResponse(ProtocolErrorState(data.ErrorCode)) 980 | 981 | p.channels.Delete(data.HostData.ChannelId) 982 | p.debugPrintln("%s: User: %s (%s) denied on channel at peerID %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 983 | 984 | } 985 | 986 | // Start reading messages 987 | func (p *MultilogueProtocol) onHostBroadcastMessage(s inet.Stream) { 988 | // get request data 989 | data := &p2p.HostBroadcastMessage{} 990 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 991 | err := decoder.Decode(data) 992 | if err != nil { 993 | p.debugPrintln(err) 994 | return 995 | } 996 | 997 | clientPeerId := p.node.ID().String() 998 | 999 | p.debugPrintln("%s: User: %s (%s) Message being broadcasted on channel %s. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1000 | 1001 | valid := p.node.authenticateMessage(data, data.MessageData) 1002 | 1003 | if !valid { 1004 | p.debugPrintln("Failed to authenticate message") 1005 | return 1006 | } 1007 | 1008 | clientPeerID, err := peer.IDFromBytes(data.ClientData.PeerId) 1009 | clientPeerIDString := clientPeerID.String() 1010 | if err != nil { 1011 | p.debugPrintln("Failed to obtain Client Peer ID") 1012 | return 1013 | } 1014 | 1015 | // Protocol Logic 1016 | // Leaving channel 1017 | value, exists := p.channels.Get(data.HostData.ChannelId) 1018 | if exists { 1019 | channel := value.(*Channel) 1020 | if clientPeerId == clientPeerIDString { 1021 | val, requestExists := p.requests.Get(data.MessageData.Id) 1022 | if !requestExists { 1023 | // TODO: Is this redundant? 1024 | p.debugPrintln("onHostBroadcastMessage: Request not found") 1025 | } else { 1026 | request := val.(*Request) 1027 | request.success <- NewResponse(NoError) 1028 | } 1029 | } 1030 | if channel.output == nil { 1031 | channel.output = NewOutputSession(1) //TODO: Replace with some default/config 1032 | } 1033 | // Alert the UI that a new message has been recieved in the channel 1034 | channel.output.messageQueue <- NewMessage(&Peer{ 1035 | peerID: clientPeerID, 1036 | username: data.ClientData.Username, 1037 | }, data.Message) 1038 | p.debugPrintln("onHostBroadcastMessage: New message being added to output queue ") 1039 | } 1040 | 1041 | p.debugPrintln("%s: User: %s (%s) broadcasted on channel %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1042 | 1043 | } 1044 | 1045 | // TODO: Create Channel etc on the cleint side 1046 | // As well as InputSession 1047 | func (p *MultilogueProtocol) onHostAcceptClient(s inet.Stream) { 1048 | // get request data 1049 | data := &p2p.HostAcceptClient{} 1050 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 1051 | err := decoder.Decode(data) 1052 | if err != nil { 1053 | p.debugPrintln(err) 1054 | return 1055 | } 1056 | 1057 | p.debugPrintln("%s: User: %s (%s) Joining Channel %s. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1058 | 1059 | valid := p.node.authenticateMessage(data, data.MessageData) 1060 | 1061 | if !valid { 1062 | p.debugPrintln("Failed to authenticate message") 1063 | return 1064 | } 1065 | 1066 | _, channelExists := p.channels.Get(data.HostData.ChannelId) 1067 | value, requestExists := p.requests.Get(data.MessageData.Id) 1068 | 1069 | // Update request data 1070 | if requestExists { 1071 | request := value.(*Request) 1072 | if channelExists { 1073 | request.success <- NewResponse(NoError) 1074 | } else { 1075 | request.fail <- NewResponse(GenericError) 1076 | } 1077 | } else { 1078 | p.debugPrintln("Failed to locate request data boject for response") 1079 | return 1080 | } 1081 | 1082 | p.debugPrintln("%s: User: %s (%s) Joined Channel %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1083 | } 1084 | 1085 | func (p *MultilogueProtocol) onHostDenyClient(s inet.Stream) { 1086 | // get request data 1087 | data := &p2p.HostDenyClient{} 1088 | decoder := protobufCodec.Multicodec(nil).Decoder(bufio.NewReader(s)) 1089 | err := decoder.Decode(data) 1090 | if err != nil { 1091 | p.debugPrintln(err) 1092 | return 1093 | } 1094 | 1095 | p.debugPrintln("%s: User: %s (%s) Client denied of channel %s. ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1096 | 1097 | valid := p.node.authenticateMessage(data, data.MessageData) 1098 | 1099 | if !valid { 1100 | p.debugPrintln("Failed to authenticate message") 1101 | return 1102 | } 1103 | // If there's no request, then simply print an error and return 1104 | value, requestExists := p.requests.Get(data.MessageData.Id) 1105 | request := value.(*Request) 1106 | if !requestExists { 1107 | p.debugPrintln("Request not found ") 1108 | return 1109 | } 1110 | 1111 | // Update request data 1112 | request.fail <- NewResponse(ProtocolErrorState(data.ErrorCode)) 1113 | 1114 | p.debugPrintln("%s: User: %s (%s) denied on channel %s ", s.Conn().LocalPeer(), data.ClientData.Username, s.Conn().RemotePeer(), data.HostData.ChannelId) 1115 | 1116 | } 1117 | 1118 | // TODO: Design proper API 1119 | func (p *MultilogueProtocol) SendMessage(clientPeer *Peer, hostPeerID peer.ID, channelId string, message string) (*Request, bool) { 1120 | p.debugPrintln("%s: Sending message to %s Channel : %s....", p.node.ID(), hostPeerID, channelId) 1121 | 1122 | // create message data 1123 | req := &p2p.ClientSendMessage{ 1124 | MessageData: p.node.NewMessageData(uuid.New().String(), false), 1125 | ClientData: &p2p.ClientData{ 1126 | PeerId: []byte(string(clientPeer.peerID)), 1127 | Username: clientPeer.username}, 1128 | HostData: &p2p.HostData{ 1129 | ChannelId: channelId, 1130 | PeerId: []byte(string(hostPeerID))}, 1131 | Message: message} 1132 | 1133 | // sign the data 1134 | signature, err := p.node.signProtoMessage(req) 1135 | if err != nil { 1136 | p.debugPrintln("failed to sign pb data: ", err) 1137 | return nil, false 1138 | } 1139 | 1140 | // add the signature to the message 1141 | req.MessageData.Sign = signature 1142 | 1143 | s, err := p.node.NewStream(context.Background(), hostPeerID, clientSendMessage) 1144 | if err != nil { 1145 | p.debugPrintln(err) 1146 | return nil, false 1147 | } 1148 | 1149 | ok := p.node.sendProtoMessage(req, s) 1150 | 1151 | if !ok { 1152 | return nil, false 1153 | } 1154 | 1155 | // Add request to request list 1156 | request := NewRequest() 1157 | p.requests.Put(req.MessageData.Id, request) 1158 | 1159 | return request, true 1160 | } 1161 | 1162 | func (p *MultilogueProtocol) SendTransmissionRequest(clientPeer *Peer, hostPeerID peer.ID, channelId string) (*Request, bool) { 1163 | p.debugPrintln("%s: Sending request to %s Channel : %s....", p.node.ID(), hostPeerID, channelId) 1164 | 1165 | // create message data 1166 | req := &p2p.ClientTransmissionStart{ 1167 | MessageData: p.node.NewMessageData(uuid.New().String(), false), 1168 | ClientData: &p2p.ClientData{ 1169 | PeerId: []byte(string(clientPeer.peerID)), 1170 | Username: clientPeer.username}, 1171 | HostData: &p2p.HostData{ 1172 | ChannelId: channelId, 1173 | PeerId: []byte(string(hostPeerID))}} 1174 | 1175 | // sign the data 1176 | signature, err := p.node.signProtoMessage(req) 1177 | if err != nil { 1178 | p.debugPrintln("failed to sign pb data") 1179 | return nil, false 1180 | } 1181 | 1182 | // add the signature to the message 1183 | req.MessageData.Sign = signature 1184 | 1185 | s, err := p.node.NewStream(context.Background(), hostPeerID, clientTransmissionStart) 1186 | if err != nil { 1187 | p.debugPrintln(err) 1188 | return nil, false 1189 | } 1190 | 1191 | ok := p.node.sendProtoMessage(req, s) 1192 | 1193 | if !ok { 1194 | return nil, false 1195 | } 1196 | 1197 | // Add request to request list 1198 | request := NewRequest() 1199 | p.requests.Put(req.MessageData.Id, request) 1200 | 1201 | return request, true 1202 | 1203 | } 1204 | 1205 | // Creates channnel and adds host to room 1206 | func (p *MultilogueProtocol) CreateChannel(clientPeer *Peer, channelId string, config *ChannelConfig) { 1207 | // Creating Channel Obj 1208 | _, exists := p.channels.Get(channelId) 1209 | // remove the channel 1210 | if !exists { 1211 | channel := NewChannel(channelId, config) 1212 | //channel.peers.Put(clientPeer.peerID.String(), clientPeer) 1213 | p.channels.Put(channelId, channel) 1214 | p.debugPrintln("CreateChannel: Channel created ") 1215 | } else { 1216 | p.debugPrintln("CreateChannel: Channel already exists. ") 1217 | } 1218 | } 1219 | 1220 | func (p *MultilogueProtocol) DeleteChannel(channelId string) { 1221 | _, exists := p.channels.Get(channelId) 1222 | if exists { 1223 | p.channels.Delete(channelId) 1224 | } 1225 | } 1226 | 1227 | func (p *MultilogueProtocol) JoinChannel(clientPeer *Peer, hostPeerID peer.ID, channelId string) (*Request, bool) { 1228 | p.debugPrintln("%s: Joining %s Channel : %s....", p.node.ID(), hostPeerID, channelId) 1229 | 1230 | // create message data 1231 | req := &p2p.ClientJoinChannel{ 1232 | MessageData: p.node.NewMessageData(uuid.New().String(), false), 1233 | ClientData: &p2p.ClientData{ 1234 | PeerId: []byte(string(clientPeer.peerID)), 1235 | Username: clientPeer.username}, 1236 | HostData: &p2p.HostData{ 1237 | ChannelId: channelId, 1238 | PeerId: []byte(string(hostPeerID))}} 1239 | 1240 | // sign the data 1241 | signature, err := p.node.signProtoMessage(req) 1242 | if err != nil { 1243 | p.debugPrintln("failed to sign pb data: ", err) 1244 | return nil, false 1245 | } 1246 | 1247 | // add the signature to the message 1248 | req.MessageData.Sign = signature 1249 | 1250 | s, err := p.node.NewStream(context.Background(), hostPeerID, clientJoinChannel) 1251 | if err != nil { 1252 | p.debugPrintln(err) 1253 | return nil, false 1254 | } 1255 | 1256 | ok := p.node.sendProtoMessage(req, s) 1257 | 1258 | if !ok { 1259 | return nil, false 1260 | } 1261 | 1262 | // Creating Channel Obj 1263 | channel := NewChannel(channelId, nil) 1264 | channel.peers.Put(clientPeer.peerID.String(), clientPeer) 1265 | p.channels.Put(channelId, channel) 1266 | 1267 | // Add request to request list 1268 | request := NewRequest() 1269 | p.requests.Put(req.MessageData.Id, request) 1270 | 1271 | return request, true 1272 | } 1273 | 1274 | func (p *MultilogueProtocol) LeaveChannel(clientPeer *Peer, hostPeerID peer.ID, channelId string) (*Request, bool) { 1275 | p.debugPrintln("%s: Leaving %s Channel : %s....", p.node.ID(), hostPeerID, channelId) 1276 | 1277 | // create message data 1278 | req := &p2p.ClientLeaveChannel{ 1279 | MessageData: p.node.NewMessageData(uuid.New().String(), false), 1280 | ClientData: &p2p.ClientData{ 1281 | PeerId: []byte(string(clientPeer.peerID)), 1282 | Username: clientPeer.username}, 1283 | HostData: &p2p.HostData{ 1284 | ChannelId: channelId, 1285 | PeerId: []byte(string(hostPeerID))}} 1286 | 1287 | // sign the data 1288 | signature, err := p.node.signProtoMessage(req) 1289 | if err != nil { 1290 | p.debugPrintln("failed to sign pb data") 1291 | return nil, false 1292 | } 1293 | 1294 | // add the signature to the message 1295 | req.MessageData.Sign = signature 1296 | 1297 | s, err := p.node.NewStream(context.Background(), hostPeerID, clientLeaveChannel) 1298 | if err != nil { 1299 | p.debugPrintln(err) 1300 | return nil, false 1301 | } 1302 | 1303 | ok := p.node.sendProtoMessage(req, s) 1304 | 1305 | if !ok { 1306 | return nil, false 1307 | } 1308 | 1309 | // Protocol logic 1310 | _, exists := p.channels.Get(channelId) 1311 | // remove the channel 1312 | if exists { 1313 | p.channels.Delete(channelId) 1314 | } 1315 | 1316 | // Add request to request list 1317 | request := NewRequest() 1318 | p.requests.Put(req.MessageData.Id, request) 1319 | 1320 | return request, true 1321 | } 1322 | 1323 | func (p *MultilogueProtocol) EndTransmission(clientPeer *Peer, hostPeerID peer.ID, channelId string) (*Request, bool) { 1324 | p.debugPrintln("%s: Ending transmission %s Channel : %s....", p.node.ID(), hostPeerID, channelId) 1325 | 1326 | // create message data 1327 | req := &p2p.ClientTransmissionEnd{ 1328 | MessageData: p.node.NewMessageData(uuid.New().String(), false), 1329 | ClientData: &p2p.ClientData{ 1330 | PeerId: []byte(string(clientPeer.peerID)), 1331 | Username: clientPeer.username}, 1332 | HostData: &p2p.HostData{ 1333 | ChannelId: channelId, 1334 | PeerId: []byte(string(hostPeerID))}} 1335 | 1336 | // sign the data 1337 | signature, err := p.node.signProtoMessage(req) 1338 | if err != nil { 1339 | p.debugPrintln("failed to sign pb data") 1340 | return nil, false 1341 | } 1342 | 1343 | // add the signature to the message 1344 | req.MessageData.Sign = signature 1345 | 1346 | s, err := p.node.NewStream(context.Background(), hostPeerID, clientTransmissionEnd) 1347 | if err != nil { 1348 | p.debugPrintln(err) 1349 | return nil, false 1350 | } 1351 | 1352 | ok := p.node.sendProtoMessage(req, s) 1353 | 1354 | if !ok { 1355 | return nil, false 1356 | } 1357 | 1358 | // Add request to request list 1359 | request := NewRequest() 1360 | p.requests.Put(req.MessageData.Id, request) 1361 | 1362 | return request, true 1363 | } 1364 | -------------------------------------------------------------------------------- /multilogue_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "math/rand" 7 | "testing" 8 | "time" 9 | 10 | libp2p "github.com/libp2p/go-libp2p" 11 | crypto "github.com/libp2p/go-libp2p-crypto" 12 | ps "github.com/libp2p/go-libp2p-peerstore" 13 | ma "github.com/multiformats/go-multiaddr" 14 | ) 15 | 16 | func makeTestNodePort(port int) *Node { 17 | // Ignoring most errors for brevity 18 | // See echo example for more details and better implementation 19 | priv, _, _ := crypto.GenerateKeyPair(crypto.Secp256k1, 256) 20 | listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) 21 | host, _ := libp2p.New( 22 | context.Background(), 23 | libp2p.ListenAddrs(listen), 24 | libp2p.Identity(priv), 25 | libp2p.DisableRelay(), 26 | ) 27 | 28 | return NewNode(host) 29 | } 30 | 31 | // helper method - create a lib-p2p host to listen on a port 32 | func makeTestNode() *Node { 33 | // Generating random post 34 | rand.Seed(666) 35 | port := rand.Intn(100) + 10000 36 | 37 | return makeTestNodePort(port) 38 | } 39 | 40 | // API Tests 41 | func TestCreateChannel(t *testing.T) { 42 | host := makeTestNode() 43 | 44 | host.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 45 | 46 | _, exists := host.channels.Get("test") 47 | if !exists { 48 | t.Errorf("CreateChannel failed to create channel.") 49 | } 50 | } 51 | 52 | func TestDeleteChannel(t *testing.T) { 53 | host := makeTestNode() 54 | 55 | host.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 56 | host.DeleteChannel("test") 57 | 58 | _, exists := host.channels.Get("test") 59 | if exists { 60 | t.Errorf("DeleteChannel failed to delete channel.") 61 | } 62 | } 63 | 64 | func TestJoinChannel(t *testing.T) { 65 | rand.Seed(666) 66 | port := rand.Intn(100) + 10000 67 | 68 | host1 := makeTestNodePort(port) 69 | host2 := makeTestNodePort(port + 1) 70 | 71 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 72 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 73 | 74 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 75 | 76 | host2IDString := host2.ID().String() 77 | 78 | host2Peer := &Peer{ 79 | peerID: host2.ID(), 80 | username: "host2"} 81 | 82 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 83 | 84 | var host2Notified *Response 85 | 86 | _, channelExists := host2.channels.Get("test") 87 | if !channelExists { 88 | t.Errorf("Test channel was not added to chanel 2 ") 89 | } 90 | 91 | select { 92 | case host2Notified = <-req.success: 93 | break 94 | case <-time.After(1 * time.Second): 95 | break 96 | } 97 | 98 | val, _ := host1.channels.Get("test") 99 | channel := val.(*Channel) 100 | _, host1AddedChannel := channel.peers.Get(host2IDString) 101 | 102 | if !host1AddedChannel || host2Notified == nil { 103 | t.Errorf("Failed to join channel. host1AddedChannel: %t host2Notified: %d ", host1AddedChannel, host2Notified.errorCode) 104 | } 105 | } 106 | 107 | func TestLeaveChannel(t *testing.T) { 108 | rand.Seed(666) 109 | port := rand.Intn(100) + 10000 110 | 111 | host1 := makeTestNodePort(port) 112 | host2 := makeTestNodePort(port + 1) 113 | 114 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 115 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 116 | 117 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 118 | 119 | host2IDString := host2.ID().String() 120 | 121 | host2Peer := &Peer{ 122 | peerID: host2.ID(), 123 | username: "host2"} 124 | 125 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 126 | 127 | select { 128 | case <-req.success: 129 | host2.LeaveChannel(host2Peer, host1.ID(), "test") 130 | break 131 | case <-time.After(1 * time.Second): 132 | break 133 | } 134 | 135 | <-time.After(2 * time.Second) 136 | val, _ := host1.channels.Get("test") 137 | channel := val.(*Channel) 138 | 139 | _, peerExists := channel.peers.Get(host2IDString) 140 | if peerExists { 141 | t.Errorf("Host2 was not remove from channel. ") 142 | } 143 | 144 | } 145 | 146 | func TestReqestTransmission(t *testing.T) { 147 | rand.Seed(666) 148 | port := rand.Intn(100) + 10000 149 | 150 | host1 := makeTestNodePort(port) 151 | host2 := makeTestNodePort(port + 1) 152 | 153 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 154 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 155 | 156 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 157 | 158 | //host2IDString := host2.ID().String() 159 | 160 | host2Peer := &Peer{ 161 | peerID: host2.ID(), 162 | username: "host2"} 163 | 164 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 165 | 166 | requestRecieved := false 167 | 168 | select { 169 | case <-req.success: 170 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 171 | select { 172 | // Just testing if the request was recieved at all. Ideally it should be 173 | // accepted in this scenario (first user starting transmisison), but 174 | // that's not what we're testing 175 | case <-req2.success: 176 | requestRecieved = true 177 | break 178 | case <-req2.fail: 179 | requestRecieved = true 180 | break 181 | case <-time.After(1 * time.Second): 182 | break 183 | } 184 | break 185 | case <-time.After(1 * time.Second): 186 | break 187 | } 188 | 189 | if !requestRecieved { 190 | t.Errorf("Host2 request not sent or recieved. ") 191 | } 192 | 193 | } 194 | 195 | func TestSendMessage(t *testing.T) { 196 | rand.Seed(666) 197 | port := rand.Intn(100) + 10000 198 | 199 | host1 := makeTestNodePort(port) 200 | host2 := makeTestNodePort(port + 1) 201 | 202 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 203 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 204 | 205 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 206 | 207 | host2Peer := &Peer{ 208 | peerID: host2.ID(), 209 | username: "host2"} 210 | 211 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 212 | 213 | messageRecieved := false 214 | 215 | select { 216 | case <-req.success: 217 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 218 | val, _ := host2.channels.Get("test") 219 | channel := val.(*Channel) 220 | select { 221 | // Just testing if the request was recieved at all. Ideally it should be 222 | // accepted in this scenario (first user starting transmisison), but 223 | // that's not what we're testing 224 | case <-req2.success: 225 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 226 | select { 227 | case <-req3.success: 228 | messageRecieved = true 229 | break 230 | case <-channel.output.messageQueue: 231 | messageRecieved = true 232 | break 233 | case <-time.After(3 * time.Second): 234 | break 235 | } 236 | break 237 | case <-time.After(3 * time.Second): 238 | break 239 | } 240 | break 241 | case <-time.After(3 * time.Second): 242 | break 243 | } 244 | 245 | if !messageRecieved { 246 | t.Errorf("Host2 message not recieved. ") 247 | } 248 | 249 | } 250 | 251 | func TestEndTransmission(t *testing.T) { 252 | rand.Seed(666) 253 | port := rand.Intn(100) + 10000 254 | 255 | host1 := makeTestNodePort(port) 256 | host2 := makeTestNodePort(port + 1) 257 | 258 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 259 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 260 | 261 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 262 | 263 | host2Peer := &Peer{ 264 | peerID: host2.ID(), 265 | username: "host2"} 266 | 267 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 268 | 269 | transmissionEnded := false 270 | 271 | select { 272 | case <-req.success: 273 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 274 | select { 275 | // Just testing if the request was recieved at all. Ideally it should be 276 | // accepted in this scenario (first user starting transmisison), but 277 | // that's not what we're testing 278 | case <-req2.success: 279 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 280 | val, _ := host1.channels.Get("test") 281 | channel := val.(*Channel) 282 | 283 | select { 284 | case <-req3.success: 285 | host2.EndTransmission(host2Peer, host1.ID(), "test") 286 | select { 287 | case <-time.After(3 * time.Second): 288 | channel.RLock() 289 | if channel.currentTransmission == nil { 290 | transmissionEnded = true 291 | } 292 | channel.RUnlock() 293 | break 294 | } 295 | break 296 | case <-time.After(3 * time.Second): 297 | break 298 | } 299 | break 300 | case <-time.After(3 * time.Second): 301 | break 302 | } 303 | break 304 | case <-time.After(3 * time.Second): 305 | break 306 | } 307 | 308 | if !transmissionEnded { 309 | t.Errorf("Host2 transmission not ended. ") 310 | } 311 | 312 | } 313 | 314 | // need to have 3 hosts here 315 | // the 2nd compete 316 | func TestCooldown(t *testing.T) { 317 | rand.Seed(666) 318 | port := rand.Intn(100) + 10000 319 | 320 | host1 := makeTestNodePort(port) 321 | host2 := makeTestNodePort(port + 1) 322 | 323 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 324 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 325 | config := DefaultChannelConfig() 326 | config.HistorySize = 0 327 | config.CooldownPeriod = 8 328 | 329 | host1.CreateChannel(&Peer{}, "test", config) 330 | 331 | host2Peer := &Peer{ 332 | peerID: host2.ID(), 333 | username: "host2"} 334 | 335 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 336 | 337 | var transmissionDenied *Response 338 | 339 | select { 340 | case <-req.success: 341 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 342 | select { 343 | // Just testing if the request was recieved at all. Ideally it should be 344 | // accepted in this scenario (first user starting transmisison), but 345 | // that's not what we're testing 346 | case <-req2.success: 347 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 348 | select { 349 | case <-req3.success: 350 | host2.EndTransmission(host2Peer, host1.ID(), "test") 351 | select { 352 | case <-time.After(3 * time.Second): 353 | req4, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 354 | select { 355 | case transmissionDenied = <-req4.fail: 356 | break 357 | case <-time.After(1 * time.Second): 358 | break 359 | } 360 | break 361 | } 362 | break 363 | case <-time.After(3 * time.Second): 364 | break 365 | } 366 | break 367 | case <-time.After(3 * time.Second): 368 | break 369 | } 370 | break 371 | case <-time.After(3 * time.Second): 372 | break 373 | } 374 | 375 | if transmissionDenied == nil || transmissionDenied.errorCode != CooldownError { 376 | t.Errorf("Host2 transmission was not denied upon violating cooldown. ") 377 | } 378 | 379 | } 380 | 381 | func TestMessageLimit(t *testing.T) { 382 | rand.Seed(666) 383 | port := rand.Intn(100) + 10000 384 | 385 | host1 := makeTestNodePort(port) 386 | host2 := makeTestNodePort(port + 1) 387 | 388 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 389 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 390 | 391 | config := DefaultChannelConfig() 392 | config.MaxMessageRatio = 10000 393 | 394 | host1.CreateChannel(&Peer{}, "test", config) 395 | 396 | host2Peer := &Peer{ 397 | peerID: host2.ID(), 398 | username: "host2"} 399 | 400 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 401 | 402 | var messageLimitFailed *Response 403 | 404 | select { 405 | case <-req.success: 406 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 407 | select { 408 | // Just testing if the request was recieved at all. Ideally it should be 409 | // accepted in this scenario (first user starting transmisison), but 410 | // that's not what we're testing 411 | case <-req2.success: 412 | for i := 0; i < config.MessageLimit; i++ { 413 | host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 414 | } 415 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 416 | select { 417 | case messageLimitFailed = <-req3.fail: 418 | break 419 | case <-time.After(3 * time.Second): 420 | break 421 | } 422 | break 423 | case <-time.After(3 * time.Second): 424 | break 425 | } 426 | break 427 | case <-time.After(3 * time.Second): 428 | break 429 | } 430 | 431 | if messageLimitFailed == nil || messageLimitFailed.errorCode != MessageLimitError { 432 | t.Errorf("Host limit did not deny. ") 433 | } 434 | 435 | } 436 | 437 | func TestTimeLimit(t *testing.T) { 438 | rand.Seed(666) 439 | port := rand.Intn(100) + 10000 440 | 441 | host1 := makeTestNodePort(port) 442 | host2 := makeTestNodePort(port + 1) 443 | 444 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 445 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 446 | config := DefaultChannelConfig() 447 | config.TimeLimit = config.TimeLimit + 1 448 | 449 | host1.CreateChannel(&Peer{}, "test", DefaultChannelConfig()) 450 | 451 | //host2IDString := host2.ID().String() 452 | 453 | host2Peer := &Peer{ 454 | peerID: host2.ID(), 455 | username: "host2"} 456 | 457 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 458 | 459 | var timeLimitDeny *Response 460 | 461 | select { 462 | case <-req.success: 463 | host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 464 | timeLimit := time.Duration(config.TimeLimit) * time.Second 465 | <-time.After(timeLimit) 466 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 467 | 468 | select { 469 | // Just testing if the request was recieved at all. Ideally it should be 470 | // accepted in this scenario (first user starting transmisison), but 471 | // that's not what we're testing 472 | case timeLimitDeny = <-req3.fail: 473 | break 474 | } 475 | break 476 | case <-time.After(1 * time.Second): 477 | break 478 | } 479 | 480 | if timeLimitDeny == nil || timeLimitDeny.errorCode != TimeLimitError { 481 | t.Errorf("Message was not denied after time limit . ") 482 | } 483 | 484 | } 485 | 486 | func TestRatioLimit(t *testing.T) { 487 | rand.Seed(666) 488 | port := rand.Intn(100) + 10000 489 | 490 | host1 := makeTestNodePort(port) 491 | host2 := makeTestNodePort(port + 1) 492 | 493 | host1.Peerstore().AddAddrs(host2.ID(), host2.Addrs(), ps.PermanentAddrTTL) 494 | host2.Peerstore().AddAddrs(host1.ID(), host1.Addrs(), ps.PermanentAddrTTL) 495 | 496 | config := DefaultChannelConfig() 497 | config.MessageLimit = 10000 498 | 499 | host1.CreateChannel(&Peer{}, "test", config) 500 | 501 | host2Peer := &Peer{ 502 | peerID: host2.ID(), 503 | username: "host2"} 504 | 505 | req, _ := host2.JoinChannel(host2Peer, host1.ID(), "test") 506 | 507 | var ratioLimitFailed *Response 508 | 509 | select { 510 | case <-req.success: 511 | req2, _ := host2.SendTransmissionRequest(host2Peer, host1.ID(), "test") 512 | select { 513 | // Just testing if the request was recieved at all. Ideally it should be 514 | // accepted in this scenario (first user starting transmisison), but 515 | // that's not what we're testing 516 | case <-req2.success: 517 | for i := 1; i < 20; i++ { 518 | host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 519 | } 520 | req3, _ := host2.SendMessage(host2Peer, host1.ID(), "test", "Hello World!") 521 | select { 522 | case ratioLimitFailed = <-req3.fail: 523 | break 524 | case <-time.After(3 * time.Second): 525 | break 526 | } 527 | break 528 | case <-time.After(3 * time.Second): 529 | break 530 | } 531 | break 532 | case <-time.After(3 * time.Second): 533 | break 534 | } 535 | 536 | if ratioLimitFailed == nil || ratioLimitFailed.errorCode != RatioError { 537 | t.Errorf("Ratio limit did not deny. ") 538 | } 539 | 540 | } 541 | -------------------------------------------------------------------------------- /node.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "log" 6 | "time" 7 | 8 | p2p "github.com/assemblaj/Multilogue/pb" 9 | 10 | "github.com/gogo/protobuf/proto" 11 | crypto "github.com/libp2p/go-libp2p-crypto" 12 | host "github.com/libp2p/go-libp2p-host" 13 | inet "github.com/libp2p/go-libp2p-net" 14 | peer "github.com/libp2p/go-libp2p-peer" 15 | protobufCodec "github.com/multiformats/go-multicodec/protobuf" 16 | ) 17 | 18 | // node client version 19 | const clientVersion = "go-p2p-node/0.0.1" 20 | 21 | // Node type - a p2p host implementing one or more p2p protocols 22 | type Node struct { 23 | host.Host // lib-p2p host 24 | *MultilogueProtocol // ping protocol impl 25 | // add other protocols here... 26 | } 27 | 28 | // Create a new node with its implemented protocols 29 | func NewNode(host host.Host) *Node { 30 | node := &Node{Host: host} 31 | node.MultilogueProtocol = NewMultilogueProtocol(node) 32 | return node 33 | } 34 | 35 | // Authenticate incoming p2p message 36 | // message: a protobufs go data object 37 | // data: common p2p message data 38 | func (n *Node) authenticateMessage(message proto.Message, data *p2p.MessageData) bool { 39 | // store a temp ref to signature and remove it from message data 40 | // sign is a string to allow easy reset to zero-value (empty string) 41 | sign := data.Sign 42 | data.Sign = nil 43 | 44 | // marshall data without the signature to protobufs3 binary format 45 | bin, err := proto.Marshal(message) 46 | if err != nil { 47 | log.Println(err, "failed to marshal pb message") 48 | return false 49 | } 50 | 51 | // restore sig in message data (for possible future use) 52 | data.Sign = sign 53 | 54 | // restore peer id binary format from base58 encoded node id data 55 | peerId, err := peer.IDB58Decode(data.NodeId) 56 | if err != nil { 57 | log.Println(err, "Failed to decode node id from base58") 58 | return false 59 | } 60 | 61 | // verify the data was authored by the signing peer identified by the public key 62 | // and signature included in the message 63 | return n.verifyData(bin, []byte(sign), peerId, data.NodePubKey) 64 | } 65 | 66 | // sign an outgoing p2p message payload 67 | func (n *Node) signProtoMessage(message proto.Message) ([]byte, error) { 68 | data, err := proto.Marshal(message) 69 | if err != nil { 70 | return nil, err 71 | } 72 | return n.signData(data) 73 | } 74 | 75 | // sign binary data using the local node's private key 76 | func (n *Node) signData(data []byte) ([]byte, error) { 77 | key := n.Peerstore().PrivKey(n.ID()) 78 | res, err := key.Sign(data) 79 | return res, err 80 | } 81 | 82 | // Verify incoming p2p message data integrity 83 | // data: data to verify 84 | // signature: author signature provided in the message payload 85 | // peerId: author peer id from the message payload 86 | // pubKeyData: author public key from the message payload 87 | func (n *Node) verifyData(data []byte, signature []byte, peerId peer.ID, pubKeyData []byte) bool { 88 | key, err := crypto.UnmarshalPublicKey(pubKeyData) 89 | if err != nil { 90 | log.Println(err, "Failed to extract key from message key data") 91 | return false 92 | } 93 | 94 | // extract node id from the provided public key 95 | idFromKey, err := peer.IDFromPublicKey(key) 96 | 97 | if err != nil { 98 | log.Println(err, "Failed to extract peer id from public key") 99 | return false 100 | } 101 | 102 | // verify that message author node id matches the provided node public key 103 | if idFromKey != peerId { 104 | log.Println(err, "Node id and provided public key mismatch") 105 | return false 106 | } 107 | 108 | res, err := key.Verify(data, signature) 109 | if err != nil { 110 | log.Println(err, "Error authenticating data") 111 | return false 112 | } 113 | 114 | return res 115 | } 116 | 117 | // helper method - generate message data shared between all node's p2p protocols 118 | // messageId: unique for requests, copied from request for responses 119 | func (n *Node) NewMessageData(messageId string, gossip bool) *p2p.MessageData { 120 | // Add protobufs bin data for message author public key 121 | // this is useful for authenticating messages forwarded by a node authored by another node 122 | nodePubKey, err := n.Peerstore().PubKey(n.ID()).Bytes() 123 | 124 | if err != nil { 125 | panic("Failed to get public key for sender from local peer store.") 126 | } 127 | 128 | return &p2p.MessageData{ClientVersion: clientVersion, 129 | NodeId: peer.IDB58Encode(n.ID()), 130 | NodePubKey: nodePubKey, 131 | Timestamp: time.Now().Unix(), 132 | Id: messageId, 133 | Gossip: gossip} 134 | } 135 | 136 | // helper method - writes a protobuf go data object to a network stream 137 | // data: reference of protobuf go data object to send (not the object itself) 138 | // s: network stream to write the data to 139 | func (n *Node) sendProtoMessage(data proto.Message, s inet.Stream) bool { 140 | writer := bufio.NewWriter(s) 141 | enc := protobufCodec.Multicodec(nil).Encoder(writer) 142 | err := enc.Encode(data) 143 | if err != nil { 144 | log.Println(err) 145 | return false 146 | } 147 | writer.Flush() 148 | return true 149 | } 150 | -------------------------------------------------------------------------------- /pb/p2p.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-gogo. DO NOT EDIT. 2 | // source: p2p.proto 3 | 4 | package protocols_p2p 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/gogo/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package 22 | 23 | // designed to be shared between all app protocols 24 | type MessageData struct { 25 | // shared between all requests 26 | ClientVersion string `protobuf:"bytes,1,opt,name=clientVersion,proto3" json:"clientVersion,omitempty"` 27 | Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 28 | Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` 29 | Gossip bool `protobuf:"varint,4,opt,name=gossip,proto3" json:"gossip,omitempty"` 30 | NodeId string `protobuf:"bytes,5,opt,name=nodeId,proto3" json:"nodeId,omitempty"` 31 | NodePubKey []byte `protobuf:"bytes,6,opt,name=nodePubKey,proto3" json:"nodePubKey,omitempty"` 32 | Sign []byte `protobuf:"bytes,7,opt,name=sign,proto3" json:"sign,omitempty"` 33 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 34 | XXX_unrecognized []byte `json:"-"` 35 | XXX_sizecache int32 `json:"-"` 36 | } 37 | 38 | func (m *MessageData) Reset() { *m = MessageData{} } 39 | func (m *MessageData) String() string { return proto.CompactTextString(m) } 40 | func (*MessageData) ProtoMessage() {} 41 | func (*MessageData) Descriptor() ([]byte, []int) { 42 | return fileDescriptor_e7fdddb109e6467a, []int{0} 43 | } 44 | func (m *MessageData) XXX_Unmarshal(b []byte) error { 45 | return xxx_messageInfo_MessageData.Unmarshal(m, b) 46 | } 47 | func (m *MessageData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 48 | return xxx_messageInfo_MessageData.Marshal(b, m, deterministic) 49 | } 50 | func (m *MessageData) XXX_Merge(src proto.Message) { 51 | xxx_messageInfo_MessageData.Merge(m, src) 52 | } 53 | func (m *MessageData) XXX_Size() int { 54 | return xxx_messageInfo_MessageData.Size(m) 55 | } 56 | func (m *MessageData) XXX_DiscardUnknown() { 57 | xxx_messageInfo_MessageData.DiscardUnknown(m) 58 | } 59 | 60 | var xxx_messageInfo_MessageData proto.InternalMessageInfo 61 | 62 | func (m *MessageData) GetClientVersion() string { 63 | if m != nil { 64 | return m.ClientVersion 65 | } 66 | return "" 67 | } 68 | 69 | func (m *MessageData) GetTimestamp() int64 { 70 | if m != nil { 71 | return m.Timestamp 72 | } 73 | return 0 74 | } 75 | 76 | func (m *MessageData) GetId() string { 77 | if m != nil { 78 | return m.Id 79 | } 80 | return "" 81 | } 82 | 83 | func (m *MessageData) GetGossip() bool { 84 | if m != nil { 85 | return m.Gossip 86 | } 87 | return false 88 | } 89 | 90 | func (m *MessageData) GetNodeId() string { 91 | if m != nil { 92 | return m.NodeId 93 | } 94 | return "" 95 | } 96 | 97 | func (m *MessageData) GetNodePubKey() []byte { 98 | if m != nil { 99 | return m.NodePubKey 100 | } 101 | return nil 102 | } 103 | 104 | func (m *MessageData) GetSign() []byte { 105 | if m != nil { 106 | return m.Sign 107 | } 108 | return nil 109 | } 110 | 111 | //// Multilogue protocol 112 | type ClientData struct { 113 | PeerId []byte `protobuf:"bytes,1,opt,name=peerId,proto3" json:"peerId,omitempty"` 114 | Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` 115 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 116 | XXX_unrecognized []byte `json:"-"` 117 | XXX_sizecache int32 `json:"-"` 118 | } 119 | 120 | func (m *ClientData) Reset() { *m = ClientData{} } 121 | func (m *ClientData) String() string { return proto.CompactTextString(m) } 122 | func (*ClientData) ProtoMessage() {} 123 | func (*ClientData) Descriptor() ([]byte, []int) { 124 | return fileDescriptor_e7fdddb109e6467a, []int{1} 125 | } 126 | func (m *ClientData) XXX_Unmarshal(b []byte) error { 127 | return xxx_messageInfo_ClientData.Unmarshal(m, b) 128 | } 129 | func (m *ClientData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 130 | return xxx_messageInfo_ClientData.Marshal(b, m, deterministic) 131 | } 132 | func (m *ClientData) XXX_Merge(src proto.Message) { 133 | xxx_messageInfo_ClientData.Merge(m, src) 134 | } 135 | func (m *ClientData) XXX_Size() int { 136 | return xxx_messageInfo_ClientData.Size(m) 137 | } 138 | func (m *ClientData) XXX_DiscardUnknown() { 139 | xxx_messageInfo_ClientData.DiscardUnknown(m) 140 | } 141 | 142 | var xxx_messageInfo_ClientData proto.InternalMessageInfo 143 | 144 | func (m *ClientData) GetPeerId() []byte { 145 | if m != nil { 146 | return m.PeerId 147 | } 148 | return nil 149 | } 150 | 151 | func (m *ClientData) GetUsername() string { 152 | if m != nil { 153 | return m.Username 154 | } 155 | return "" 156 | } 157 | 158 | type HostData struct { 159 | ChannelId string `protobuf:"bytes,1,opt,name=channelId,proto3" json:"channelId,omitempty"` 160 | PeerId []byte `protobuf:"bytes,2,opt,name=peerId,proto3" json:"peerId,omitempty"` 161 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 162 | XXX_unrecognized []byte `json:"-"` 163 | XXX_sizecache int32 `json:"-"` 164 | } 165 | 166 | func (m *HostData) Reset() { *m = HostData{} } 167 | func (m *HostData) String() string { return proto.CompactTextString(m) } 168 | func (*HostData) ProtoMessage() {} 169 | func (*HostData) Descriptor() ([]byte, []int) { 170 | return fileDescriptor_e7fdddb109e6467a, []int{2} 171 | } 172 | func (m *HostData) XXX_Unmarshal(b []byte) error { 173 | return xxx_messageInfo_HostData.Unmarshal(m, b) 174 | } 175 | func (m *HostData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 176 | return xxx_messageInfo_HostData.Marshal(b, m, deterministic) 177 | } 178 | func (m *HostData) XXX_Merge(src proto.Message) { 179 | xxx_messageInfo_HostData.Merge(m, src) 180 | } 181 | func (m *HostData) XXX_Size() int { 182 | return xxx_messageInfo_HostData.Size(m) 183 | } 184 | func (m *HostData) XXX_DiscardUnknown() { 185 | xxx_messageInfo_HostData.DiscardUnknown(m) 186 | } 187 | 188 | var xxx_messageInfo_HostData proto.InternalMessageInfo 189 | 190 | func (m *HostData) GetChannelId() string { 191 | if m != nil { 192 | return m.ChannelId 193 | } 194 | return "" 195 | } 196 | 197 | func (m *HostData) GetPeerId() []byte { 198 | if m != nil { 199 | return m.PeerId 200 | } 201 | return nil 202 | } 203 | 204 | // a protocol define a set of reuqest and responses 205 | type ClientSendMessage struct { 206 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 207 | // method specific data 208 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 209 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 210 | Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` 211 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 212 | XXX_unrecognized []byte `json:"-"` 213 | XXX_sizecache int32 `json:"-"` 214 | } 215 | 216 | func (m *ClientSendMessage) Reset() { *m = ClientSendMessage{} } 217 | func (m *ClientSendMessage) String() string { return proto.CompactTextString(m) } 218 | func (*ClientSendMessage) ProtoMessage() {} 219 | func (*ClientSendMessage) Descriptor() ([]byte, []int) { 220 | return fileDescriptor_e7fdddb109e6467a, []int{3} 221 | } 222 | func (m *ClientSendMessage) XXX_Unmarshal(b []byte) error { 223 | return xxx_messageInfo_ClientSendMessage.Unmarshal(m, b) 224 | } 225 | func (m *ClientSendMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 226 | return xxx_messageInfo_ClientSendMessage.Marshal(b, m, deterministic) 227 | } 228 | func (m *ClientSendMessage) XXX_Merge(src proto.Message) { 229 | xxx_messageInfo_ClientSendMessage.Merge(m, src) 230 | } 231 | func (m *ClientSendMessage) XXX_Size() int { 232 | return xxx_messageInfo_ClientSendMessage.Size(m) 233 | } 234 | func (m *ClientSendMessage) XXX_DiscardUnknown() { 235 | xxx_messageInfo_ClientSendMessage.DiscardUnknown(m) 236 | } 237 | 238 | var xxx_messageInfo_ClientSendMessage proto.InternalMessageInfo 239 | 240 | func (m *ClientSendMessage) GetMessageData() *MessageData { 241 | if m != nil { 242 | return m.MessageData 243 | } 244 | return nil 245 | } 246 | 247 | func (m *ClientSendMessage) GetClientData() *ClientData { 248 | if m != nil { 249 | return m.ClientData 250 | } 251 | return nil 252 | } 253 | 254 | func (m *ClientSendMessage) GetHostData() *HostData { 255 | if m != nil { 256 | return m.HostData 257 | } 258 | return nil 259 | } 260 | 261 | func (m *ClientSendMessage) GetMessage() string { 262 | if m != nil { 263 | return m.Message 264 | } 265 | return "" 266 | } 267 | 268 | type ClientTransmissionStart struct { 269 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 270 | // method specific data 271 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 272 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 273 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 274 | XXX_unrecognized []byte `json:"-"` 275 | XXX_sizecache int32 `json:"-"` 276 | } 277 | 278 | func (m *ClientTransmissionStart) Reset() { *m = ClientTransmissionStart{} } 279 | func (m *ClientTransmissionStart) String() string { return proto.CompactTextString(m) } 280 | func (*ClientTransmissionStart) ProtoMessage() {} 281 | func (*ClientTransmissionStart) Descriptor() ([]byte, []int) { 282 | return fileDescriptor_e7fdddb109e6467a, []int{4} 283 | } 284 | func (m *ClientTransmissionStart) XXX_Unmarshal(b []byte) error { 285 | return xxx_messageInfo_ClientTransmissionStart.Unmarshal(m, b) 286 | } 287 | func (m *ClientTransmissionStart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 288 | return xxx_messageInfo_ClientTransmissionStart.Marshal(b, m, deterministic) 289 | } 290 | func (m *ClientTransmissionStart) XXX_Merge(src proto.Message) { 291 | xxx_messageInfo_ClientTransmissionStart.Merge(m, src) 292 | } 293 | func (m *ClientTransmissionStart) XXX_Size() int { 294 | return xxx_messageInfo_ClientTransmissionStart.Size(m) 295 | } 296 | func (m *ClientTransmissionStart) XXX_DiscardUnknown() { 297 | xxx_messageInfo_ClientTransmissionStart.DiscardUnknown(m) 298 | } 299 | 300 | var xxx_messageInfo_ClientTransmissionStart proto.InternalMessageInfo 301 | 302 | func (m *ClientTransmissionStart) GetMessageData() *MessageData { 303 | if m != nil { 304 | return m.MessageData 305 | } 306 | return nil 307 | } 308 | 309 | func (m *ClientTransmissionStart) GetClientData() *ClientData { 310 | if m != nil { 311 | return m.ClientData 312 | } 313 | return nil 314 | } 315 | 316 | func (m *ClientTransmissionStart) GetHostData() *HostData { 317 | if m != nil { 318 | return m.HostData 319 | } 320 | return nil 321 | } 322 | 323 | type ClientTransmissionEnd struct { 324 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 325 | // method specific data 326 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 327 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 328 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 329 | XXX_unrecognized []byte `json:"-"` 330 | XXX_sizecache int32 `json:"-"` 331 | } 332 | 333 | func (m *ClientTransmissionEnd) Reset() { *m = ClientTransmissionEnd{} } 334 | func (m *ClientTransmissionEnd) String() string { return proto.CompactTextString(m) } 335 | func (*ClientTransmissionEnd) ProtoMessage() {} 336 | func (*ClientTransmissionEnd) Descriptor() ([]byte, []int) { 337 | return fileDescriptor_e7fdddb109e6467a, []int{5} 338 | } 339 | func (m *ClientTransmissionEnd) XXX_Unmarshal(b []byte) error { 340 | return xxx_messageInfo_ClientTransmissionEnd.Unmarshal(m, b) 341 | } 342 | func (m *ClientTransmissionEnd) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 343 | return xxx_messageInfo_ClientTransmissionEnd.Marshal(b, m, deterministic) 344 | } 345 | func (m *ClientTransmissionEnd) XXX_Merge(src proto.Message) { 346 | xxx_messageInfo_ClientTransmissionEnd.Merge(m, src) 347 | } 348 | func (m *ClientTransmissionEnd) XXX_Size() int { 349 | return xxx_messageInfo_ClientTransmissionEnd.Size(m) 350 | } 351 | func (m *ClientTransmissionEnd) XXX_DiscardUnknown() { 352 | xxx_messageInfo_ClientTransmissionEnd.DiscardUnknown(m) 353 | } 354 | 355 | var xxx_messageInfo_ClientTransmissionEnd proto.InternalMessageInfo 356 | 357 | func (m *ClientTransmissionEnd) GetMessageData() *MessageData { 358 | if m != nil { 359 | return m.MessageData 360 | } 361 | return nil 362 | } 363 | 364 | func (m *ClientTransmissionEnd) GetClientData() *ClientData { 365 | if m != nil { 366 | return m.ClientData 367 | } 368 | return nil 369 | } 370 | 371 | func (m *ClientTransmissionEnd) GetHostData() *HostData { 372 | if m != nil { 373 | return m.HostData 374 | } 375 | return nil 376 | } 377 | 378 | type HostAcceptTransmission struct { 379 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 380 | // method specific data 381 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 382 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 383 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 384 | XXX_unrecognized []byte `json:"-"` 385 | XXX_sizecache int32 `json:"-"` 386 | } 387 | 388 | func (m *HostAcceptTransmission) Reset() { *m = HostAcceptTransmission{} } 389 | func (m *HostAcceptTransmission) String() string { return proto.CompactTextString(m) } 390 | func (*HostAcceptTransmission) ProtoMessage() {} 391 | func (*HostAcceptTransmission) Descriptor() ([]byte, []int) { 392 | return fileDescriptor_e7fdddb109e6467a, []int{6} 393 | } 394 | func (m *HostAcceptTransmission) XXX_Unmarshal(b []byte) error { 395 | return xxx_messageInfo_HostAcceptTransmission.Unmarshal(m, b) 396 | } 397 | func (m *HostAcceptTransmission) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 398 | return xxx_messageInfo_HostAcceptTransmission.Marshal(b, m, deterministic) 399 | } 400 | func (m *HostAcceptTransmission) XXX_Merge(src proto.Message) { 401 | xxx_messageInfo_HostAcceptTransmission.Merge(m, src) 402 | } 403 | func (m *HostAcceptTransmission) XXX_Size() int { 404 | return xxx_messageInfo_HostAcceptTransmission.Size(m) 405 | } 406 | func (m *HostAcceptTransmission) XXX_DiscardUnknown() { 407 | xxx_messageInfo_HostAcceptTransmission.DiscardUnknown(m) 408 | } 409 | 410 | var xxx_messageInfo_HostAcceptTransmission proto.InternalMessageInfo 411 | 412 | func (m *HostAcceptTransmission) GetMessageData() *MessageData { 413 | if m != nil { 414 | return m.MessageData 415 | } 416 | return nil 417 | } 418 | 419 | func (m *HostAcceptTransmission) GetClientData() *ClientData { 420 | if m != nil { 421 | return m.ClientData 422 | } 423 | return nil 424 | } 425 | 426 | func (m *HostAcceptTransmission) GetHostData() *HostData { 427 | if m != nil { 428 | return m.HostData 429 | } 430 | return nil 431 | } 432 | 433 | type HostDenyTransmission struct { 434 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 435 | // method specific data 436 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 437 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 438 | ErrorCode int32 `protobuf:"varint,4,opt,name=errorCode,proto3" json:"errorCode,omitempty"` 439 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 440 | XXX_unrecognized []byte `json:"-"` 441 | XXX_sizecache int32 `json:"-"` 442 | } 443 | 444 | func (m *HostDenyTransmission) Reset() { *m = HostDenyTransmission{} } 445 | func (m *HostDenyTransmission) String() string { return proto.CompactTextString(m) } 446 | func (*HostDenyTransmission) ProtoMessage() {} 447 | func (*HostDenyTransmission) Descriptor() ([]byte, []int) { 448 | return fileDescriptor_e7fdddb109e6467a, []int{7} 449 | } 450 | func (m *HostDenyTransmission) XXX_Unmarshal(b []byte) error { 451 | return xxx_messageInfo_HostDenyTransmission.Unmarshal(m, b) 452 | } 453 | func (m *HostDenyTransmission) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 454 | return xxx_messageInfo_HostDenyTransmission.Marshal(b, m, deterministic) 455 | } 456 | func (m *HostDenyTransmission) XXX_Merge(src proto.Message) { 457 | xxx_messageInfo_HostDenyTransmission.Merge(m, src) 458 | } 459 | func (m *HostDenyTransmission) XXX_Size() int { 460 | return xxx_messageInfo_HostDenyTransmission.Size(m) 461 | } 462 | func (m *HostDenyTransmission) XXX_DiscardUnknown() { 463 | xxx_messageInfo_HostDenyTransmission.DiscardUnknown(m) 464 | } 465 | 466 | var xxx_messageInfo_HostDenyTransmission proto.InternalMessageInfo 467 | 468 | func (m *HostDenyTransmission) GetMessageData() *MessageData { 469 | if m != nil { 470 | return m.MessageData 471 | } 472 | return nil 473 | } 474 | 475 | func (m *HostDenyTransmission) GetClientData() *ClientData { 476 | if m != nil { 477 | return m.ClientData 478 | } 479 | return nil 480 | } 481 | 482 | func (m *HostDenyTransmission) GetHostData() *HostData { 483 | if m != nil { 484 | return m.HostData 485 | } 486 | return nil 487 | } 488 | 489 | func (m *HostDenyTransmission) GetErrorCode() int32 { 490 | if m != nil { 491 | return m.ErrorCode 492 | } 493 | return 0 494 | } 495 | 496 | type HostBroadcastMessage struct { 497 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 498 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 499 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 500 | Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"` 501 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 502 | XXX_unrecognized []byte `json:"-"` 503 | XXX_sizecache int32 `json:"-"` 504 | } 505 | 506 | func (m *HostBroadcastMessage) Reset() { *m = HostBroadcastMessage{} } 507 | func (m *HostBroadcastMessage) String() string { return proto.CompactTextString(m) } 508 | func (*HostBroadcastMessage) ProtoMessage() {} 509 | func (*HostBroadcastMessage) Descriptor() ([]byte, []int) { 510 | return fileDescriptor_e7fdddb109e6467a, []int{8} 511 | } 512 | func (m *HostBroadcastMessage) XXX_Unmarshal(b []byte) error { 513 | return xxx_messageInfo_HostBroadcastMessage.Unmarshal(m, b) 514 | } 515 | func (m *HostBroadcastMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 516 | return xxx_messageInfo_HostBroadcastMessage.Marshal(b, m, deterministic) 517 | } 518 | func (m *HostBroadcastMessage) XXX_Merge(src proto.Message) { 519 | xxx_messageInfo_HostBroadcastMessage.Merge(m, src) 520 | } 521 | func (m *HostBroadcastMessage) XXX_Size() int { 522 | return xxx_messageInfo_HostBroadcastMessage.Size(m) 523 | } 524 | func (m *HostBroadcastMessage) XXX_DiscardUnknown() { 525 | xxx_messageInfo_HostBroadcastMessage.DiscardUnknown(m) 526 | } 527 | 528 | var xxx_messageInfo_HostBroadcastMessage proto.InternalMessageInfo 529 | 530 | func (m *HostBroadcastMessage) GetMessageData() *MessageData { 531 | if m != nil { 532 | return m.MessageData 533 | } 534 | return nil 535 | } 536 | 537 | func (m *HostBroadcastMessage) GetClientData() *ClientData { 538 | if m != nil { 539 | return m.ClientData 540 | } 541 | return nil 542 | } 543 | 544 | func (m *HostBroadcastMessage) GetHostData() *HostData { 545 | if m != nil { 546 | return m.HostData 547 | } 548 | return nil 549 | } 550 | 551 | func (m *HostBroadcastMessage) GetMessage() string { 552 | if m != nil { 553 | return m.Message 554 | } 555 | return "" 556 | } 557 | 558 | type ClientJoinChannel struct { 559 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 560 | // method specific data 561 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 562 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 563 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 564 | XXX_unrecognized []byte `json:"-"` 565 | XXX_sizecache int32 `json:"-"` 566 | } 567 | 568 | func (m *ClientJoinChannel) Reset() { *m = ClientJoinChannel{} } 569 | func (m *ClientJoinChannel) String() string { return proto.CompactTextString(m) } 570 | func (*ClientJoinChannel) ProtoMessage() {} 571 | func (*ClientJoinChannel) Descriptor() ([]byte, []int) { 572 | return fileDescriptor_e7fdddb109e6467a, []int{9} 573 | } 574 | func (m *ClientJoinChannel) XXX_Unmarshal(b []byte) error { 575 | return xxx_messageInfo_ClientJoinChannel.Unmarshal(m, b) 576 | } 577 | func (m *ClientJoinChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 578 | return xxx_messageInfo_ClientJoinChannel.Marshal(b, m, deterministic) 579 | } 580 | func (m *ClientJoinChannel) XXX_Merge(src proto.Message) { 581 | xxx_messageInfo_ClientJoinChannel.Merge(m, src) 582 | } 583 | func (m *ClientJoinChannel) XXX_Size() int { 584 | return xxx_messageInfo_ClientJoinChannel.Size(m) 585 | } 586 | func (m *ClientJoinChannel) XXX_DiscardUnknown() { 587 | xxx_messageInfo_ClientJoinChannel.DiscardUnknown(m) 588 | } 589 | 590 | var xxx_messageInfo_ClientJoinChannel proto.InternalMessageInfo 591 | 592 | func (m *ClientJoinChannel) GetMessageData() *MessageData { 593 | if m != nil { 594 | return m.MessageData 595 | } 596 | return nil 597 | } 598 | 599 | func (m *ClientJoinChannel) GetClientData() *ClientData { 600 | if m != nil { 601 | return m.ClientData 602 | } 603 | return nil 604 | } 605 | 606 | func (m *ClientJoinChannel) GetHostData() *HostData { 607 | if m != nil { 608 | return m.HostData 609 | } 610 | return nil 611 | } 612 | 613 | type ClientLeaveChannel struct { 614 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 615 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 616 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 617 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 618 | XXX_unrecognized []byte `json:"-"` 619 | XXX_sizecache int32 `json:"-"` 620 | } 621 | 622 | func (m *ClientLeaveChannel) Reset() { *m = ClientLeaveChannel{} } 623 | func (m *ClientLeaveChannel) String() string { return proto.CompactTextString(m) } 624 | func (*ClientLeaveChannel) ProtoMessage() {} 625 | func (*ClientLeaveChannel) Descriptor() ([]byte, []int) { 626 | return fileDescriptor_e7fdddb109e6467a, []int{10} 627 | } 628 | func (m *ClientLeaveChannel) XXX_Unmarshal(b []byte) error { 629 | return xxx_messageInfo_ClientLeaveChannel.Unmarshal(m, b) 630 | } 631 | func (m *ClientLeaveChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 632 | return xxx_messageInfo_ClientLeaveChannel.Marshal(b, m, deterministic) 633 | } 634 | func (m *ClientLeaveChannel) XXX_Merge(src proto.Message) { 635 | xxx_messageInfo_ClientLeaveChannel.Merge(m, src) 636 | } 637 | func (m *ClientLeaveChannel) XXX_Size() int { 638 | return xxx_messageInfo_ClientLeaveChannel.Size(m) 639 | } 640 | func (m *ClientLeaveChannel) XXX_DiscardUnknown() { 641 | xxx_messageInfo_ClientLeaveChannel.DiscardUnknown(m) 642 | } 643 | 644 | var xxx_messageInfo_ClientLeaveChannel proto.InternalMessageInfo 645 | 646 | func (m *ClientLeaveChannel) GetMessageData() *MessageData { 647 | if m != nil { 648 | return m.MessageData 649 | } 650 | return nil 651 | } 652 | 653 | func (m *ClientLeaveChannel) GetClientData() *ClientData { 654 | if m != nil { 655 | return m.ClientData 656 | } 657 | return nil 658 | } 659 | 660 | func (m *ClientLeaveChannel) GetHostData() *HostData { 661 | if m != nil { 662 | return m.HostData 663 | } 664 | return nil 665 | } 666 | 667 | type HostAcceptClient struct { 668 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 669 | // method specific data 670 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 671 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 672 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 673 | XXX_unrecognized []byte `json:"-"` 674 | XXX_sizecache int32 `json:"-"` 675 | } 676 | 677 | func (m *HostAcceptClient) Reset() { *m = HostAcceptClient{} } 678 | func (m *HostAcceptClient) String() string { return proto.CompactTextString(m) } 679 | func (*HostAcceptClient) ProtoMessage() {} 680 | func (*HostAcceptClient) Descriptor() ([]byte, []int) { 681 | return fileDescriptor_e7fdddb109e6467a, []int{11} 682 | } 683 | func (m *HostAcceptClient) XXX_Unmarshal(b []byte) error { 684 | return xxx_messageInfo_HostAcceptClient.Unmarshal(m, b) 685 | } 686 | func (m *HostAcceptClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 687 | return xxx_messageInfo_HostAcceptClient.Marshal(b, m, deterministic) 688 | } 689 | func (m *HostAcceptClient) XXX_Merge(src proto.Message) { 690 | xxx_messageInfo_HostAcceptClient.Merge(m, src) 691 | } 692 | func (m *HostAcceptClient) XXX_Size() int { 693 | return xxx_messageInfo_HostAcceptClient.Size(m) 694 | } 695 | func (m *HostAcceptClient) XXX_DiscardUnknown() { 696 | xxx_messageInfo_HostAcceptClient.DiscardUnknown(m) 697 | } 698 | 699 | var xxx_messageInfo_HostAcceptClient proto.InternalMessageInfo 700 | 701 | func (m *HostAcceptClient) GetMessageData() *MessageData { 702 | if m != nil { 703 | return m.MessageData 704 | } 705 | return nil 706 | } 707 | 708 | func (m *HostAcceptClient) GetClientData() *ClientData { 709 | if m != nil { 710 | return m.ClientData 711 | } 712 | return nil 713 | } 714 | 715 | func (m *HostAcceptClient) GetHostData() *HostData { 716 | if m != nil { 717 | return m.HostData 718 | } 719 | return nil 720 | } 721 | 722 | type HostDenyClient struct { 723 | MessageData *MessageData `protobuf:"bytes,1,opt,name=messageData,proto3" json:"messageData,omitempty"` 724 | // method specific data 725 | ClientData *ClientData `protobuf:"bytes,2,opt,name=clientData,proto3" json:"clientData,omitempty"` 726 | HostData *HostData `protobuf:"bytes,3,opt,name=hostData,proto3" json:"hostData,omitempty"` 727 | ErrorCode int32 `protobuf:"varint,4,opt,name=errorCode,proto3" json:"errorCode,omitempty"` 728 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 729 | XXX_unrecognized []byte `json:"-"` 730 | XXX_sizecache int32 `json:"-"` 731 | } 732 | 733 | func (m *HostDenyClient) Reset() { *m = HostDenyClient{} } 734 | func (m *HostDenyClient) String() string { return proto.CompactTextString(m) } 735 | func (*HostDenyClient) ProtoMessage() {} 736 | func (*HostDenyClient) Descriptor() ([]byte, []int) { 737 | return fileDescriptor_e7fdddb109e6467a, []int{12} 738 | } 739 | func (m *HostDenyClient) XXX_Unmarshal(b []byte) error { 740 | return xxx_messageInfo_HostDenyClient.Unmarshal(m, b) 741 | } 742 | func (m *HostDenyClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 743 | return xxx_messageInfo_HostDenyClient.Marshal(b, m, deterministic) 744 | } 745 | func (m *HostDenyClient) XXX_Merge(src proto.Message) { 746 | xxx_messageInfo_HostDenyClient.Merge(m, src) 747 | } 748 | func (m *HostDenyClient) XXX_Size() int { 749 | return xxx_messageInfo_HostDenyClient.Size(m) 750 | } 751 | func (m *HostDenyClient) XXX_DiscardUnknown() { 752 | xxx_messageInfo_HostDenyClient.DiscardUnknown(m) 753 | } 754 | 755 | var xxx_messageInfo_HostDenyClient proto.InternalMessageInfo 756 | 757 | func (m *HostDenyClient) GetMessageData() *MessageData { 758 | if m != nil { 759 | return m.MessageData 760 | } 761 | return nil 762 | } 763 | 764 | func (m *HostDenyClient) GetClientData() *ClientData { 765 | if m != nil { 766 | return m.ClientData 767 | } 768 | return nil 769 | } 770 | 771 | func (m *HostDenyClient) GetHostData() *HostData { 772 | if m != nil { 773 | return m.HostData 774 | } 775 | return nil 776 | } 777 | 778 | func (m *HostDenyClient) GetErrorCode() int32 { 779 | if m != nil { 780 | return m.ErrorCode 781 | } 782 | return 0 783 | } 784 | 785 | func init() { 786 | proto.RegisterType((*MessageData)(nil), "protocols.p2p.MessageData") 787 | proto.RegisterType((*ClientData)(nil), "protocols.p2p.ClientData") 788 | proto.RegisterType((*HostData)(nil), "protocols.p2p.HostData") 789 | proto.RegisterType((*ClientSendMessage)(nil), "protocols.p2p.ClientSendMessage") 790 | proto.RegisterType((*ClientTransmissionStart)(nil), "protocols.p2p.ClientTransmissionStart") 791 | proto.RegisterType((*ClientTransmissionEnd)(nil), "protocols.p2p.ClientTransmissionEnd") 792 | proto.RegisterType((*HostAcceptTransmission)(nil), "protocols.p2p.HostAcceptTransmission") 793 | proto.RegisterType((*HostDenyTransmission)(nil), "protocols.p2p.HostDenyTransmission") 794 | proto.RegisterType((*HostBroadcastMessage)(nil), "protocols.p2p.HostBroadcastMessage") 795 | proto.RegisterType((*ClientJoinChannel)(nil), "protocols.p2p.ClientJoinChannel") 796 | proto.RegisterType((*ClientLeaveChannel)(nil), "protocols.p2p.ClientLeaveChannel") 797 | proto.RegisterType((*HostAcceptClient)(nil), "protocols.p2p.HostAcceptClient") 798 | proto.RegisterType((*HostDenyClient)(nil), "protocols.p2p.HostDenyClient") 799 | } 800 | 801 | func init() { proto.RegisterFile("p2p.proto", fileDescriptor_e7fdddb109e6467a) } 802 | 803 | var fileDescriptor_e7fdddb109e6467a = []byte{ 804 | // 477 bytes of a gzipped FileDescriptorProto 805 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x94, 0xcf, 0x6e, 0x13, 0x31, 806 | 0x10, 0xc6, 0xe5, 0xb4, 0x4d, 0xb3, 0xb3, 0x6d, 0x05, 0x16, 0xa4, 0x4b, 0x55, 0xa1, 0x68, 0xc5, 807 | 0x21, 0xa7, 0x1c, 0xb6, 0x27, 0x24, 0x0e, 0x85, 0x80, 0x44, 0xf9, 0x23, 0x21, 0x17, 0x71, 0x77, 808 | 0xd7, 0xa3, 0xd4, 0x52, 0xd6, 0xb6, 0xec, 0x2d, 0x52, 0xdf, 0x0e, 0x90, 0x80, 0x87, 0x00, 0x71, 809 | 0xe0, 0x49, 0xd0, 0x7a, 0x9d, 0xec, 0x26, 0x48, 0xdc, 0xcd, 0x29, 0x3b, 0x5f, 0x66, 0xc6, 0xf3, 810 | 0xdb, 0xf1, 0x7e, 0x90, 0x98, 0xc2, 0xcc, 0x8c, 0xd5, 0xb5, 0xa6, 0x87, 0xfe, 0xa7, 0xd4, 0x4b, 811 | 0x37, 0x33, 0x85, 0xc9, 0xbf, 0x12, 0x48, 0xdf, 0xa2, 0x73, 0x7c, 0x81, 0xcf, 0x79, 0xcd, 0xe9, 812 | 0x23, 0x38, 0x2c, 0x97, 0x12, 0x55, 0xfd, 0x01, 0xad, 0x93, 0x5a, 0x65, 0x64, 0x42, 0xa6, 0x09, 813 | 0xdb, 0x14, 0xe9, 0x29, 0x24, 0xb5, 0xac, 0xd0, 0xd5, 0xbc, 0x32, 0xd9, 0x60, 0x42, 0xa6, 0x3b, 814 | 0xac, 0x13, 0xe8, 0x11, 0x0c, 0xa4, 0xc8, 0x76, 0x7c, 0xe1, 0x40, 0x0a, 0x3a, 0x86, 0xe1, 0x42, 815 | 0x3b, 0x27, 0x4d, 0xb6, 0x3b, 0x21, 0xd3, 0x11, 0x0b, 0x51, 0xa3, 0x2b, 0x2d, 0xf0, 0x42, 0x64, 816 | 0x7b, 0x3e, 0x37, 0x44, 0xf4, 0x21, 0x40, 0xf3, 0xf4, 0xee, 0xe6, 0xea, 0x35, 0xde, 0x66, 0xc3, 817 | 0x09, 0x99, 0x1e, 0xb0, 0x9e, 0x42, 0x29, 0xec, 0x3a, 0xb9, 0x50, 0xd9, 0xbe, 0xff, 0xc7, 0x3f, 818 | 0xe7, 0xe7, 0x00, 0x73, 0x3f, 0xa2, 0xa7, 0x18, 0xc3, 0xd0, 0x20, 0xda, 0x0b, 0xe1, 0xc7, 0x3f, 819 | 0x60, 0x21, 0xa2, 0x27, 0x30, 0xba, 0x71, 0x68, 0x15, 0xaf, 0xd0, 0x8f, 0x9d, 0xb0, 0x75, 0x9c, 820 | 0x9f, 0xc3, 0xe8, 0xa5, 0x76, 0x6d, 0xfd, 0x29, 0x24, 0xe5, 0x35, 0x57, 0x0a, 0x97, 0xa1, 0x45, 821 | 0xc2, 0x3a, 0xa1, 0xd7, 0x7d, 0xd0, 0xef, 0x9e, 0xff, 0x20, 0x70, 0xb7, 0x1d, 0xe2, 0x12, 0x95, 822 | 0x08, 0x6f, 0x95, 0x3e, 0x81, 0xb4, 0xea, 0x5e, 0xb0, 0xef, 0x96, 0x16, 0x27, 0xb3, 0x8d, 0x35, 823 | 0xcc, 0x7a, 0x2b, 0x60, 0xfd, 0x74, 0xfa, 0x18, 0xa0, 0x5c, 0x73, 0xf9, 0xf3, 0xd2, 0xe2, 0xc1, 824 | 0x56, 0x71, 0x07, 0xce, 0x7a, 0xc9, 0xf4, 0x0c, 0x46, 0xd7, 0x01, 0xc8, 0x2f, 0x23, 0x2d, 0x8e, 825 | 0xb7, 0x0a, 0x57, 0xbc, 0x6c, 0x9d, 0x48, 0x33, 0xd8, 0x0f, 0xc7, 0xfb, 0x65, 0x25, 0x6c, 0x15, 826 | 0xe6, 0xdf, 0x09, 0x1c, 0xb7, 0x27, 0xbd, 0xb7, 0x5c, 0xb9, 0x4a, 0xba, 0xe6, 0x2a, 0x5c, 0xd6, 827 | 0xdc, 0xd6, 0x71, 0x31, 0x36, 0x77, 0xfe, 0xfe, 0xdf, 0x24, 0x2f, 0x94, 0x88, 0x8c, 0xe3, 0x1b, 828 | 0x81, 0x71, 0x23, 0x3f, 0x2d, 0x4b, 0x34, 0x1b, 0x2c, 0x91, 0x81, 0xfc, 0x26, 0x70, 0xcf, 0xcb, 829 | 0xa8, 0x6e, 0xe3, 0xc5, 0x68, 0x5c, 0x03, 0xad, 0xd5, 0x76, 0xae, 0x45, 0xfb, 0xf5, 0xec, 0xb1, 830 | 0x4e, 0xc8, 0x7f, 0x05, 0xc8, 0x67, 0x56, 0x73, 0x51, 0x72, 0x57, 0xff, 0x6f, 0x06, 0xf1, 0x79, 831 | 0x6d, 0x7f, 0xaf, 0xb4, 0x54, 0xf3, 0xd6, 0x2e, 0x23, 0xbb, 0x89, 0x5f, 0x08, 0xd0, 0xb6, 0xdf, 832 | 0x1b, 0xe4, 0x1f, 0x31, 0x4e, 0x88, 0x4f, 0x04, 0xee, 0x74, 0xbe, 0xd0, 0x76, 0x8e, 0x0c, 0xe1, 833 | 0x27, 0x81, 0xa3, 0x95, 0x23, 0xc4, 0x08, 0xf0, 0x6f, 0x2f, 0xb8, 0x1a, 0xfa, 0xfa, 0xb3, 0x3f, 834 | 0x01, 0x00, 0x00, 0xff, 0xff, 0x39, 0x96, 0xb0, 0x7b, 0x98, 0x09, 0x00, 0x00, 835 | } 836 | -------------------------------------------------------------------------------- /pb/p2p.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package protocols.p2p; 4 | 5 | // designed to be shared between all app protocols 6 | message MessageData { 7 | // shared between all requests 8 | string clientVersion = 1; // client version 9 | int64 timestamp = 2; // unix time 10 | string id = 3; // allows requesters to use request data when processing a response 11 | bool gossip = 4; // true to have receiver peer gossip the message to neighbors 12 | string nodeId = 5; // id of node that created the message (not the peer that may have sent it). =base58(multihash(nodePubKey)) 13 | bytes nodePubKey = 6; // Authoring node Secp256k1 public key (32bytes) - protobufs serielized 14 | bytes sign = 7; // signature of message data + method specific data by message authoring node. 15 | } 16 | 17 | //// Multilogue protocol 18 | message ClientData { 19 | bytes peerId = 1; 20 | string username = 2; 21 | } 22 | 23 | message HostData { 24 | string channelId = 1; 25 | bytes peerId = 2; 26 | } 27 | 28 | // a protocol define a set of reuqest and responses 29 | message ClientSendMessage { 30 | MessageData messageData = 1; 31 | 32 | // method specific data 33 | ClientData clientData = 2; 34 | HostData hostData = 3; 35 | 36 | string message = 4; 37 | } 38 | 39 | message ClientTransmissionStart { 40 | MessageData messageData = 1; 41 | 42 | // method specific data 43 | ClientData clientData = 2; 44 | HostData hostData = 3; 45 | 46 | } 47 | 48 | message ClientTransmissionEnd { 49 | MessageData messageData = 1; 50 | 51 | // method specific data 52 | ClientData clientData = 2; 53 | HostData hostData = 3; 54 | 55 | } 56 | 57 | 58 | message HostAcceptTransmission { 59 | MessageData messageData = 1; 60 | 61 | // method specific data 62 | ClientData clientData = 2; 63 | HostData hostData = 3; 64 | } 65 | 66 | message HostDenyTransmission { 67 | MessageData messageData = 1; 68 | 69 | // method specific data 70 | ClientData clientData = 2; 71 | HostData hostData = 3; 72 | 73 | int32 errorCode = 4; 74 | } 75 | 76 | message HostBroadcastMessage { 77 | MessageData messageData = 1; 78 | 79 | ClientData clientData = 2; 80 | HostData hostData = 3; 81 | 82 | string message = 4; 83 | 84 | } 85 | 86 | message ClientJoinChannel { 87 | MessageData messageData = 1; 88 | 89 | // method specific data 90 | ClientData clientData = 2; 91 | HostData hostData = 3; 92 | } 93 | 94 | message ClientLeaveChannel { 95 | MessageData messageData = 1; 96 | 97 | ClientData clientData = 2; 98 | HostData hostData = 3; 99 | } 100 | 101 | message HostAcceptClient { 102 | MessageData messageData = 1; 103 | 104 | // method specific data 105 | ClientData clientData = 2; 106 | HostData hostData = 3; 107 | } 108 | 109 | message HostDenyClient { 110 | MessageData messageData = 1; 111 | 112 | // method specific data 113 | ClientData clientData = 2; 114 | HostData hostData = 3; 115 | int32 errorCode = 4; 116 | } 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /ui.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/rand" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "time" 11 | 12 | "github.com/jroimartin/gocui" 13 | peer "github.com/libp2p/go-libp2p-peer" 14 | ) 15 | 16 | /* 17 | TODO: Some sort of map of Error code to message 18 | 19 | */ 20 | 21 | type UIColor struct { 22 | nameColor string 23 | } 24 | 25 | type ChatUI struct { 26 | node *Node 27 | colorMap map[string]*UIColor 28 | colorRandomizer *rand.Rand 29 | channelID string 30 | clientPeer *Peer 31 | hostPeerID peer.ID 32 | isTurn bool 33 | host *Peer 34 | hostMA string 35 | } 36 | 37 | func NewChatUI(node *Node, channelID string, clientPeer *Peer, hostPeerID peer.ID, hostMA string) *ChatUI { 38 | var seed = rand.NewSource(time.Now().UnixNano()) 39 | var randomizer = rand.New(seed) 40 | 41 | return &ChatUI{ 42 | node: node, 43 | colorMap: make(map[string]*UIColor), 44 | colorRandomizer: randomizer, 45 | channelID: channelID, 46 | clientPeer: clientPeer, 47 | host: &Peer{username: "*Channel*"}, 48 | hostPeerID: hostPeerID, 49 | hostMA: hostMA} 50 | } 51 | 52 | func (ui *ChatUI) randomColor() string { 53 | randColor := strconv.Itoa(ui.colorRandomizer.Intn(8)) 54 | bold := ui.colorRandomizer.Intn(2) == 0 55 | colorString := "\u001b[3" + randColor 56 | if bold { 57 | colorString = colorString + ";1" 58 | } 59 | return colorString + "m" 60 | } 61 | 62 | // Layout creates chat UI 63 | func (ui *ChatUI) Layout(g *gocui.Gui) error { 64 | maxX, maxY := g.Size() 65 | g.Cursor = true 66 | 67 | if messages, err := g.SetView("messages", 0, 0, maxX-1, maxY-5); err != nil { 68 | if err != gocui.ErrUnknownView { 69 | return err 70 | } 71 | messages.Title = ui.channelID + ": " + ui.hostMA 72 | messages.Autoscroll = true 73 | messages.Wrap = true 74 | 75 | messagesView, _ := g.View("messages") 76 | go ui.BroadcastPanel(g, messagesView, ui.channelID) 77 | 78 | } 79 | 80 | if input, err := g.SetView("input", 0, maxY-5, maxX-1, maxY-1); err != nil { 81 | if err != gocui.ErrUnknownView { 82 | return err 83 | } 84 | input.Title = ui.clientPeer.username + ": " 85 | input.Autoscroll = false 86 | input.Wrap = true 87 | input.Editable = true 88 | if _, err := g.SetCurrentView("input"); err != nil { 89 | return err 90 | } 91 | } 92 | 93 | return nil 94 | } 95 | 96 | func (ui *ChatUI) exit(g *gocui.Gui, v *gocui.View) error { 97 | ui.node.LeaveChannel(ui.clientPeer, ui.hostPeerID, ui.channelID) 98 | g.Close() 99 | os.Exit(0) 100 | return gocui.ErrQuit 101 | } 102 | 103 | func (ui *ChatUI) buildMessage(message *Message) string { 104 | color := ui.randomColor() 105 | return color + message.peer.username + ": \u001b[0m" + message.text 106 | } 107 | 108 | func (ui *ChatUI) sendMessage(g *gocui.Gui, v *gocui.View) error { 109 | if ui.isTurn { 110 | msg := strings.TrimSpace(v.Buffer()) 111 | 112 | req, _ := ui.node.SendMessage(ui.clientPeer, ui.hostPeerID, ui.channelID, msg) 113 | var resp *Response 114 | select { 115 | case <-req.success: 116 | // Clear input panel 117 | g.Update(func(g *gocui.Gui) error { 118 | v.Clear() 119 | v.SetCursor(0, 0) 120 | v.SetOrigin(0, 0) 121 | return nil 122 | }) 123 | break 124 | case resp = <-req.fail: 125 | ui.isTurn = false 126 | errorName := ProtocolErrorName(resp.errorCode) 127 | errorMsg := ui.clientPeer.username + " turn finished because " + errorName 128 | ui.displayMessage(g, v, ui.buildChannelMessage(errorMsg)) 129 | break 130 | case <-time.After(3 * time.Second): 131 | // Timeout 132 | ui.isTurn = false 133 | ui.displayMessage(g, v, ui.buildChannelMessage("Message request timed out. ")) 134 | break 135 | } 136 | } else { 137 | ui.displayMessage(g, v, ui.buildChannelMessage("Not your turn. ")) 138 | } 139 | 140 | return nil 141 | } 142 | 143 | func (ui *ChatUI) requestTransmission(g *gocui.Gui, v *gocui.View) error { 144 | if !ui.isTurn { 145 | req, reqSent := ui.node.SendTransmissionRequest(ui.clientPeer, ui.hostPeerID, ui.channelID) 146 | if reqSent { 147 | select { 148 | case <-req.success: 149 | ui.isTurn = true 150 | msg := ui.clientPeer.username + " turn strated " 151 | ui.displayMessage(g, v, ui.buildChannelMessage(msg)) 152 | case <-req.fail: 153 | ui.isTurn = false 154 | msg := "Can't start turn, " + ui.clientPeer.username 155 | ui.displayMessage(g, v, ui.buildChannelMessage(msg)) 156 | } 157 | } else { 158 | ui.isTurn = false 159 | ui.node.debugPrintln("Transmission request not completed.") 160 | } 161 | } 162 | return nil 163 | } 164 | 165 | func (ui *ChatUI) endTransmission(g *gocui.Gui, v *gocui.View) error { 166 | if ui.isTurn { 167 | ui.node.EndTransmission(ui.clientPeer, ui.hostPeerID, ui.channelID) 168 | msg := ui.clientPeer.username + " turn ended." 169 | ui.displayMessage(g, v, ui.buildChannelMessage(msg)) 170 | ui.isTurn = false 171 | } 172 | return nil 173 | } 174 | 175 | func (ui *ChatUI) StartUI() { 176 | g, err := gocui.NewGui(gocui.OutputNormal) 177 | if err != nil { 178 | log.Fatal(err) 179 | } 180 | defer g.Close() 181 | 182 | g.SetManagerFunc(ui.Layout) 183 | g.SetKeybinding("input", gocui.KeyEnter, gocui.ModNone, ui.sendMessage) 184 | g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, ui.exit) 185 | g.SetKeybinding("", gocui.KeyHome, gocui.ModNone, ui.requestTransmission) 186 | g.SetKeybinding("", gocui.KeyEnd, gocui.ModNone, ui.endTransmission) 187 | g.MainLoop() 188 | } 189 | 190 | // Displays messages broadcasted to channel 191 | func (ui *ChatUI) BroadcastPanel(g *gocui.Gui, v *gocui.View, channelID string) { 192 | val, exists := ui.node.channels.Get(channelID) 193 | if exists == false { 194 | log.Println("Channel not found.") 195 | return 196 | } 197 | 198 | channel := val.(*Channel) 199 | 200 | var message *Message 201 | for { 202 | select { 203 | case message = <-channel.output.messageQueue: 204 | msgString := "From UI, message reqcieved " + message.text 205 | ui.node.debugPrintln(msgString) 206 | 207 | ui.displayMessage(g, v, message) 208 | break 209 | } 210 | } 211 | } 212 | 213 | func (ui *ChatUI) buildChannelMessage(message string) *Message { 214 | return &Message{ 215 | peer: ui.host, 216 | timestamp: time.Now(), 217 | text: message} 218 | } 219 | 220 | func (ui *ChatUI) displayMessage(g *gocui.Gui, v *gocui.View, message *Message) { 221 | color, exists := ui.colorMap[message.peer.username] 222 | if !exists { 223 | color = &UIColor{ 224 | nameColor: ui.randomColor()} 225 | ui.colorMap[message.peer.username] = color 226 | } 227 | 228 | msg := color.nameColor + message.peer.username + 229 | "\u001b[0m" + ":" + message.text + "\u001b[0m" 230 | 231 | // Add to message panel 232 | messagesView, _ := g.View("messages") 233 | g.Update(func(g *gocui.Gui) error { 234 | fmt.Fprintln(messagesView, msg) 235 | return nil 236 | }) 237 | } 238 | --------------------------------------------------------------------------------