package connections import ( "cwtch.im/cwtch/model" "cwtch.im/cwtch/peer/peer" "cwtch.im/cwtch/protocol" "git.openprivacy.ca/openprivacy/libricochet-go" "git.openprivacy.ca/openprivacy/libricochet-go/channels" "git.openprivacy.ca/openprivacy/libricochet-go/connection" "git.openprivacy.ca/openprivacy/libricochet-go/identity" "log" "time" ) // PeerPeerConnection encapsulates a single outgoing Peer->Peer connection type PeerPeerConnection struct { connection.AutoConnectionHandler PeerHostname string state ConnectionState connection *connection.Connection profile *model.Profile } // NewPeerPeerConnection creates a new peer connection for the given hostname and profile. func NewPeerPeerConnection(peerhostname string, profile *model.Profile) *PeerPeerConnection { ppc := new(PeerPeerConnection) ppc.PeerHostname = peerhostname ppc.profile = profile ppc.Init() return ppc } // GetState returns the current connection state func (ppc *PeerPeerConnection) GetState() ConnectionState { return ppc.state } // ClientIdentity passes the given CwtchIdentity packet to the profile. func (ppc *PeerPeerConnection) ClientIdentity(ci *protocol.CwtchIdentity) { ppc.profile.AddCwtchIdentity(ppc.PeerHostname, ci) } // HandleGroupInvite passes the given group invite tothe profile func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite) { ppc.profile.ProcessInvite(gci, ppc.PeerHostname) } // GetClientIdentityPacket returns nil to avoid peers constantly sending identity packets to eachother. func (ppc *PeerPeerConnection) GetClientIdentityPacket() []byte { return nil } // SendGroupInvite sends the given serialized invite packet to the Peer func (ppc *PeerPeerConnection) SendGroupInvite(invite []byte) { ppc.connection.Do(func() error { channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound) if channel != nil { peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel) if ok { log.Printf("Sending group invite packet\n") peerchannel.SendMessage(invite) } } return nil }) } // Run manages the setup and teardown of a peer->peer connection func (ppc *PeerPeerConnection) Run() error { ppc.state = CONNECTING rc, err := goricochet.Open(ppc.PeerHostname) if err == nil { rc.TraceLog(false) ppc.connection = rc ppc.state = CONNECTED _, err := connection.HandleOutboundConnection(ppc.connection).ProcessAuthAsClient(identity.Initialize(ppc.profile.Name, ppc.profile.OnionPrivateKey)) if err == nil { ppc.state = AUTHENTICATED go func() { ppc.connection.Do(func() error { ppc.connection.RequestOpenChannel("im.cwtch.peer", &peer.CwtchPeerChannel{Handler: ppc}) return nil }) time.Sleep(time.Second * 1) ppc.connection.Do(func() error { channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound) if channel != nil { peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel) if ok { peerchannel.SendMessage(ppc.profile.GetCwtchIdentityPacket()) } } return nil }) }() ppc.connection.Process(ppc) } } ppc.state = FAILED return err } // Close closes the connection func (ppc *PeerPeerConnection) Close() { ppc.state = KILLED ppc.connection.Conn.Close() }