go-waku/examples/chat2/chat.go

171 lines
4.0 KiB
Go
Raw Normal View History

2021-04-04 17:06:17 +00:00
package main
import (
"chat2/pb"
"context"
"crypto/sha256"
2021-04-04 17:06:17 +00:00
"time"
"github.com/golang/protobuf/proto"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/status-im/go-waku/waku/v2/node"
2021-06-28 14:14:28 +00:00
"github.com/status-im/go-waku/waku/v2/protocol"
"github.com/status-im/go-waku/waku/v2/protocol/filter"
2021-04-22 00:12:51 +00:00
wpb "github.com/status-im/go-waku/waku/v2/protocol/pb"
2021-06-28 14:14:28 +00:00
"github.com/status-im/go-waku/waku/v2/protocol/relay"
2021-10-12 13:12:54 +00:00
"github.com/status-im/go-waku/waku/v2/utils"
"golang.org/x/crypto/pbkdf2"
2021-04-04 17:06:17 +00:00
)
// Chat represents a subscription to a single PubSub topic. Messages
// can be published to the topic with Chat.Publish, and received
// messages are pushed to the Messages channel.
type Chat struct {
// Messages is a channel of messages received from other peers in the chat room
Messages chan *pb.Chat2Message
2021-06-28 14:14:28 +00:00
C chan *protocol.Envelope
2021-04-04 17:06:17 +00:00
node *node.WakuNode
self peer.ID
contentTopic string
useV1Payload bool
2021-11-01 14:42:55 +00:00
useLightPush bool
nick string
2021-04-04 17:06:17 +00:00
}
// NewChat tries to subscribe to the PubSub topic for the room name, returning
// a ChatRoom on success.
2021-06-28 14:14:28 +00:00
func NewChat(ctx context.Context, n *node.WakuNode, selfID peer.ID, contentTopic string, useV1Payload bool, useLightPush bool, nickname string) (*Chat, error) {
2021-04-04 17:06:17 +00:00
// join the default waku topic and subscribe to it
2021-06-28 14:14:28 +00:00
chat := &Chat{
node: n,
self: selfID,
contentTopic: contentTopic,
nick: nickname,
useV1Payload: useV1Payload,
2021-11-01 14:42:55 +00:00
useLightPush: useLightPush,
Messages: make(chan *pb.Chat2Message, 1024),
2021-04-04 17:06:17 +00:00
}
2021-06-28 14:14:28 +00:00
if useLightPush {
cf := filter.ContentFilter{
Topic: string(relay.GetTopic(nil)),
ContentTopics: []string{contentTopic},
}
var err error
_, chat.C, err = n.SubscribeFilter(ctx, cf)
if err != nil {
return nil, err
}
2021-06-28 14:14:28 +00:00
} else {
2021-11-01 14:42:55 +00:00
sub, err := n.Relay().Subscribe(ctx, nil)
2021-06-28 14:14:28 +00:00
if err != nil {
return nil, err
}
chat.C = sub.C
}
2021-04-04 17:06:17 +00:00
// start reading messages from the subscription in a loop
2021-06-28 14:14:28 +00:00
go chat.readLoop()
2021-04-04 17:06:17 +00:00
2021-06-28 14:14:28 +00:00
return chat, nil
2021-04-04 17:06:17 +00:00
}
func generateSymKey(password string) []byte {
// AesKeyLength represents the length (in bytes) of an private key
AESKeyLength := 256 / 8
return pbkdf2.Key([]byte(password), nil, 65356, AESKeyLength, sha256.New)
}
2021-04-04 17:06:17 +00:00
// Publish sends a message to the pubsub topic.
func (cr *Chat) Publish(ctx context.Context, message string) error {
2021-04-04 17:06:17 +00:00
msg := &pb.Chat2Message{
Timestamp: uint64(time.Now().Unix()),
Nick: cr.nick,
Payload: []byte(message),
}
msgBytes, err := proto.Marshal(msg)
if err != nil {
return err
}
var version uint32
2021-10-12 13:12:54 +00:00
var timestamp float64 = utils.GetUnixEpoch()
var keyInfo *node.KeyInfo = &node.KeyInfo{}
if cr.useV1Payload { // Use WakuV1 encryption
keyInfo.Kind = node.Symmetric
keyInfo.SymKey = generateSymKey(cr.contentTopic)
version = 1
} else {
keyInfo.Kind = node.None
version = 0
}
p := new(node.Payload)
p.Data = msgBytes
p.Key = keyInfo
2021-04-04 17:06:17 +00:00
payload, err := p.Encode(version)
2021-04-04 17:06:17 +00:00
if err != nil {
return err
}
2021-04-22 00:12:51 +00:00
wakuMsg := &wpb.WakuMessage{
2021-04-04 17:06:17 +00:00
Payload: payload,
2021-04-07 21:19:39 +00:00
Version: version,
ContentTopic: cr.contentTopic,
2021-04-07 21:19:39 +00:00
Timestamp: timestamp,
2021-04-04 17:06:17 +00:00
}
2021-11-01 14:42:55 +00:00
if cr.useLightPush {
_, err = cr.node.Lightpush().Publish(ctx, wakuMsg, nil)
} else {
_, err = cr.node.Relay().Publish(ctx, wakuMsg, nil)
}
2021-04-11 23:45:42 +00:00
return err
2021-04-04 17:06:17 +00:00
}
2021-04-22 00:12:51 +00:00
func (cr *Chat) decodeMessage(wakumsg *wpb.WakuMessage) {
var keyInfo *node.KeyInfo = &node.KeyInfo{}
if cr.useV1Payload { // Use WakuV1 encryption
keyInfo.Kind = node.Symmetric
keyInfo.SymKey = generateSymKey(cr.contentTopic)
} else {
keyInfo.Kind = node.None
}
payload, err := node.DecodePayload(wakumsg, keyInfo)
2021-04-12 18:03:58 +00:00
if err != nil {
return
}
msg := &pb.Chat2Message{}
if err := proto.Unmarshal(payload.Data, msg); err != nil {
return
}
// send valid messages onto the Messages channel
cr.Messages <- msg
}
2021-04-04 17:06:17 +00:00
// readLoop pulls messages from the pubsub topic and pushes them onto the Messages channel.
func (cr *Chat) readLoop() {
2021-06-28 14:14:28 +00:00
for value := range cr.C {
2021-04-12 18:03:58 +00:00
cr.decodeMessage(value.Message())
}
}
2021-04-22 00:12:51 +00:00
func (cr *Chat) displayMessages(messages []*wpb.WakuMessage) {
2021-04-12 18:03:58 +00:00
for _, msg := range messages {
cr.decodeMessage(msg)
2021-04-04 17:06:17 +00:00
}
}