make Messenger.Timesource public (#1837)

This commit is contained in:
Adam Babik 2020-02-07 12:30:26 +01:00 committed by GitHub
parent e1dee26ba9
commit d27a507e0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 112 additions and 84 deletions

View File

@ -160,6 +160,33 @@ func (c *Chat) updateChatFromProtocolGroup(g *v1protocol.Group) {
c.MembershipUpdates = g.Events()
}
// NextClockAndTimestamp returns the next clock value
// and the current timestamp
func (c *Chat) NextClockAndTimestamp(timesource TimeSource) (uint64, uint64) {
clock := c.LastClockValue
timestamp := timesource.GetCurrentTime()
if clock == 0 || clock < timestamp {
clock = timestamp
} else {
clock = clock + 1
}
return clock, timestamp
}
func (c *Chat) UpdateFromMessage(message *Message, timesource TimeSource) error {
c.Timestamp = int64(timesource.GetCurrentTime())
if c.LastClockValue <= message.Clock {
jsonMessage, err := json.Marshal(message)
if err != nil {
return err
}
c.LastClockValue = message.Clock
c.LastMessage = jsonMessage
}
return nil
}
// ChatMembershipUpdate represent an event on membership of the chat
type ChatMembershipUpdate struct {
// Unique identifier for the event
@ -207,14 +234,14 @@ func oneToOneChatID(publicKey *ecdsa.PublicKey) string {
return types.EncodeHex(crypto.FromECDSAPub(publicKey))
}
func OneToOneFromPublicKey(pk *ecdsa.PublicKey, timesource ClockValueTimesource) *Chat {
func OneToOneFromPublicKey(pk *ecdsa.PublicKey, timesource TimeSource) *Chat {
chatID := types.EncodeHex(crypto.FromECDSAPub(pk))
newChat := CreateOneToOneChat(chatID[:8], pk, timesource)
return &newChat
}
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource ClockValueTimesource) Chat {
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource TimeSource) Chat {
return Chat{
ID: oneToOneChatID(publicKey),
Name: name,
@ -224,7 +251,7 @@ func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource Cloc
}
}
func CreatePublicChat(name string, timesource ClockValueTimesource) Chat {
func CreatePublicChat(name string, timesource TimeSource) Chat {
return Chat{
ID: name,
Name: name,
@ -235,7 +262,7 @@ func CreatePublicChat(name string, timesource ClockValueTimesource) Chat {
}
}
func createGroupChat(timesource ClockValueTimesource) Chat {
func CreateGroupChat(timesource TimeSource) Chat {
return Chat{
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
@ -276,37 +303,6 @@ func stringSliceToPublicKeys(slice []string, prefixed bool) ([]*ecdsa.PublicKey,
return result, nil
}
type ClockValueTimesource interface {
GetCurrentTime() uint64
}
// NextClockAndTimestamp returns the next clock value
// and the current timestamp
func (c *Chat) NextClockAndTimestamp(timesource ClockValueTimesource) (uint64, uint64) {
clock := c.LastClockValue
timestamp := timesource.GetCurrentTime()
if clock == 0 || clock < timestamp {
clock = timestamp
} else {
clock = clock + 1
}
return clock, timestamp
}
func (c *Chat) UpdateFromMessage(message *Message, timesource ClockValueTimesource) error {
c.Timestamp = int64(timesource.GetCurrentTime())
if c.LastClockValue <= message.Clock {
jsonMessage, err := json.Marshal(message)
if err != nil {
return err
}
c.LastClockValue = message.Clock
c.LastMessage = jsonMessage
}
return nil
}
func stringSliceContains(slice []string, item string) bool {
for _, s := range slice {
if s == item {

View File

@ -9,7 +9,7 @@ import (
"github.com/status-im/status-go/protocol/identity/identicon"
)
func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, timesource ClockValueTimesource) error {
func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, timesource TimeSource) error {
clock, timestamp := chat.NextClockAndTimestamp(timesource)
message.LocalChatID = chat.ID

View File

@ -59,7 +59,7 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
if !group.IsMember(contactIDFromPublicKey(&m.identity.PublicKey)) {
return errors.New("can't create a new group chat without us being a member")
}
newChat := createGroupChat(messageState.Timesource)
newChat := CreateGroupChat(messageState.Timesource)
chat = &newChat
} else {
@ -550,7 +550,7 @@ func (m *MessageHandler) HandleDeclineRequestTransaction(messageState *ReceivedM
return m.handleCommandMessage(messageState, oldMessage)
}
func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat, timesource ClockValueTimesource) (*Chat, error) {
func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat, timesource TimeSource) (*Chat, error) {
if message.SigPubKey == nil {
m.logger.Error("public key can't be empty")
return nil, errors.New("received a message with empty public key")

View File

@ -126,6 +126,8 @@ type config struct {
type Option func(*config) error
// WithSystemMessagesTranslations is required for Group Chats which are currently disabled.
// nolint: unused
func WithSystemMessagesTranslations(t map[protobuf.MembershipUpdateEvent_EventType]string) Option {
return func(c *config) error {
c.systemMessagesTranslations = t
@ -629,7 +631,7 @@ func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string,
var response MessengerResponse
logger := m.logger.With(zap.String("site", "CreateGroupChatWithMembers"))
logger.Info("Creating group chat", zap.String("name", name), zap.Any("members", members))
chat := createGroupChat(m.getTimesource())
chat := CreateGroupChat(m.getTimesource())
group, err := v1protocol.NewGroupWithCreator(name, m.identity)
if err != nil {
return nil, err
@ -1699,8 +1701,8 @@ type ReceivedMessageState struct {
ExistingMessagesMap map[string]bool
// Response to the client
Response *MessengerResponse
// Timesource is a timesource for clock values/timestamps
Timesource ClockValueTimesource
// Timesource is a time source for clock values/timestamps.
Timesource TimeSource
}
func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filter][]*types.Message) (*MessengerResponse, error) {
@ -2806,6 +2808,10 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
return &response, nil
}
func (m *Messenger) getTimesource() ClockValueTimesource {
func (m *Messenger) getTimesource() TimeSource {
return m.transport
}
func (m *Messenger) Timesource() TimeSource {
return m.getTimesource()
}

12
protocol/timesource.go Normal file
View File

@ -0,0 +1,12 @@
package protocol
// TimeSource provides a unified way of getting the current time.
// The intention is to always use a synchronized time source
// between all components of the protocol.
//
// This is required by Whisper and Waku protocols
// which rely on a fact that all peers
// have a synchronized time source.
type TimeSource interface {
GetCurrentTime() uint64
}

View File

@ -160,6 +160,33 @@ func (c *Chat) updateChatFromProtocolGroup(g *v1protocol.Group) {
c.MembershipUpdates = g.Events()
}
// NextClockAndTimestamp returns the next clock value
// and the current timestamp
func (c *Chat) NextClockAndTimestamp(timesource TimeSource) (uint64, uint64) {
clock := c.LastClockValue
timestamp := timesource.GetCurrentTime()
if clock == 0 || clock < timestamp {
clock = timestamp
} else {
clock = clock + 1
}
return clock, timestamp
}
func (c *Chat) UpdateFromMessage(message *Message, timesource TimeSource) error {
c.Timestamp = int64(timesource.GetCurrentTime())
if c.LastClockValue <= message.Clock {
jsonMessage, err := json.Marshal(message)
if err != nil {
return err
}
c.LastClockValue = message.Clock
c.LastMessage = jsonMessage
}
return nil
}
// ChatMembershipUpdate represent an event on membership of the chat
type ChatMembershipUpdate struct {
// Unique identifier for the event
@ -207,14 +234,14 @@ func oneToOneChatID(publicKey *ecdsa.PublicKey) string {
return types.EncodeHex(crypto.FromECDSAPub(publicKey))
}
func OneToOneFromPublicKey(pk *ecdsa.PublicKey, timesource ClockValueTimesource) *Chat {
func OneToOneFromPublicKey(pk *ecdsa.PublicKey, timesource TimeSource) *Chat {
chatID := types.EncodeHex(crypto.FromECDSAPub(pk))
newChat := CreateOneToOneChat(chatID[:8], pk, timesource)
return &newChat
}
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource ClockValueTimesource) Chat {
func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource TimeSource) Chat {
return Chat{
ID: oneToOneChatID(publicKey),
Name: name,
@ -224,7 +251,7 @@ func CreateOneToOneChat(name string, publicKey *ecdsa.PublicKey, timesource Cloc
}
}
func CreatePublicChat(name string, timesource ClockValueTimesource) Chat {
func CreatePublicChat(name string, timesource TimeSource) Chat {
return Chat{
ID: name,
Name: name,
@ -235,7 +262,7 @@ func CreatePublicChat(name string, timesource ClockValueTimesource) Chat {
}
}
func createGroupChat(timesource ClockValueTimesource) Chat {
func CreateGroupChat(timesource TimeSource) Chat {
return Chat{
Active: true,
Color: chatColors[rand.Intn(len(chatColors))],
@ -276,37 +303,6 @@ func stringSliceToPublicKeys(slice []string, prefixed bool) ([]*ecdsa.PublicKey,
return result, nil
}
type ClockValueTimesource interface {
GetCurrentTime() uint64
}
// NextClockAndTimestamp returns the next clock value
// and the current timestamp
func (c *Chat) NextClockAndTimestamp(timesource ClockValueTimesource) (uint64, uint64) {
clock := c.LastClockValue
timestamp := timesource.GetCurrentTime()
if clock == 0 || clock < timestamp {
clock = timestamp
} else {
clock = clock + 1
}
return clock, timestamp
}
func (c *Chat) UpdateFromMessage(message *Message, timesource ClockValueTimesource) error {
c.Timestamp = int64(timesource.GetCurrentTime())
if c.LastClockValue <= message.Clock {
jsonMessage, err := json.Marshal(message)
if err != nil {
return err
}
c.LastClockValue = message.Clock
c.LastMessage = jsonMessage
}
return nil
}
func stringSliceContains(slice []string, item string) bool {
for _, s := range slice {
if s == item {

View File

@ -9,7 +9,7 @@ import (
"github.com/status-im/status-go/protocol/identity/identicon"
)
func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, timesource ClockValueTimesource) error {
func extendMessageFromChat(message *Message, chat *Chat, key *ecdsa.PublicKey, timesource TimeSource) error {
clock, timestamp := chat.NextClockAndTimestamp(timesource)
message.LocalChatID = chat.ID

View File

@ -59,7 +59,7 @@ func (m *MessageHandler) HandleMembershipUpdate(messageState *ReceivedMessageSta
if !group.IsMember(contactIDFromPublicKey(&m.identity.PublicKey)) {
return errors.New("can't create a new group chat without us being a member")
}
newChat := createGroupChat(messageState.Timesource)
newChat := CreateGroupChat(messageState.Timesource)
chat = &newChat
} else {
@ -550,7 +550,7 @@ func (m *MessageHandler) HandleDeclineRequestTransaction(messageState *ReceivedM
return m.handleCommandMessage(messageState, oldMessage)
}
func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat, timesource ClockValueTimesource) (*Chat, error) {
func (m *MessageHandler) matchMessage(message *Message, chats map[string]*Chat, timesource TimeSource) (*Chat, error) {
if message.SigPubKey == nil {
m.logger.Error("public key can't be empty")
return nil, errors.New("received a message with empty public key")

View File

@ -126,6 +126,8 @@ type config struct {
type Option func(*config) error
// WithSystemMessagesTranslations is required for Group Chats which are currently disabled.
// nolint: unused
func WithSystemMessagesTranslations(t map[protobuf.MembershipUpdateEvent_EventType]string) Option {
return func(c *config) error {
c.systemMessagesTranslations = t
@ -629,7 +631,7 @@ func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string,
var response MessengerResponse
logger := m.logger.With(zap.String("site", "CreateGroupChatWithMembers"))
logger.Info("Creating group chat", zap.String("name", name), zap.Any("members", members))
chat := createGroupChat(m.getTimesource())
chat := CreateGroupChat(m.getTimesource())
group, err := v1protocol.NewGroupWithCreator(name, m.identity)
if err != nil {
return nil, err
@ -1699,8 +1701,8 @@ type ReceivedMessageState struct {
ExistingMessagesMap map[string]bool
// Response to the client
Response *MessengerResponse
// Timesource is a timesource for clock values/timestamps
Timesource ClockValueTimesource
// Timesource is a time source for clock values/timestamps.
Timesource TimeSource
}
func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filter][]*types.Message) (*MessengerResponse, error) {
@ -2806,6 +2808,10 @@ func (m *Messenger) ValidateTransactions(ctx context.Context, addresses []types.
return &response, nil
}
func (m *Messenger) getTimesource() ClockValueTimesource {
func (m *Messenger) getTimesource() TimeSource {
return m.transport
}
func (m *Messenger) Timesource() TimeSource {
return m.getTimesource()
}

View File

@ -0,0 +1,12 @@
package protocol
// TimeSource provides a unified way of getting the current time.
// The intention is to always use a synchronized time source
// between all components of the protocol.
//
// This is required by Whisper and Waku protocols
// which rely on a fact that all peers
// have a synchronized time source.
type TimeSource interface {
GetCurrentTime() uint64
}