Add datasync, v1messages & disable discovery topic options

Adds support for datasync, V1Messages and disabling the discovery topic.
This is a backward compatible change as long as they are not toggled on
(they are not by default).
This commit is contained in:
Andrea Maria Piana 2019-07-26 09:17:29 +02:00
parent 21a62c731f
commit 9de77b21b2
53 changed files with 2303 additions and 431 deletions

View File

@ -1 +1 @@
0.31.0-beta.0 0.31.0-beta.1

2
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/status-im/doubleratchet v2.0.0+incompatible github.com/status-im/doubleratchet v2.0.0+incompatible
github.com/status-im/migrate/v4 v4.3.1-status github.com/status-im/migrate/v4 v4.3.1-status
github.com/status-im/rendezvous v1.3.0 github.com/status-im/rendezvous v1.3.0
github.com/status-im/status-protocol-go v0.1.1 github.com/status-im/status-protocol-go v0.1.3
github.com/status-im/whisper v1.4.14 github.com/status-im/whisper v1.4.14
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0

13
go.sum
View File

@ -145,6 +145,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@ -216,6 +218,8 @@ github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr1
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s=
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
@ -438,8 +442,6 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/status-im/doubleratchet v2.0.0+incompatible h1:s77lF1lDubK0RKftxN2vH8G9gwtVVp13ggWfyY4O1q4= github.com/status-im/doubleratchet v2.0.0+incompatible h1:s77lF1lDubK0RKftxN2vH8G9gwtVVp13ggWfyY4O1q4=
github.com/status-im/doubleratchet v2.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU= github.com/status-im/doubleratchet v2.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU=
github.com/status-im/go-ethereum v1.8.27-status.3 h1:h+CsF2Z/HyERLo5qTQnrK0RXHuDJ605hG2BbqNOLAAc=
github.com/status-im/go-ethereum v1.8.27-status.3/go.mod h1:Ulij8LMpMvXnbnPcmDqrpI+iXoXSjxItuY/wmbasTZU=
github.com/status-im/go-ethereum v1.8.27-status.5 h1:FS+1KwA97yWh9BtHse0BLfEWtldboSiTMA7nCavxtzc= github.com/status-im/go-ethereum v1.8.27-status.5 h1:FS+1KwA97yWh9BtHse0BLfEWtldboSiTMA7nCavxtzc=
github.com/status-im/go-ethereum v1.8.27-status.5/go.mod h1:Ulij8LMpMvXnbnPcmDqrpI+iXoXSjxItuY/wmbasTZU= github.com/status-im/go-ethereum v1.8.27-status.5/go.mod h1:Ulij8LMpMvXnbnPcmDqrpI+iXoXSjxItuY/wmbasTZU=
github.com/status-im/go-fcm v1.0.0-status h1:eUNKm4ooAXdEf9/GaTYeTELna5aVMOEbzjbm2irQ0gY= github.com/status-im/go-fcm v1.0.0-status h1:eUNKm4ooAXdEf9/GaTYeTELna5aVMOEbzjbm2irQ0gY=
@ -451,14 +453,15 @@ github.com/status-im/migrate/v4 v4.3.1-status/go.mod h1:r8HggRBZ/k7TRwByq/Hp3P/u
github.com/status-im/rendezvous v1.3.0 h1:7RK/MXXW+tlm0asKm1u7Qp7Yni6AO29a7j8+E4Lbjg4= github.com/status-im/rendezvous v1.3.0 h1:7RK/MXXW+tlm0asKm1u7Qp7Yni6AO29a7j8+E4Lbjg4=
github.com/status-im/rendezvous v1.3.0/go.mod h1:+hzjuP+j/XzLPeF6E50b88pWOTLdTcwjvNYt+Gh1W1s= github.com/status-im/rendezvous v1.3.0/go.mod h1:+hzjuP+j/XzLPeF6E50b88pWOTLdTcwjvNYt+Gh1W1s=
github.com/status-im/status-go v0.29.0-beta.3/go.mod h1:8OHekmRoYTn9oZgMsBdhMEgeyfaQ4eI4ycOFHJCoX7M= github.com/status-im/status-go v0.29.0-beta.3/go.mod h1:8OHekmRoYTn9oZgMsBdhMEgeyfaQ4eI4ycOFHJCoX7M=
github.com/status-im/status-protocol-go v0.1.1 h1:PGKtMTgfk48LS2ZyNIEdJZJjQGVbkBfccf6EVYCjCpA= github.com/status-im/status-protocol-go v0.1.3 h1:2ELZ3XR/11CHvElVUDIo9swUQRvrekFC5ZK9W1dB+Eo=
github.com/status-im/status-protocol-go v0.1.1/go.mod h1:rqlsXFR7WENTB4HDJRByRg95UfRo8pjGWvrvVrC2Dm4= github.com/status-im/status-protocol-go v0.1.3/go.mod h1:K1sZNTGahmrliIsVDTPrruKMZqbbqd8inbfbfh9Wmw4=
github.com/status-im/whisper v1.4.14 h1:9VHqx4+PUYfhDnYYtDxHkg/3cfVvkHjPNciY4LO83yc= github.com/status-im/whisper v1.4.14 h1:9VHqx4+PUYfhDnYYtDxHkg/3cfVvkHjPNciY4LO83yc=
github.com/status-im/whisper v1.4.14/go.mod h1:WS6z39YJQ8WJa9s+DmTuEM/s2nVF6Iz3B1SZYw5cYf0= github.com/status-im/whisper v1.4.14/go.mod h1:WS6z39YJQ8WJa9s+DmTuEM/s2nVF6Iz3B1SZYw5cYf0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v0.0.0-20190716104307-221dbe5ed46703ee255b1da0dec05086f5035f62/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -468,6 +471,8 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/vacp2p/mvds v0.0.19 h1:ZXopUNicQPzmIsggqa9Pbd6cqphFiyhthe3kneuJpC8=
github.com/vacp2p/mvds v0.0.19/go.mod h1:MxvN/VFp5zkjhUfJdBft+NrsVDwMsvueDIP2x0h6Tx8=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=

View File

@ -409,6 +409,15 @@ type ShhextConfig struct {
// WhisperCacheDir is a folder where whisper filters may persist messages before delivering them // WhisperCacheDir is a folder where whisper filters may persist messages before delivering them
// to a client. // to a client.
WhisperCacheDir string WhisperCacheDir string
// DisableGenericDiscoveryTopic indicates whether we should be listening on the old discovery
DisableGenericDiscoveryTopic bool
// SendV1Messages indicates whether we should be sending v1-compatible only messages
SendV1Messages bool
// DatasyncEnabled indicates whether we should enable dataasync
DataSyncEnabled bool
} }
// Validate validates the ShhextConfig struct and returns an error if inconsistent values are found // Validate validates the ShhextConfig struct and returns an error if inconsistent values are found

View File

@ -176,17 +176,17 @@ func (s *Service) initProtocol(address, encKey, password string) error {
os.Remove(v4Path) os.Remove(v4Path)
} }
options, err := buildMessengerOptions(s.config, sessionsDatabasePath, transportDatabasePath)
if err != nil {
return err
}
selectedKeyID := s.w.SelectedKeyPairID() selectedKeyID := s.w.SelectedKeyPairID()
identity, err := s.w.GetPrivateKey(selectedKeyID) identity, err := s.w.GetPrivateKey(selectedKeyID)
if err != nil { if err != nil {
return err return err
} }
// Create a custom zap.Logger which will forward logs from status-protocol-go to status-go logger.
zapLogger, err := logutils.NewZapLoggerWithAdapter(logutils.Logger())
if err != nil {
return err
}
messenger, err := protocol.NewMessenger( messenger, err := protocol.NewMessenger(
identity, identity,
&server{server: s.server}, &server{server: s.server},
@ -194,12 +194,7 @@ func (s *Service) initProtocol(address, encKey, password string) error {
dataDir, dataDir,
encKey, encKey,
s.config.InstallationID, s.config.InstallationID,
protocol.WithDatabaseFilePaths( options...,
sessionsDatabasePath,
transportDatabasePath,
),
protocol.WithGenericDiscoveryTopicSupport(),
protocol.WithCustomLogger(zapLogger),
) )
if err != nil { if err != nil {
return err return err
@ -226,11 +221,19 @@ func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{
} }
var signalMessages []*signal.Messages var signalMessages []*signal.Messages
for chat, messages := range chatWithMessages { for chat, messages := range chatWithMessages {
var retrievedMessages []*whisper.Message
for _, message := range messages {
whisperMessage := message.TransportMessage
whisperMessage.Payload = message.DecryptedPayload
retrievedMessages = append(retrievedMessages, whisperMessage)
}
signalMessage := &signal.Messages{ signalMessage := &signal.Messages{
Chat: chat, Chat: chat,
Error: nil, // TODO: what is it needed for? Error: nil, // TODO: what is it needed for?
Messages: s.deduplicator.Deduplicate(messages), Messages: s.deduplicator.Deduplicate(retrievedMessages),
} }
signalMessages = append(signalMessages, signalMessage) signalMessages = append(signalMessages, signalMessage)
} }
@ -395,6 +398,35 @@ func (s *Service) syncMessages(ctx context.Context, mailServerID []byte, r whisp
} }
} }
func buildMessengerOptions(config params.ShhextConfig, sessionsDatabasePath string, transportDatabasePath string) ([]protocol.Option, error) {
// Create a custom zap.Logger which will forward logs from status-protocol-go to status-go logger.
zapLogger, err := logutils.NewZapLoggerWithAdapter(logutils.Logger())
if err != nil {
return nil, err
}
options := []protocol.Option{
protocol.WithCustomLogger(zapLogger),
protocol.WithDatabaseFilePaths(
sessionsDatabasePath,
transportDatabasePath,
),
}
if !config.DisableGenericDiscoveryTopic {
options = append(options, protocol.WithGenericDiscoveryTopicSupport())
}
if config.DataSyncEnabled {
options = append(options, protocol.WithDatasync())
}
if config.SendV1Messages {
options = append(options, protocol.WithSendV1Messages())
}
return options, nil
}
func (s *Service) afterPost(hash []byte, newMessage whisper.NewMessage) hexutil.Bytes { func (s *Service) afterPost(hash []byte, newMessage whisper.NewMessage) hexutil.Bytes {
s.envelopesMonitor.Add(common.BytesToHash(hash), newMessage) s.envelopesMonitor.Add(common.BytesToHash(hash), newMessage)
mID := messageID(newMessage) mID := messageID(newMessage)

View File

@ -38,7 +38,6 @@ package proto
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
@ -194,7 +193,7 @@ func (p *Properties) Parse(s string) {
// "bytes,49,opt,name=foo,def=hello!" // "bytes,49,opt,name=foo,def=hello!"
fields := strings.Split(s, ",") // breaks def=, but handled below. fields := strings.Split(s, ",") // breaks def=, but handled below.
if len(fields) < 2 { if len(fields) < 2 {
fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s) log.Printf("proto: tag has too few fields: %q", s)
return return
} }
@ -214,7 +213,7 @@ func (p *Properties) Parse(s string) {
p.WireType = WireBytes p.WireType = WireBytes
// no numeric converter for non-numeric types // no numeric converter for non-numeric types
default: default:
fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s) log.Printf("proto: tag has unknown wire type: %q", s)
return return
} }

3
vendor/github.com/jinzhu/copier/Guardfile generated vendored Normal file
View File

@ -0,0 +1,3 @@
guard 'gotest' do
watch(%r{\.go$})
end

20
vendor/github.com/jinzhu/copier/License generated vendored Normal file
View File

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

100
vendor/github.com/jinzhu/copier/README.md generated vendored Normal file
View File

@ -0,0 +1,100 @@
# Copier
I am a copier, I copy everything from one to another
[![wercker status](https://app.wercker.com/status/9d44ad2d4e6253929c8fb71359effc0b/s/master "wercker status")](https://app.wercker.com/project/byKey/9d44ad2d4e6253929c8fb71359effc0b)
## Features
* Copy from field to field with same name
* Copy from method to field with same name
* Copy from field to method with same name
* Copy from slice to slice
* Copy from struct to slice
## Usage
```go
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type User struct {
Name string
Role string
Age int32
}
func (user *User) DoubleAge() int32 {
return 2 * user.Age
}
type Employee struct {
Name string
Age int32
DoubleAge int32
EmployeId int64
SuperRule string
}
func (employee *Employee) Role(role string) {
employee.SuperRule = "Super " + role
}
func main() {
var (
user = User{Name: "Jinzhu", Age: 18, Role: "Admin"}
users = []User{{Name: "Jinzhu", Age: 18, Role: "Admin"}, {Name: "jinzhu 2", Age: 30, Role: "Dev"}}
employee = Employee{}
employees = []Employee{}
)
copier.Copy(&employee, &user)
fmt.Printf("%#v \n", employee)
// Employee{
// Name: "Jinzhu", // Copy from field
// Age: 18, // Copy from field
// DoubleAge: 36, // Copy from method
// EmployeeId: 0, // Ignored
// SuperRule: "Super Admin", // Copy to method
// }
// Copy struct to slice
copier.Copy(&employees, &user)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, DoubleAge: 36, EmployeId: 0, SuperRule: "Super Admin"}
// }
// Copy slice to slice
employees = []Employee{}
copier.Copy(&employees, &users)
fmt.Printf("%#v \n", employees)
// []Employee{
// {Name: "Jinzhu", Age: 18, DoubleAge: 36, EmployeId: 0, SuperRule: "Super Admin"},
// {Name: "jinzhu 2", Age: 30, DoubleAge: 60, EmployeId: 0, SuperRule: "Super Dev"},
// }
}
```
## Contributing
You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do.
# Author
**jinzhu**
* <http://github.com/jinzhu>
* <wosmvp@gmail.com>
* <http://twitter.com/zhangjinzhu>
## License
Released under the [MIT License](https://github.com/jinzhu/copier/blob/master/License).

189
vendor/github.com/jinzhu/copier/copier.go generated vendored Normal file
View File

@ -0,0 +1,189 @@
package copier
import (
"database/sql"
"errors"
"reflect"
)
// Copy copy things
func Copy(toValue interface{}, fromValue interface{}) (err error) {
var (
isSlice bool
amount = 1
from = indirect(reflect.ValueOf(fromValue))
to = indirect(reflect.ValueOf(toValue))
)
if !to.CanAddr() {
return errors.New("copy to value is unaddressable")
}
// Return is from value is invalid
if !from.IsValid() {
return
}
fromType := indirectType(from.Type())
toType := indirectType(to.Type())
// Just set it if possible to assign
// And need to do copy anyway if the type is struct
if fromType.Kind() != reflect.Struct && from.Type().AssignableTo(to.Type()) {
to.Set(from)
return
}
if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
return
}
if to.Kind() == reflect.Slice {
isSlice = true
if from.Kind() == reflect.Slice {
amount = from.Len()
}
}
for i := 0; i < amount; i++ {
var dest, source reflect.Value
if isSlice {
// source
if from.Kind() == reflect.Slice {
source = indirect(from.Index(i))
} else {
source = indirect(from)
}
// dest
dest = indirect(reflect.New(toType).Elem())
} else {
source = indirect(from)
dest = indirect(to)
}
// check source
if source.IsValid() {
fromTypeFields := deepFields(fromType)
//fmt.Printf("%#v", fromTypeFields)
// Copy from field to field or method
for _, field := range fromTypeFields {
name := field.Name
if fromField := source.FieldByName(name); fromField.IsValid() {
// has field
if toField := dest.FieldByName(name); toField.IsValid() {
if toField.CanSet() {
if !set(toField, fromField) {
if err := Copy(toField.Addr().Interface(), fromField.Interface()); err != nil {
return err
}
}
}
} else {
// try to set to method
var toMethod reflect.Value
if dest.CanAddr() {
toMethod = dest.Addr().MethodByName(name)
} else {
toMethod = dest.MethodByName(name)
}
if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
toMethod.Call([]reflect.Value{fromField})
}
}
}
}
// Copy from method to field
for _, field := range deepFields(toType) {
name := field.Name
var fromMethod reflect.Value
if source.CanAddr() {
fromMethod = source.Addr().MethodByName(name)
} else {
fromMethod = source.MethodByName(name)
}
if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 {
if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
values := fromMethod.Call([]reflect.Value{})
if len(values) >= 1 {
set(toField, values[0])
}
}
}
}
}
if isSlice {
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
to.Set(reflect.Append(to, dest.Addr()))
} else if dest.Type().AssignableTo(to.Type().Elem()) {
to.Set(reflect.Append(to, dest))
}
}
}
return
}
func deepFields(reflectType reflect.Type) []reflect.StructField {
var fields []reflect.StructField
if reflectType = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
for i := 0; i < reflectType.NumField(); i++ {
v := reflectType.Field(i)
if v.Anonymous {
fields = append(fields, deepFields(v.Type)...)
} else {
fields = append(fields, v)
}
}
}
return fields
}
func indirect(reflectValue reflect.Value) reflect.Value {
for reflectValue.Kind() == reflect.Ptr {
reflectValue = reflectValue.Elem()
}
return reflectValue
}
func indirectType(reflectType reflect.Type) reflect.Type {
for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
reflectType = reflectType.Elem()
}
return reflectType
}
func set(to, from reflect.Value) bool {
if from.IsValid() {
if to.Kind() == reflect.Ptr {
//set `to` to nil if from is nil
if from.Kind() == reflect.Ptr && from.IsNil() {
to.Set(reflect.Zero(to.Type()))
return true
} else if to.IsNil() {
to.Set(reflect.New(to.Type().Elem()))
}
to = to.Elem()
}
if from.Type().ConvertibleTo(to.Type()) {
to.Set(from.Convert(to.Type()))
} else if scanner, ok := to.Addr().Interface().(sql.Scanner); ok {
err := scanner.Scan(from.Interface())
if err != nil {
return false
}
} else if from.Kind() == reflect.Ptr {
return set(to, from.Elem())
} else {
return false
}
}
return true
}

23
vendor/github.com/jinzhu/copier/wercker.yml generated vendored Normal file
View File

@ -0,0 +1,23 @@
box: golang
build:
steps:
- setup-go-workspace
# Gets the dependencies
- script:
name: go get
code: |
go get
# Build the project
- script:
name: go build
code: |
go build ./...
# Test the project
- script:
name: go test
code: |
go test ./...

View File

@ -1,3 +1,8 @@
run: run:
concurrency: 4
modules-download-mode: vendor modules-download-mode: vendor
deadline: 5m deadline: 5m
skip:
- migrations.go
- .*_mock.go
- vendor/

View File

@ -2,26 +2,22 @@ notifications:
email: false email: false
language: go language: go
go:
- "1.12.x"
- "1.13beta1"
install: true install: true
env: env:
- GO111MODULE=on - GO111MODULE=on GOFLAGS=-mod=vendor
before_script:
- make install-linter
matrix: matrix:
include: allow_failures:
- go: "1.11.x" - go: "1.13beta1"
env: GOFLAGS=-mod=vendor
script: before_script:
- make install-linter
script:
- make lint - make lint
# fails without -a - make test
- go test -a ./... # make test
- go: "1.12.x"
env: GOFLAGS=-mod=vendor
script:
- make lint
# fails without -a
- go test -a ./... # make test

View File

@ -19,6 +19,9 @@ import (
"github.com/status-im/status-protocol-go/encryption/multidevice" "github.com/status-im/status-protocol-go/encryption/multidevice"
transport "github.com/status-im/status-protocol-go/transport/whisper" transport "github.com/status-im/status-protocol-go/transport/whisper"
protocol "github.com/status-im/status-protocol-go/v1" protocol "github.com/status-im/status-protocol-go/v1"
"github.com/status-im/status-protocol-go/datasync"
datasyncpeer "github.com/status-im/status-protocol-go/datasync/peer"
) )
// Whisper message properties. // Whisper message properties.
@ -34,6 +37,7 @@ type whisperAdapter struct {
privateKey *ecdsa.PrivateKey privateKey *ecdsa.PrivateKey
transport *transport.WhisperServiceTransport transport *transport.WhisperServiceTransport
protocol *encryption.Protocol protocol *encryption.Protocol
datasync *datasync.DataSync
logger *zap.Logger logger *zap.Logger
featureFlags featureFlags featureFlags featureFlags
@ -43,6 +47,7 @@ func newWhisperAdapter(
pk *ecdsa.PrivateKey, pk *ecdsa.PrivateKey,
t *transport.WhisperServiceTransport, t *transport.WhisperServiceTransport,
p *encryption.Protocol, p *encryption.Protocol,
d *datasync.DataSync,
featureFlags featureFlags, featureFlags featureFlags,
logger *zap.Logger, logger *zap.Logger,
) *whisperAdapter { ) *whisperAdapter {
@ -50,13 +55,22 @@ func newWhisperAdapter(
logger = zap.NewNop() logger = zap.NewNop()
} }
return &whisperAdapter{ adapter := &whisperAdapter{
privateKey: pk, privateKey: pk,
transport: t, transport: t,
protocol: p, protocol: p,
datasync: d,
featureFlags: featureFlags, featureFlags: featureFlags,
logger: logger.With(zap.Namespace("whisperAdapter")), logger: logger.With(zap.Namespace("whisperAdapter")),
} }
if featureFlags.datasync {
// We pass our encryption/transport handling to the datasync
// so it's correctly encrypted.
d.Init(adapter.encryptAndSend)
}
return adapter
} }
func (a *whisperAdapter) JoinPublic(chatID string) error { func (a *whisperAdapter) JoinPublic(chatID string) error {
@ -75,6 +89,34 @@ func (a *whisperAdapter) LeavePrivate(publicKey *ecdsa.PublicKey) error {
return a.transport.LeavePrivate(publicKey) return a.transport.LeavePrivate(publicKey)
} }
type ChatMessages struct {
Messages []*protocol.Message
Public bool
ChatID string
}
func (a *whisperAdapter) RetrieveAllMessages() ([]ChatMessages, error) {
chatMessages, err := a.transport.RetrieveAllMessages()
if err != nil {
return nil, err
}
var result []ChatMessages
for _, messages := range chatMessages {
protoMessages, err := a.handleRetrievedMessages(messages.Messages)
if err != nil {
return nil, err
}
result = append(result, ChatMessages{
Messages: protoMessages,
Public: messages.Public,
ChatID: messages.ChatID,
})
}
return result, nil
}
// RetrievePublicMessages retrieves the collected public messages. // RetrievePublicMessages retrieves the collected public messages.
// It implies joining a chat if it has not been joined yet. // It implies joining a chat if it has not been joined yet.
func (a *whisperAdapter) RetrievePublicMessages(chatID string) ([]*protocol.Message, error) { func (a *whisperAdapter) RetrievePublicMessages(chatID string) ([]*protocol.Message, error) {
@ -83,32 +125,7 @@ func (a *whisperAdapter) RetrievePublicMessages(chatID string) ([]*protocol.Mess
return nil, err return nil, err
} }
logger := a.logger.With(zap.String("site", "RetrievePublicMessages")) return a.handleRetrievedMessages(messages)
decodedMessages := make([]*protocol.Message, 0, len(messages))
for _, item := range messages {
shhMessage := whisper.ToWhisperMessage(item)
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
hlogger.Debug("received a public message")
statusMessage, err := a.decodeMessage(shhMessage)
if err != nil {
hlogger.Error("failed to decode message", zap.Error(err))
continue
}
switch m := statusMessage.Message.(type) {
case protocol.Message:
m.ID = statusMessage.ID
m.SigPubKey = statusMessage.SigPubKey
decodedMessages = append(decodedMessages, &m)
default:
hlogger.Error("skipped a public message of unsupported type")
}
}
return decodedMessages, nil
} }
// RetrievePrivateMessages retrieves the collected private messages. // RetrievePrivateMessages retrieves the collected private messages.
@ -119,34 +136,33 @@ func (a *whisperAdapter) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]
return nil, err return nil, err
} }
logger := a.logger.With(zap.String("site", "RetrievePrivateMessages")) return a.handleRetrievedMessages(messages)
}
func (a *whisperAdapter) handleRetrievedMessages(messages []*whisper.ReceivedMessage) ([]*protocol.Message, error) {
logger := a.logger.With(zap.String("site", "handleRetrievedMessages"))
decodedMessages := make([]*protocol.Message, 0, len(messages)) decodedMessages := make([]*protocol.Message, 0, len(messages))
for _, item := range messages { for _, item := range messages {
shhMessage := whisper.ToWhisperMessage(item) shhMessage := whisper.ToWhisperMessage(item)
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash)) hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
hlogger.Debug("handling a received message")
hlogger.Debug("received a private message") statusMessages, err := a.handleMessages(shhMessage, true)
err := a.decryptMessage(context.Background(), shhMessage)
if err != nil { if err != nil {
hlogger.Error("failed to decrypt a message", zap.Error(err)) hlogger.Info("failed to decode messages", zap.Error(err))
}
statusMessage, err := a.decodeMessage(shhMessage)
if err != nil {
hlogger.Error("failed to decode a message", zap.Error(err))
continue continue
} }
switch m := statusMessage.Message.(type) { for _, statusMessage := range statusMessages {
switch m := statusMessage.ParsedMessage.(type) {
case protocol.Message: case protocol.Message:
m.ID = statusMessage.ID m.ID = statusMessage.ID
m.SigPubKey = statusMessage.SigPubKey m.SigPubKey = statusMessage.SigPubKey()
decodedMessages = append(decodedMessages, &m) decodedMessages = append(decodedMessages, &m)
case protocol.PairMessage: case protocol.PairMessage:
fromOurDevice := isPubKeyEqual(statusMessage.SigPubKey, &a.privateKey.PublicKey) fromOurDevice := isPubKeyEqual(statusMessage.SigPubKey(), &a.privateKey.PublicKey)
if !fromOurDevice { if !fromOurDevice {
hlogger.Debug("received PairMessage from not our device, skipping") hlogger.Debug("received PairMessage from not our device, skipping")
break break
@ -161,94 +177,90 @@ func (a *whisperAdapter) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]
if err != nil { if err != nil {
return nil, err return nil, err
} }
default:
hlogger.Error("skipped a public message of unsupported type")
}
} }
} }
return decodedMessages, nil return decodedMessages, nil
} }
// DEPRECATED // DEPRECATED
func (a *whisperAdapter) RetrieveRawAll() (map[filter.Chat][]*whisper.Message, error) { func (a *whisperAdapter) RetrieveRawAll() (map[filter.Chat][]*protocol.StatusMessage, error) {
chatWithMessages, err := a.transport.RetrieveRawAll() chatWithMessages, err := a.transport.RetrieveRawAll()
if err != nil { if err != nil {
return nil, err return nil, err
} }
logger := a.logger.With(zap.String("site", "RetrieveRawAll")) logger := a.logger.With(zap.String("site", "RetrieveRawAll"))
result := make(map[filter.Chat][]*whisper.Message) result := make(map[filter.Chat][]*protocol.StatusMessage)
for chat, messages := range chatWithMessages { for chat, messages := range chatWithMessages {
for _, message := range messages { for _, message := range messages {
shhMessage := whisper.ToWhisperMessage(message) shhMessage := whisper.ToWhisperMessage(message)
err := a.decryptMessage(context.Background(), shhMessage) statusMessages, err := a.handleMessages(shhMessage, false)
if err != nil { if err != nil {
logger.Warn("failed to decrypt a message", zap.Error(err), zap.Binary("messageID", shhMessage.Hash)) logger.Info("failed to decode messages", zap.Error(err))
continue
} }
result[chat] = append(result[chat], shhMessage)
result[chat] = append(result[chat], statusMessages...)
} }
} }
return result, nil return result, nil
} }
// DEPRECATED // handleMessages expects a whisper message as input, and it will go through
func (a *whisperAdapter) RetrieveRaw(filterID string) ([]*whisper.Message, error) { // a series of transformations until the message is parsed into an application
messages, err := a.transport.RetrieveRaw(filterID) // layer message, or in case of Raw methods, the processing stops at the layer
// before
func (a *whisperAdapter) handleMessages(shhMessage *whisper.Message, applicationLayer bool) ([]*protocol.StatusMessage, error) {
logger := a.logger.With(zap.String("site", "handleMessages"))
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
var statusMessage protocol.StatusMessage
err := statusMessage.HandleTransport(shhMessage)
if err != nil { if err != nil {
hlogger.Error("failed to handle transport layer message", zap.Error(err))
return nil, err return nil, err
} }
logger := a.logger.With(zap.String("site", "RetrieveRaw")) err = a.handleEncryptionLayer(context.Background(), &statusMessage)
var result []*whisper.Message
for _, message := range messages {
shhMessage := whisper.ToWhisperMessage(message)
err := a.decryptMessage(context.Background(), shhMessage)
if err != nil { if err != nil {
logger.Warn("failed to decrypt a message", zap.Error(err), zap.Binary("messageID", shhMessage.Hash)) hlogger.Debug("failed to handle an encryption message", zap.Error(err))
}
result = append(result, shhMessage)
} }
return result, nil statusMessages, err := statusMessage.HandleDatasync(a.datasync)
if err != nil {
hlogger.Debug("failed to handle datasync message", zap.Error(err))
}
for _, statusMessage := range statusMessages {
err := statusMessage.HandleApplicationMetadata()
if err != nil {
hlogger.Error("failed to handle application metadata layer message", zap.Error(err))
}
if applicationLayer {
err = statusMessage.HandleApplication()
if err != nil {
hlogger.Error("failed to handle application layer message")
}
}
}
return statusMessages, nil
} }
func (a *whisperAdapter) decodeMessage(message *whisper.Message) (*protocol.StatusMessage, error) { func (a *whisperAdapter) handleEncryptionLayer(ctx context.Context, message *protocol.StatusMessage) error {
publicKey := message.SigPubKey()
publicKey, err := crypto.UnmarshalPubkey(message.Sig) logger := a.logger.With(zap.String("site", "handleEncryptionLayer"))
if err != nil {
return nil, err
}
decoded, err := protocol.DecodeMessage(publicKey, message.Payload) err := message.HandleEncryption(a.privateKey, publicKey, a.protocol)
if err != nil {
return nil, err
}
return &decoded, nil
}
func (a *whisperAdapter) decryptMessage(ctx context.Context, message *whisper.Message) error {
publicKey, err := crypto.UnmarshalPubkey(message.Sig)
if err != nil {
return errors.Wrap(err, "failed to get signature")
}
var protocolMessage encryption.ProtocolMessage
err = proto.Unmarshal(message.Payload, &protocolMessage)
if err != nil {
return errors.Wrap(err, "failed to unmarshal ProtocolMessage")
}
logger := a.logger.With(zap.String("site", "decryptMessage"))
payload, err := a.protocol.HandleMessage(
a.privateKey,
publicKey,
&protocolMessage,
message.Hash,
)
if err == encryption.ErrDeviceNotFound { if err == encryption.ErrDeviceNotFound {
handleErr := a.handleErrDeviceNotFound(ctx, publicKey) handleErr := a.handleErrDeviceNotFound(ctx, publicKey)
if handleErr != nil { if handleErr != nil {
@ -259,9 +271,7 @@ func (a *whisperAdapter) decryptMessage(ctx context.Context, message *whisper.Me
return errors.Wrap(err, "failed to process an encrypted message") return errors.Wrap(err, "failed to process an encrypted message")
} }
message.Payload = payload
return nil return nil
} }
func (a *whisperAdapter) handleErrDeviceNotFound(ctx context.Context, publicKey *ecdsa.PublicKey) error { func (a *whisperAdapter) handleErrDeviceNotFound(ctx context.Context, publicKey *ecdsa.PublicKey) error {
@ -307,11 +317,19 @@ func (a *whisperAdapter) SendPublic(ctx context.Context, chatName, chatID string
return nil, errors.Wrap(err, "failed to encode message") return nil, errors.Wrap(err, "failed to encode message")
} }
newMessage := whisper.NewMessage{ wrappedMessage, err := a.tryWrapMessageV1(encodedMessage)
TTL: whisperTTL, if err != nil {
Payload: encodedMessage, return nil, errors.Wrap(err, "failed to wrap message")
PowTarget: whisperPoW, }
PowTime: whisperPoWTime,
messageSpec, err := a.protocol.BuildPublicMessage(a.privateKey, wrappedMessage)
if err != nil {
return nil, errors.Wrap(err, "failed to build public message")
}
newMessage, err := a.messageSpecToWhisper(messageSpec)
if err != nil {
return nil, err
} }
_, err = a.transport.SendPublic(ctx, newMessage, chatName) _, err = a.transport.SendPublic(ctx, newMessage, chatName)
@ -319,18 +337,27 @@ func (a *whisperAdapter) SendPublic(ctx context.Context, chatName, chatID string
return nil, err return nil, err
} }
return protocol.MessageID(&a.privateKey.PublicKey, encodedMessage), nil return protocol.MessageID(&a.privateKey.PublicKey, wrappedMessage), nil
} }
// SendPublicRaw takes encoded data, encrypts it and sends through the wire. // SendPublicRaw takes encoded data, encrypts it and sends through the wire.
// DEPRECATED // DEPRECATED
func (a *whisperAdapter) SendPublicRaw(ctx context.Context, chatName string, data []byte) ([]byte, whisper.NewMessage, error) { func (a *whisperAdapter) SendPublicRaw(ctx context.Context, chatName string, data []byte) ([]byte, whisper.NewMessage, error) {
newMessage := whisper.NewMessage{
var newMessage whisper.NewMessage
wrappedMessage, err := a.tryWrapMessageV1(data)
if err != nil {
return nil, newMessage, errors.Wrap(err, "failed to wrap message")
}
newMessage = whisper.NewMessage{
TTL: whisperTTL, TTL: whisperTTL,
Payload: data, Payload: wrappedMessage,
PowTarget: whisperPoW, PowTarget: whisperPoW,
PowTime: whisperPoWTime, PowTime: whisperPoWTime,
} }
hash, err := a.transport.SendPublic(ctx, newMessage, chatName) hash, err := a.transport.SendPublic(ctx, newMessage, chatName)
return hash, newMessage, err return hash, newMessage, err
} }
@ -344,20 +371,25 @@ func (a *whisperAdapter) SendContactCode(ctx context.Context, messageSpec *encry
return a.transport.SendPublic(ctx, newMessage, filter.ContactCodeTopic(&a.privateKey.PublicKey)) return a.transport.SendPublic(ctx, newMessage, filter.ContactCodeTopic(&a.privateKey.PublicKey))
} }
func (a *whisperAdapter) tryWrapMessageV1(encodedMessage []byte) ([]byte, error) {
if a.featureFlags.sendV1Messages {
wrappedMessage, err := protocol.WrapMessageV1(encodedMessage, a.privateKey)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
return wrappedMessage, nil
}
return encodedMessage, nil
}
func (a *whisperAdapter) encodeMessage(message protocol.Message) ([]byte, error) { func (a *whisperAdapter) encodeMessage(message protocol.Message) ([]byte, error) {
encodedMessage, err := protocol.EncodeMessage(message) encodedMessage, err := protocol.EncodeMessage(message)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to encode message") return nil, errors.Wrap(err, "failed to encode message")
} }
if a.featureFlags.sendV1Messages {
encodedMessage, err = protocol.WrapMessageV1(encodedMessage, a.privateKey)
if err != nil {
return nil, errors.Wrap(err, "failed to wrap message")
}
}
return encodedMessage, nil return encodedMessage, nil
} }
@ -388,16 +420,43 @@ func (a *whisperAdapter) SendPrivate(
return nil, nil, errors.Wrap(err, "failed to encode message") return nil, nil, errors.Wrap(err, "failed to encode message")
} }
messageSpec, err := a.protocol.BuildDirectMessage(a.privateKey, publicKey, encodedMessage) wrappedMessage, err := a.tryWrapMessageV1(encodedMessage)
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "failed to encrypt message") return nil, nil, errors.Wrap(err, "failed to wrap message")
} }
_, err = a.sendMessageSpec(ctx, publicKey, messageSpec) if a.featureFlags.datasync {
if err := a.sendWithDataSync(publicKey, wrappedMessage); err != nil {
return nil, nil, errors.Wrap(err, "failed to send message with datasync")
}
} else {
err = a.encryptAndSend(ctx, publicKey, wrappedMessage)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return protocol.MessageID(&a.privateKey.PublicKey, encodedMessage), &message, nil }
return protocol.MessageID(&a.privateKey.PublicKey, wrappedMessage), &message, nil
}
func (a *whisperAdapter) sendWithDataSync(publicKey *ecdsa.PublicKey, message []byte) error {
groupID := datasync.ToOneToOneGroupID(&a.privateKey.PublicKey, publicKey)
peerID := datasyncpeer.PublicKeyToPeerID(*publicKey)
exist, err := a.datasync.IsPeerInGroup(groupID, peerID)
if err != nil {
return errors.Wrap(err, "failed to check if peer is in group")
}
if !exist {
if err := a.datasync.AddPeer(groupID, peerID); err != nil {
return errors.Wrap(err, "failed to add peer")
}
}
_, err = a.datasync.AppendMessage(groupID, message)
if err != nil {
return errors.Wrap(err, "failed to append message to datasync")
}
return nil
} }
// SendPrivateRaw takes encoded data, encrypts it and sends through the wire. // SendPrivateRaw takes encoded data, encrypts it and sends through the wire.
@ -415,7 +474,12 @@ func (a *whisperAdapter) SendPrivateRaw(
var newMessage whisper.NewMessage var newMessage whisper.NewMessage
messageSpec, err := a.protocol.BuildDirectMessage(a.privateKey, publicKey, data) wrappedMessage, err := a.tryWrapMessageV1(data)
if err != nil {
return nil, newMessage, errors.Wrap(err, "failed to wrap message")
}
messageSpec, err := a.protocol.BuildDirectMessage(a.privateKey, publicKey, wrappedMessage)
if err != nil { if err != nil {
return nil, newMessage, errors.Wrap(err, "failed to encrypt message") return nil, newMessage, errors.Wrap(err, "failed to encrypt message")
} }
@ -425,6 +489,13 @@ func (a *whisperAdapter) SendPrivateRaw(
return nil, newMessage, errors.Wrap(err, "failed to convert ProtocolMessageSpec to whisper.NewMessage") return nil, newMessage, errors.Wrap(err, "failed to convert ProtocolMessageSpec to whisper.NewMessage")
} }
if a.featureFlags.datasync {
if err := a.sendWithDataSync(publicKey, wrappedMessage); err != nil {
return nil, newMessage, errors.Wrap(err, "failed to send message with datasync")
}
return nil, newMessage, err
}
hash, err := a.sendMessageSpec(ctx, publicKey, messageSpec) hash, err := a.sendMessageSpec(ctx, publicKey, messageSpec)
return hash, newMessage, err return hash, newMessage, err
} }
@ -452,6 +523,18 @@ func (a *whisperAdapter) sendMessageSpec(ctx context.Context, publicKey *ecdsa.P
} }
} }
func (a *whisperAdapter) encryptAndSend(ctx context.Context, publicKey *ecdsa.PublicKey, encodedMessage []byte) error {
messageSpec, err := a.protocol.BuildDirectMessage(a.privateKey, publicKey, encodedMessage)
if err != nil {
return errors.Wrap(err, "failed to encrypt message")
}
_, err = a.sendMessageSpec(ctx, publicKey, messageSpec)
if err != nil {
return err
}
return nil
}
func (a *whisperAdapter) messageSpecToWhisper(spec *encryption.ProtocolMessageSpec) (whisper.NewMessage, error) { func (a *whisperAdapter) messageSpecToWhisper(spec *encryption.ProtocolMessageSpec) (whisper.NewMessage, error) {
var newMessage whisper.NewMessage var newMessage whisper.NewMessage

View File

@ -0,0 +1,85 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: message.proto
package applicationmetadata
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Message struct {
Signature []byte `protobuf:"bytes,4001,opt,name=signature,proto3" json:"signature,omitempty"`
Payload []byte `protobuf:"bytes,4002,opt,name=payload,proto3" json:"payload,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Message) Reset() { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage() {}
func (*Message) Descriptor() ([]byte, []int) {
return fileDescriptor_33c57e4bae7b9afd, []int{0}
}
func (m *Message) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Message.Unmarshal(m, b)
}
func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Message.Marshal(b, m, deterministic)
}
func (m *Message) XXX_Merge(src proto.Message) {
xxx_messageInfo_Message.Merge(m, src)
}
func (m *Message) XXX_Size() int {
return xxx_messageInfo_Message.Size(m)
}
func (m *Message) XXX_DiscardUnknown() {
xxx_messageInfo_Message.DiscardUnknown(m)
}
var xxx_messageInfo_Message proto.InternalMessageInfo
func (m *Message) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
func (m *Message) GetPayload() []byte {
if m != nil {
return m.Payload
}
return nil
}
func init() {
proto.RegisterType((*Message)(nil), "applicationmetadata.Message")
}
func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) }
var fileDescriptor_33c57e4bae7b9afd = []byte{
// 112 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x4d, 0x2d, 0x2e,
0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4e, 0x2c, 0x28, 0xc8, 0xc9,
0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0xcb, 0x4d, 0x2d, 0x49, 0x4c, 0x49, 0x2c, 0x49, 0x54, 0x72,
0xe6, 0x62, 0xf7, 0x85, 0xa8, 0x12, 0x92, 0xe5, 0xe2, 0x2c, 0xce, 0x4c, 0xcf, 0x4b, 0x2c, 0x29,
0x2d, 0x4a, 0x95, 0x58, 0x28, 0xaf, 0xc0, 0xa8, 0xc1, 0x13, 0x84, 0x10, 0x11, 0x92, 0xe4, 0x62,
0x2f, 0x48, 0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x91, 0x58, 0x04, 0x91, 0x84, 0xf1, 0x93, 0xd8, 0xc0,
0x16, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x7f, 0x4a, 0x96, 0x71, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,8 @@
syntax = "proto3";
package applicationmetadata;
message Message {
bytes signature = 4001;
bytes payload = 4002;
}

View File

@ -0,0 +1,22 @@
package applicationmetadata
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/crypto"
)
func (m *Message) RecoverKey() (*ecdsa.PublicKey, error) {
if m.Signature == nil {
return nil, nil
}
recoveredKey, err := crypto.SigToPub(
crypto.Keccak256(m.Payload),
m.Signature,
)
if err != nil {
return nil, err
}
return recoveredKey, nil
}

View File

@ -0,0 +1,17 @@
package applicationmetadata
import (
"github.com/golang/protobuf/proto"
)
//go:generate protoc --go_out=. ./message.proto
func Unmarshal(payload []byte) (*Message, error) {
var message Message
err := proto.Unmarshal(payload, &message)
if err != nil {
return nil, err
}
return &message, nil
}

View File

@ -0,0 +1,67 @@
package datasync
import (
"crypto/ecdsa"
"github.com/golang/protobuf/proto"
datasyncpeer "github.com/status-im/status-protocol-go/datasync/peer"
datasyncnode "github.com/vacp2p/mvds/node"
datasyncproto "github.com/vacp2p/mvds/protobuf"
datasynctransport "github.com/vacp2p/mvds/transport"
"go.uber.org/zap"
)
type DataSync struct {
*datasyncnode.Node
// DataSyncNodeTransport is the implemntation of the datasync transport interface
*DataSyncNodeTransport
logger *zap.Logger
sendingEnabled bool
}
func New(node *datasyncnode.Node, transport *DataSyncNodeTransport, sendingEnabled bool, logger *zap.Logger) *DataSync {
return &DataSync{Node: node, DataSyncNodeTransport: transport, sendingEnabled: sendingEnabled, logger: logger}
}
func (d *DataSync) Add(publicKey *ecdsa.PublicKey, datasyncMessage datasyncproto.Payload) {
packet := datasynctransport.Packet{
Sender: datasyncpeer.PublicKeyToPeerID(*publicKey),
Payload: datasyncMessage,
}
d.DataSyncNodeTransport.AddPacket(packet)
}
func (d *DataSync) Handle(sender *ecdsa.PublicKey, payload []byte) [][]byte {
var payloads [][]byte
logger := d.logger.With(zap.String("site", "Handle"))
datasyncMessage, err := unwrap(payload)
// If it failed to decode is not a protobuf message, if it successfully decoded but body is empty, is likedly a protobuf wrapped message
if err != nil || !datasyncMessage.IsValid() {
logger.Debug("handling non-datasync message", zap.Error(err), zap.Bool("datasyncMessage.IsValid()", datasyncMessage.IsValid()))
// Not a datasync message, return unchanged
payloads = append(payloads, payload)
} else {
logger.Debug("handling datasync message")
// datasync message
for _, message := range datasyncMessage.Messages {
//copiedMessage := statusMessage.Copy()
//copiedMessage.DataSyncLayerInfo.Payload = message.Body
payloads = append(payloads, message.Body)
}
if d.sendingEnabled {
d.Add(sender, datasyncMessage)
}
}
return payloads
}
func unwrap(payload []byte) (datasyncPayload datasyncproto.Payload, err error) {
err = proto.Unmarshal(payload, &datasyncPayload)
return
}
func (d *DataSync) Stop() {
d.Node.Stop()
}

View File

@ -0,0 +1,19 @@
package peer
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/crypto"
"github.com/vacp2p/mvds/state"
)
func PublicKeyToPeerID(k ecdsa.PublicKey) state.PeerID {
var p state.PeerID
copy(p[:], crypto.FromECDSAPub(&k))
return p
}
func PeerIDToPublicKey(p state.PeerID) (*ecdsa.PublicKey, error) {
return crypto.UnmarshalPubkey(p[:])
}

View File

@ -0,0 +1,61 @@
package datasync
import (
"context"
"crypto/ecdsa"
"errors"
"github.com/golang/protobuf/proto"
datasyncpeer "github.com/status-im/status-protocol-go/datasync/peer"
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
"github.com/vacp2p/mvds/transport"
)
var errNotInitialized = errors.New("Datasync transport not initialized")
type DataSyncNodeTransport struct {
packets chan transport.Packet
dispatch func(context.Context, *ecdsa.PublicKey, []byte) error
}
func NewDataSyncNodeTransport() *DataSyncNodeTransport {
return &DataSyncNodeTransport{
packets: make(chan transport.Packet),
}
}
func (t *DataSyncNodeTransport) Init(dispatch func(context.Context, *ecdsa.PublicKey, []byte) error) {
t.dispatch = dispatch
}
func (t *DataSyncNodeTransport) AddPacket(p transport.Packet) {
t.packets <- p
}
func (t *DataSyncNodeTransport) Watch() transport.Packet {
return <-t.packets
}
func (t *DataSyncNodeTransport) Send(_ state.PeerID, peer state.PeerID, payload protobuf.Payload) error {
if t.dispatch == nil {
return errNotInitialized
}
data, err := proto.Marshal(&payload)
if err != nil {
return err
}
publicKey, err := datasyncpeer.PeerIDToPublicKey(peer)
if err != nil {
return err
}
return t.dispatch(context.TODO(), publicKey, data)
}
// CalculateSendTime calculates the next epoch
// at which a message should be sent.
func CalculateSendTime(count uint64, time int64) int64 {
return time + int64(count*2) // @todo this should match that time is increased by whisper periods, aka we only retransmit the first time when a message has expired.
}

View File

@ -0,0 +1,28 @@
package datasync
import (
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/crypto"
"github.com/vacp2p/mvds/state"
)
func ToGroupID(data []byte) state.GroupID {
g := state.GroupID{}
copy(g[:], data[:])
return g
}
// ToOneToOneGroupID returns a groupID for a onetoonechat, which is taken by
// concatenating the bytes of the compressed keys, in ascending order by X
func ToOneToOneGroupID(key1 *ecdsa.PublicKey, key2 *ecdsa.PublicKey) state.GroupID {
pk1 := crypto.CompressPubkey(key1)
pk2 := crypto.CompressPubkey(key2)
var groupID []byte
if key1.X.Cmp(key2.X) == -1 {
groupID = append(pk1, pk2...)
} else {
groupID = append(pk2, pk1...)
}
return ToGroupID(crypto.Keccak256(groupID))
}

View File

@ -13,8 +13,6 @@
// 1558588866_add_version.up.sql (57B) // 1558588866_add_version.up.sql (57B)
// 1559627659_add_contact_code.down.sql (32B) // 1559627659_add_contact_code.down.sql (32B)
// 1559627659_add_contact_code.up.sql (198B) // 1559627659_add_contact_code.up.sql (198B)
// 1561059285_add_whisper_keys.down.sql (25B)
// 1561059285_add_whisper_keys.up.sql (112B)
// 1561368210_add_installation_metadata.down.sql (35B) // 1561368210_add_installation_metadata.down.sql (35B)
// 1561368210_add_installation_metadata.up.sql (267B) // 1561368210_add_installation_metadata.up.sql (267B)
// doc.go (377B) // doc.go (377B)
@ -101,7 +99,7 @@ func _1536754952_initial_schemaDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1536754952_initial_schema.down.sql", size: 83, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x44, 0xcf, 0x76, 0x71, 0x1f, 0x5e, 0x9a, 0x43, 0xd8, 0xcd, 0xb8, 0xc3, 0x70, 0xc3, 0x7f, 0xfc, 0x90, 0xb4, 0x25, 0x1e, 0xf4, 0x66, 0x20, 0xb8, 0x33, 0x7e, 0xb0, 0x76, 0x1f, 0xc, 0xc0, 0x75}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x44, 0xcf, 0x76, 0x71, 0x1f, 0x5e, 0x9a, 0x43, 0xd8, 0xcd, 0xb8, 0xc3, 0x70, 0xc3, 0x7f, 0xfc, 0x90, 0xb4, 0x25, 0x1e, 0xf4, 0x66, 0x20, 0xb8, 0x33, 0x7e, 0xb0, 0x76, 0x1f, 0xc, 0xc0, 0x75}}
return a, nil return a, nil
} }
@ -121,7 +119,7 @@ func _1536754952_initial_schemaUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1536754952_initial_schema.up.sql", size: 962, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x90, 0x5a, 0x59, 0x3e, 0x3, 0xe2, 0x3c, 0x81, 0x42, 0xcd, 0x4c, 0x9a, 0xe8, 0xda, 0x93, 0x2b, 0x70, 0xa4, 0xd5, 0x29, 0x3e, 0xd5, 0xc9, 0x27, 0xb6, 0xb7, 0x65, 0xff, 0x0, 0xcb, 0xde}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xea, 0x90, 0x5a, 0x59, 0x3e, 0x3, 0xe2, 0x3c, 0x81, 0x42, 0xcd, 0x4c, 0x9a, 0xe8, 0xda, 0x93, 0x2b, 0x70, 0xa4, 0xd5, 0x29, 0x3e, 0xd5, 0xc9, 0x27, 0xb6, 0xb7, 0x65, 0xff, 0x0, 0xcb, 0xde}}
return a, nil return a, nil
} }
@ -141,7 +139,7 @@ func _1539249977_update_ratchet_infoDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1539249977_update_ratchet_info.down.sql", size: 311, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xa4, 0xeb, 0xa0, 0xe6, 0xa0, 0xd4, 0x48, 0xbb, 0xad, 0x6f, 0x7d, 0x67, 0x8c, 0xbd, 0x25, 0xde, 0x1f, 0x73, 0x9a, 0xbb, 0xa8, 0xc9, 0x30, 0xb7, 0xa9, 0x7c, 0xaf, 0xb5, 0x1, 0x61, 0xdd}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0xa4, 0xeb, 0xa0, 0xe6, 0xa0, 0xd4, 0x48, 0xbb, 0xad, 0x6f, 0x7d, 0x67, 0x8c, 0xbd, 0x25, 0xde, 0x1f, 0x73, 0x9a, 0xbb, 0xa8, 0xc9, 0x30, 0xb7, 0xa9, 0x7c, 0xaf, 0xb5, 0x1, 0x61, 0xdd}}
return a, nil return a, nil
} }
@ -161,7 +159,7 @@ func _1539249977_update_ratchet_infoUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1539249977_update_ratchet_info.up.sql", size: 368, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x8e, 0xbf, 0x6f, 0xa, 0xc0, 0xe1, 0x3c, 0x42, 0x28, 0x88, 0x1d, 0xdb, 0xba, 0x1c, 0x83, 0xec, 0xba, 0xd3, 0x5f, 0x5c, 0x77, 0x5e, 0xa7, 0x46, 0x36, 0xec, 0x69, 0xa, 0x4b, 0x17, 0x79}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc, 0x8e, 0xbf, 0x6f, 0xa, 0xc0, 0xe1, 0x3c, 0x42, 0x28, 0x88, 0x1d, 0xdb, 0xba, 0x1c, 0x83, 0xec, 0xba, 0xd3, 0x5f, 0x5c, 0x77, 0x5e, 0xa7, 0x46, 0x36, 0xec, 0x69, 0xa, 0x4b, 0x17, 0x79}}
return a, nil return a, nil
} }
@ -181,7 +179,7 @@ func _1540715431_add_versionDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1540715431_add_version.down.sql", size: 127, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x9, 0x4, 0xe3, 0x76, 0x2e, 0xb8, 0x9, 0x23, 0xf0, 0x70, 0x93, 0xc4, 0x50, 0xe, 0x9d, 0x84, 0x22, 0x8c, 0x94, 0xd3, 0x24, 0x9, 0x9a, 0xc1, 0xa1, 0x48, 0x45, 0xfd, 0x40, 0x6e, 0xe6}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x9, 0x4, 0xe3, 0x76, 0x2e, 0xb8, 0x9, 0x23, 0xf0, 0x70, 0x93, 0xc4, 0x50, 0xe, 0x9d, 0x84, 0x22, 0x8c, 0x94, 0xd3, 0x24, 0x9, 0x9a, 0xc1, 0xa1, 0x48, 0x45, 0xfd, 0x40, 0x6e, 0xe6}}
return a, nil return a, nil
} }
@ -201,7 +199,7 @@ func _1540715431_add_versionUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1540715431_add_version.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc7, 0x4c, 0x36, 0x96, 0xdf, 0x16, 0x10, 0xa6, 0x27, 0x1a, 0x79, 0x8b, 0x42, 0x83, 0x23, 0xc, 0x7e, 0xb6, 0x3d, 0x2, 0xda, 0xa4, 0xb4, 0xd, 0x27, 0x55, 0xba, 0xdc, 0xb2, 0x88, 0x8f, 0xa6}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xc7, 0x4c, 0x36, 0x96, 0xdf, 0x16, 0x10, 0xa6, 0x27, 0x1a, 0x79, 0x8b, 0x42, 0x83, 0x23, 0xc, 0x7e, 0xb6, 0x3d, 0x2, 0xda, 0xa4, 0xb4, 0xd, 0x27, 0x55, 0xba, 0xdc, 0xb2, 0x88, 0x8f, 0xa6}}
return a, nil return a, nil
} }
@ -221,7 +219,7 @@ func _1541164797_add_installationsDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1541164797_add_installations.down.sql", size: 26, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xfd, 0xe6, 0xd8, 0xca, 0x3b, 0x38, 0x18, 0xee, 0x0, 0x5f, 0x36, 0x9e, 0x1e, 0xd, 0x19, 0x3e, 0xb4, 0x73, 0x53, 0xe9, 0xa5, 0xac, 0xdd, 0xa1, 0x2f, 0xc7, 0x6c, 0xa8, 0xd9, 0xa, 0x88}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0xfd, 0xe6, 0xd8, 0xca, 0x3b, 0x38, 0x18, 0xee, 0x0, 0x5f, 0x36, 0x9e, 0x1e, 0xd, 0x19, 0x3e, 0xb4, 0x73, 0x53, 0xe9, 0xa5, 0xac, 0xdd, 0xa1, 0x2f, 0xc7, 0x6c, 0xa8, 0xd9, 0xa, 0x88}}
return a, nil return a, nil
} }
@ -241,7 +239,7 @@ func _1541164797_add_installationsUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1541164797_add_installations.up.sql", size: 216, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2d, 0x18, 0x26, 0xb8, 0x88, 0x47, 0xdb, 0x83, 0xcc, 0xb6, 0x9d, 0x1c, 0x1, 0xae, 0x2f, 0xde, 0x97, 0x82, 0x3, 0x30, 0xa8, 0x63, 0xa1, 0x78, 0x4b, 0xa5, 0x9, 0x8, 0x75, 0xa2, 0x57, 0x81}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2d, 0x18, 0x26, 0xb8, 0x88, 0x47, 0xdb, 0x83, 0xcc, 0xb6, 0x9d, 0x1c, 0x1, 0xae, 0x2f, 0xde, 0x97, 0x82, 0x3, 0x30, 0xa8, 0x63, 0xa1, 0x78, 0x4b, 0xa5, 0x9, 0x8, 0x75, 0xa2, 0x57, 0x81}}
return a, nil return a, nil
} }
@ -261,7 +259,7 @@ func _1558084410_add_secretDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1558084410_add_secret.down.sql", size: 56, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xb, 0x65, 0xdf, 0x59, 0xbf, 0xe9, 0x5, 0x5b, 0x6f, 0xd5, 0x3a, 0xb7, 0x57, 0xe8, 0x78, 0x38, 0x73, 0x53, 0x57, 0xf7, 0x24, 0x4, 0xe4, 0xa2, 0x49, 0x22, 0xa2, 0xc6, 0xfd, 0x80, 0xa4}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x49, 0xb, 0x65, 0xdf, 0x59, 0xbf, 0xe9, 0x5, 0x5b, 0x6f, 0xd5, 0x3a, 0xb7, 0x57, 0xe8, 0x78, 0x38, 0x73, 0x53, 0x57, 0xf7, 0x24, 0x4, 0xe4, 0xa2, 0x49, 0x22, 0xa2, 0xc6, 0xfd, 0x80, 0xa4}}
return a, nil return a, nil
} }
@ -281,7 +279,7 @@ func _1558084410_add_secretUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1558084410_add_secret.up.sql", size: 301, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x32, 0x36, 0x8e, 0x47, 0xb0, 0x8f, 0xc1, 0xc6, 0xf7, 0xc6, 0x9f, 0x2d, 0x44, 0x75, 0x2b, 0x26, 0xec, 0x6, 0xa0, 0x7b, 0xa5, 0xbd, 0xc8, 0x76, 0x8a, 0x82, 0x68, 0x2, 0x42, 0xb5, 0xf4}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf5, 0x32, 0x36, 0x8e, 0x47, 0xb0, 0x8f, 0xc1, 0xc6, 0xf7, 0xc6, 0x9f, 0x2d, 0x44, 0x75, 0x2b, 0x26, 0xec, 0x6, 0xa0, 0x7b, 0xa5, 0xbd, 0xc8, 0x76, 0x8a, 0x82, 0x68, 0x2, 0x42, 0xb5, 0xf4}}
return a, nil return a, nil
} }
@ -301,7 +299,7 @@ func _1558588866_add_versionUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1558588866_add_version.up.sql", size: 57, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2a, 0xea, 0x64, 0x39, 0x61, 0x20, 0x83, 0x83, 0xb, 0x2e, 0x79, 0x64, 0xb, 0x53, 0xfa, 0xfe, 0xc6, 0xf7, 0x67, 0x42, 0xd3, 0x4f, 0xdc, 0x7e, 0x30, 0x32, 0xe8, 0x14, 0x41, 0xe9, 0xe7, 0x3b}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x2a, 0xea, 0x64, 0x39, 0x61, 0x20, 0x83, 0x83, 0xb, 0x2e, 0x79, 0x64, 0xb, 0x53, 0xfa, 0xfe, 0xc6, 0xf7, 0x67, 0x42, 0xd3, 0x4f, 0xdc, 0x7e, 0x30, 0x32, 0xe8, 0x14, 0x41, 0xe9, 0xe7, 0x3b}}
return a, nil return a, nil
} }
@ -321,7 +319,7 @@ func _1559627659_add_contact_codeDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1559627659_add_contact_code.down.sql", size: 32, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5d, 0x64, 0x6d, 0xce, 0x24, 0x42, 0x20, 0x8d, 0x4f, 0x37, 0xaa, 0x9d, 0xc, 0x57, 0x98, 0xc1, 0xd1, 0x1a, 0x34, 0xcd, 0x9f, 0x8f, 0x34, 0x86, 0xb3, 0xd3, 0xdc, 0xf1, 0x7d, 0xe5, 0x1b, 0x6e}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5d, 0x64, 0x6d, 0xce, 0x24, 0x42, 0x20, 0x8d, 0x4f, 0x37, 0xaa, 0x9d, 0xc, 0x57, 0x98, 0xc1, 0xd1, 0x1a, 0x34, 0xcd, 0x9f, 0x8f, 0x34, 0x86, 0xb3, 0xd3, 0xdc, 0xf1, 0x7d, 0xe5, 0x1b, 0x6e}}
return a, nil return a, nil
} }
@ -341,51 +339,11 @@ func _1559627659_add_contact_codeUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1559627659_add_contact_code.up.sql", size: 198, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x16, 0xf6, 0xc2, 0x62, 0x9c, 0xd2, 0xc9, 0x1e, 0xd8, 0xea, 0xaa, 0xea, 0x95, 0x8f, 0x89, 0x6a, 0x85, 0x5d, 0x9d, 0x99, 0x78, 0x3c, 0x90, 0x66, 0x99, 0x3e, 0x4b, 0x19, 0x62, 0xfb, 0x31, 0x4d}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x16, 0xf6, 0xc2, 0x62, 0x9c, 0xd2, 0xc9, 0x1e, 0xd8, 0xea, 0xaa, 0xea, 0x95, 0x8f, 0x89, 0x6a, 0x85, 0x5d, 0x9d, 0x99, 0x78, 0x3c, 0x90, 0x66, 0x99, 0x3e, 0x4b, 0x19, 0x62, 0xfb, 0x31, 0x4d}}
return a, nil return a, nil
} }
var __1561059285_add_whisper_keysDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\xcf\xc8\x2c\x2e\x48\x2d\x8a\xcf\x4e\xad\x2c\xb6\xe6\x02\x04\x00\x00\xff\xff\x42\x93\x8e\x79\x19\x00\x00\x00")
func _1561059285_add_whisper_keysDownSqlBytes() ([]byte, error) {
return bindataRead(
__1561059285_add_whisper_keysDownSql,
"1561059285_add_whisper_keys.down.sql",
)
}
func _1561059285_add_whisper_keysDownSql() (*asset, error) {
bytes, err := _1561059285_add_whisper_keysDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0x31, 0x3f, 0xce, 0xfa, 0x44, 0x36, 0x1b, 0xb0, 0xec, 0x5d, 0xb, 0x90, 0xb, 0x21, 0x4f, 0xd5, 0xe5, 0x50, 0xed, 0xc7, 0x43, 0xdf, 0x83, 0xb4, 0x3a, 0xc1, 0x55, 0x2e, 0x53, 0x7c, 0x67}}
return a, nil
}
var __1561059285_add_whisper_keysUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\xb1\x0a\xc2\x40\x0c\x06\xe0\xfd\x9e\xe2\x1f\x15\x7c\x03\xa7\xde\x19\x35\x18\x13\x09\x29\xb5\x53\x11\x3d\x68\xe9\x22\x56\x90\xbe\xbd\x5f\x71\x6a\x82\x10\x4d\x16\xc2\x6f\x9c\x96\x77\xfd\x0c\x73\x5d\x17\x6c\x12\xf0\x1c\x1f\xdf\x61\x7a\x21\xe8\x1e\xb8\x39\x5f\x1b\xef\x71\xa1\x1e\xa6\x28\xa6\x47\xe1\x12\xe0\x93\x9a\xd3\x2e\x01\x73\x5d\x91\xc5\x32\xd4\x02\xda\x8a\xa4\x2d\x3a\x8e\xb3\xb5\x01\xb7\x8e\x0f\xfb\xf4\x0f\x00\x00\xff\xff\x6e\x23\x28\x7d\x70\x00\x00\x00")
func _1561059285_add_whisper_keysUpSqlBytes() ([]byte, error) {
return bindataRead(
__1561059285_add_whisper_keysUpSql,
"1561059285_add_whisper_keys.up.sql",
)
}
func _1561059285_add_whisper_keysUpSql() (*asset, error) {
bytes, err := _1561059285_add_whisper_keysUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x41, 0xc, 0x92, 0xdd, 0x9e, 0xff, 0x5d, 0xd0, 0x93, 0xe4, 0x24, 0x50, 0x29, 0xcf, 0xc6, 0xf7, 0x49, 0x3c, 0x73, 0xd9, 0x8c, 0xfa, 0xf2, 0xcf, 0xf6, 0x6f, 0xbc, 0x31, 0xe6, 0xf7, 0xe2}}
return a, nil
}
var __1561368210_add_installation_metadataDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\xc8\xcc\x2b\x2e\x49\xcc\xc9\x49\x2c\xc9\xcc\xcf\x2b\x8e\xcf\x4d\x2d\x49\x4c\x49\x2c\x49\xb4\xe6\x02\x04\x00\x00\xff\xff\x03\x72\x7f\x08\x23\x00\x00\x00") var __1561368210_add_installation_metadataDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\xc8\xcc\x2b\x2e\x49\xcc\xc9\x49\x2c\xc9\xcc\xcf\x2b\x8e\xcf\x4d\x2d\x49\x4c\x49\x2c\x49\xb4\xe6\x02\x04\x00\x00\xff\xff\x03\x72\x7f\x08\x23\x00\x00\x00")
func _1561368210_add_installation_metadataDownSqlBytes() ([]byte, error) { func _1561368210_add_installation_metadataDownSqlBytes() ([]byte, error) {
@ -401,7 +359,7 @@ func _1561368210_add_installation_metadataDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1561368210_add_installation_metadata.down.sql", size: 35, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xde, 0x3f, 0xd2, 0x4a, 0x50, 0x98, 0x56, 0xe3, 0xc0, 0xcd, 0x9d, 0xb0, 0x34, 0x3b, 0xe5, 0x62, 0x18, 0xb5, 0x20, 0xc9, 0x3e, 0xdc, 0x6a, 0x40, 0x36, 0x66, 0xea, 0x51, 0x8c, 0x71, 0xf5}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xa8, 0xde, 0x3f, 0xd2, 0x4a, 0x50, 0x98, 0x56, 0xe3, 0xc0, 0xcd, 0x9d, 0xb0, 0x34, 0x3b, 0xe5, 0x62, 0x18, 0xb5, 0x20, 0xc9, 0x3e, 0xdc, 0x6a, 0x40, 0x36, 0x66, 0xea, 0x51, 0x8c, 0x71, 0xf5}}
return a, nil return a, nil
} }
@ -421,7 +379,7 @@ func _1561368210_add_installation_metadataUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1562427968, 0)} info := bindataFileInfo{name: "1561368210_add_installation_metadata.up.sql", size: 267, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0x71, 0x8f, 0x29, 0xb1, 0xaa, 0xd6, 0xd1, 0x8c, 0x17, 0xef, 0x6c, 0xd5, 0x80, 0xb8, 0x2c, 0xc3, 0xfe, 0xec, 0x24, 0x4d, 0xc8, 0x25, 0xd3, 0xb4, 0xcd, 0xa9, 0xac, 0x63, 0x61, 0xb2, 0x9c}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb4, 0x71, 0x8f, 0x29, 0xb1, 0xaa, 0xd6, 0xd1, 0x8c, 0x17, 0xef, 0x6c, 0xd5, 0x80, 0xb8, 0x2c, 0xc3, 0xfe, 0xec, 0x24, 0x4d, 0xc8, 0x25, 0xd3, 0xb4, 0xcd, 0xa9, 0xac, 0x63, 0x61, 0xb2, 0x9c}}
return a, nil return a, nil
} }
@ -441,7 +399,7 @@ func docGo() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1562955235, 0)} info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}}
return a, nil return a, nil
} }
@ -563,10 +521,6 @@ var _bindata = map[string]func() (*asset, error){
"1559627659_add_contact_code.up.sql": _1559627659_add_contact_codeUpSql, "1559627659_add_contact_code.up.sql": _1559627659_add_contact_codeUpSql,
"1561059285_add_whisper_keys.down.sql": _1561059285_add_whisper_keysDownSql,
"1561059285_add_whisper_keys.up.sql": _1561059285_add_whisper_keysUpSql,
"1561368210_add_installation_metadata.down.sql": _1561368210_add_installation_metadataDownSql, "1561368210_add_installation_metadata.down.sql": _1561368210_add_installation_metadataDownSql,
"1561368210_add_installation_metadata.up.sql": _1561368210_add_installation_metadataUpSql, "1561368210_add_installation_metadata.up.sql": _1561368210_add_installation_metadataUpSql,
@ -628,8 +582,6 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1558588866_add_version.up.sql": &bintree{_1558588866_add_versionUpSql, map[string]*bintree{}}, "1558588866_add_version.up.sql": &bintree{_1558588866_add_versionUpSql, map[string]*bintree{}},
"1559627659_add_contact_code.down.sql": &bintree{_1559627659_add_contact_codeDownSql, map[string]*bintree{}}, "1559627659_add_contact_code.down.sql": &bintree{_1559627659_add_contact_codeDownSql, map[string]*bintree{}},
"1559627659_add_contact_code.up.sql": &bintree{_1559627659_add_contact_codeUpSql, map[string]*bintree{}}, "1559627659_add_contact_code.up.sql": &bintree{_1559627659_add_contact_codeUpSql, map[string]*bintree{}},
"1561059285_add_whisper_keys.down.sql": &bintree{_1561059285_add_whisper_keysDownSql, map[string]*bintree{}},
"1561059285_add_whisper_keys.up.sql": &bintree{_1561059285_add_whisper_keysUpSql, map[string]*bintree{}},
"1561368210_add_installation_metadata.down.sql": &bintree{_1561368210_add_installation_metadataDownSql, map[string]*bintree{}}, "1561368210_add_installation_metadata.down.sql": &bintree{_1561368210_add_installation_metadataDownSql, map[string]*bintree{}},
"1561368210_add_installation_metadata.up.sql": &bintree{_1561368210_add_installation_metadataUpSql, map[string]*bintree{}}, "1561368210_add_installation_metadata.up.sql": &bintree{_1561368210_add_installation_metadataUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}}, "doc.go": &bintree{docGo, map[string]*bintree{}},

View File

@ -6,7 +6,8 @@ require (
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 // indirect github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 // indirect
github.com/deckarep/golang-set v1.7.1 // indirect github.com/deckarep/golang-set v1.7.1 // indirect
github.com/ethereum/go-ethereum v1.8.27 github.com/ethereum/go-ethereum v1.8.27
github.com/golang/protobuf v1.3.1 github.com/golang/protobuf v1.3.2
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
github.com/leodido/go-urn v1.1.0 // indirect github.com/leodido/go-urn v1.1.0 // indirect
github.com/mutecomm/go-sqlcipher v0.0.0-20170920224653-f799951b4ab2 github.com/mutecomm/go-sqlcipher v0.0.0-20170920224653-f799951b4ab2
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
@ -17,6 +18,7 @@ require (
github.com/status-im/status-go v0.29.0-beta.3 github.com/status-im/status-go v0.29.0-beta.3
github.com/status-im/whisper v1.4.14 github.com/status-im/whisper v1.4.14
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/vacp2p/mvds v0.0.19
go.uber.org/atomic v1.4.0 // indirect go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.1.0 // indirect go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0 go.uber.org/zap v1.10.0

View File

@ -127,6 +127,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@ -184,6 +186,8 @@ github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s=
github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@ -364,6 +368,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20170809224252-890a5c3458b4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v0.0.0-20190716104307-221dbe5ed46703ee255b1da0dec05086f5035f62/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -373,6 +378,8 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v0.0.0-20180607151842-f7e0d4744fa6/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v0.0.0-20180615202729-a51202d6f4a7/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/vacp2p/mvds v0.0.19 h1:ZXopUNicQPzmIsggqa9Pbd6cqphFiyhthe3kneuJpC8=
github.com/vacp2p/mvds v0.0.19/go.mod h1:MxvN/VFp5zkjhUfJdBft+NrsVDwMsvueDIP2x0h6Tx8=
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8=

View File

@ -1,9 +1,7 @@
// Code generated by go-bindata. DO NOT EDIT. // Code generated by go-bindata. DO NOT EDIT.
// sources: // sources:
// 000001_add_messages_contacts.down.db.sql (91B) // 000001_init.down.db.sql (82B)
// 000001_add_messages_contacts.up.db.sql (685B) // 000001_init.up.db.sql (840B)
// 000002_add_unread_to_user_messages.down.sql (210B)
// 000002_add_unread_to_user_messages.up.sql (113B)
// doc.go (377B) // doc.go (377B)
package sqlite package sqlite
@ -73,83 +71,43 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil return nil
} }
var __000001_add_messages_contactsDownDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x2d\x4e\x2d\x8a\xcf\x4d\x2d\x2e\x4e\x4c\x4f\x2d\xb6\xe6\x42\x97\x49\xce\xcf\x2b\x49\x4c\x2e\x41\x95\xc9\xc8\x2c\x2e\xc9\x2f\xaa\x8c\x47\x56\x11\x5f\x92\x5f\x90\x99\x6c\xcd\x05\x08\x00\x00\xff\xff\x1b\x57\x14\x62\x5b\x00\x00\x00") var __000001_initDownDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x28\x2d\x4e\x2d\x8a\xcf\x4d\x2d\x2e\x4e\x4c\x4f\x2d\xb6\xe6\x42\x92\xc9\x4d\xcd\x4d\x4a\x2d\x2a\xce\xc8\x2c\x88\x2f\x2d\x48\x49\x2c\x41\x93\x4e\xce\x48\x2c\x89\x87\xaa\xb1\xe6\x02\x04\x00\x00\xff\xff\x69\x98\x5e\xa1\x52\x00\x00\x00")
func _000001_add_messages_contactsDownDbSqlBytes() ([]byte, error) { func _000001_initDownDbSqlBytes() ([]byte, error) {
return bindataRead( return bindataRead(
__000001_add_messages_contactsDownDbSql, __000001_initDownDbSql,
"000001_add_messages_contacts.down.db.sql", "000001_init.down.db.sql",
) )
} }
func _000001_add_messages_contactsDownDbSql() (*asset, error) { func _000001_initDownDbSql() (*asset, error) {
bytes, err := _000001_add_messages_contactsDownDbSqlBytes() bytes, err := _000001_initDownDbSqlBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "000001_add_messages_contacts.down.db.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 0)} info := bindataFileInfo{name: "000001_init.down.db.sql", size: 82, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xee, 0x89, 0x87, 0xa3, 0x2, 0x4f, 0xb4, 0x8c, 0x2c, 0x15, 0x41, 0x85, 0x3c, 0xbe, 0x71, 0x55, 0xa1, 0x6a, 0xa1, 0x5e, 0x8e, 0xd8, 0xcf, 0x84, 0xed, 0xb0, 0x60, 0x3, 0xcb, 0xb5, 0x33, 0x7c}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0x5f, 0xe0, 0x6, 0xfc, 0xed, 0xb7, 0xff, 0xb5, 0xf3, 0x33, 0x45, 0x1, 0x5b, 0x84, 0x80, 0x74, 0x60, 0x81, 0xa6, 0x8b, 0xb4, 0xd4, 0xad, 0x10, 0xa8, 0xb3, 0x61, 0x6f, 0xc5, 0x2f, 0xaa}}
return a, nil return a, nil
} }
var __000001_add_messages_contactsUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x92\xcf\x6e\xb3\x30\x10\xc4\xef\x7e\x8a\x3d\xf2\x49\x1c\xbe\x7b\x4f\x06\x96\xc4\x2a\xb5\x5b\xc7\x34\xc9\x09\x51\xc7\x6a\x50\xc2\x1f\xc5\x8e\x54\xde\xbe\x82\x42\xe3\xa6\x69\xae\x33\xf6\x7a\xe6\xb7\x8e\x25\x52\x85\xa0\x68\x94\x21\xb0\x14\xb8\x50\x80\x1b\xb6\x52\x2b\x38\x5b\x73\x2a\x6a\x63\x6d\xf9\x6e\x2c\x04\xa4\xda\x41\x94\x89\x08\x72\xce\x5e\x72\x1c\x4f\xf2\x3c\xcb\x42\xa2\xdb\xc6\x95\xda\x15\xd5\x0e\x5e\xa9\x8c\x97\x54\x5e\x99\xa6\x71\x85\xeb\x3b\x33\xdb\x21\x99\xc6\x5e\xa9\xce\x7c\x38\x50\xb8\x51\x21\xd1\xc7\x56\x1f\x20\x62\x0b\xc6\x55\x48\x5c\x55\x1b\xeb\xca\xba\xfb\x56\xe6\xb1\x7a\x5f\x8e\x0f\x4f\xb7\xe6\xc7\x2e\x83\xba\xf3\xdb\xb1\xd2\xc5\xc1\xf4\x63\x7a\xf2\xef\x81\x90\xa9\x34\xe3\x09\x6e\xe0\x92\xde\x82\xe0\x3f\x5b\x07\x17\xd3\xbb\xf7\x27\xac\xe9\xf4\x04\x6b\x66\xf1\x2c\xd9\x13\x95\x5b\x78\xc4\xad\xc7\xa5\x29\x6b\x73\x03\x97\x6b\xbb\x4a\x8f\xd1\x7d\x71\xa0\xc4\xb8\x2f\x59\x57\xba\x51\xbb\xd1\x10\xd6\x4c\x2d\x45\xae\x40\x8a\x35\x4b\xee\xe7\xde\x57\xd6\xb5\xa7\xbe\xf0\xf3\x17\x5f\x21\x02\x62\xfb\x46\x9b\xdd\xc4\x1c\x12\x4c\x69\x9e\x29\xf8\x7f\x7f\xf5\xbf\xbe\x47\x2a\x24\xb2\x05\x1f\xfa\xfb\x3c\x41\x62\x8a\x12\x79\x8c\x57\xf4\x82\xc1\x14\x1c\x12\xcc\x50\x21\xc4\x74\x15\xd3\x04\x87\xc5\x7d\x06\x00\x00\xff\xff\x28\x6d\x42\x61\xad\x02\x00\x00") var __000001_initUpDbSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x52\xb1\x6e\xc2\x30\x14\xdc\xf3\x15\x6f\x24\x12\x43\xf7\x4e\x0e\xbc\x80\xd5\xd4\x6e\x1d\xa7\xc0\x14\x19\xe2\x82\x0b\x09\x11\x36\x52\xf9\xfb\xaa\x49\x8c\x02\x45\x15\xac\xef\xce\xe7\xbb\x7b\x6f\x24\x90\x48\x04\x49\xa2\x04\x81\xc6\xc0\xb8\x04\x9c\xd3\x54\xa6\x70\xb4\xfa\x90\x97\xda\x5a\xb5\xd6\x16\x06\x01\x00\x80\x29\x20\x4a\x78\x04\x19\xa3\xef\x19\x36\x6c\x96\x25\xc9\xb0\x01\x57\x1b\xe5\x72\x53\xc0\x07\x11\xa3\x29\x11\xd7\xe8\xbe\x72\xba\x72\xb9\x3b\xd5\xda\x53\x5a\xa4\xfb\xe3\x06\xe2\xf4\xb7\x03\x89\x73\xd9\x49\xec\xf6\xab\x2d\x44\x74\x42\x59\x37\x71\xa6\xd4\xd6\xa9\xb2\xbe\x98\xfa\xaf\xbc\xa1\x9e\x82\x37\x71\x29\x5c\x1f\x97\x3b\xb3\xca\xb7\xfa\xd4\xc4\x6b\x87\x9f\x3b\xb5\xb6\x40\x99\x3c\x07\x81\x31\xc6\x24\x4b\x24\x3c\x05\xe1\x73\x10\x74\xdd\x51\x36\xc6\xb9\x0f\x6f\x81\xb3\xcb\xe6\x06\x1d\xd2\x7b\x71\xab\xed\x52\x97\x4b\x7d\xb0\x1b\x53\xe7\xc7\xba\x50\xae\x5f\xb9\x2f\xf4\x4d\xd0\x57\x22\x16\xf0\x82\x8b\xab\x72\x0b\xe5\x54\xbb\x99\x47\x56\x12\x73\x81\x74\xc2\x1a\xbd\xb3\x4d\x10\x18\xa3\x40\x36\xc2\xb4\x79\x6e\x07\xa6\x08\x83\x10\x66\x54\x4e\x79\x26\x41\xf0\x19\x1d\xff\x9f\xa5\x91\xea\x02\x75\x29\xae\x1a\x7e\xc8\xa6\x2a\x4a\x53\x41\xc4\x79\x82\x84\xfd\x5d\x46\x4c\x92\x14\x5b\xe6\xd7\xde\x54\xba\xb8\x8b\x7a\x7f\xf6\x96\xdf\x5e\xbc\x67\x0e\x7b\x81\xc2\xdf\x63\xf8\x09\x00\x00\xff\xff\x66\xab\x2d\x2f\x48\x03\x00\x00")
func _000001_add_messages_contactsUpDbSqlBytes() ([]byte, error) { func _000001_initUpDbSqlBytes() ([]byte, error) {
return bindataRead( return bindataRead(
__000001_add_messages_contactsUpDbSql, __000001_initUpDbSql,
"000001_add_messages_contacts.up.db.sql", "000001_init.up.db.sql",
) )
} }
func _000001_add_messages_contactsUpDbSql() (*asset, error) { func _000001_initUpDbSql() (*asset, error) {
bytes, err := _000001_add_messages_contactsUpDbSqlBytes() bytes, err := _000001_initUpDbSqlBytes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "000001_add_messages_contacts.up.db.sql", size: 685, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 0)} info := bindataFileInfo{name: "000001_init.up.db.sql", size: 840, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1d, 0xd, 0x9, 0xd8, 0x7d, 0xba, 0x90, 0x3c, 0x7c, 0x6, 0xf2, 0x12, 0xb2, 0xbc, 0xd8, 0xbd, 0xc0, 0xea, 0xde, 0xa7, 0xae, 0x6a, 0x4b, 0xe5, 0x3d, 0xc3, 0xa4, 0x4a, 0x6d, 0x62, 0x2b, 0x91}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe7, 0x27, 0x96, 0x3b, 0x72, 0x81, 0x7d, 0xba, 0xa4, 0xfb, 0xf7, 0x4, 0xd, 0x6f, 0xc8, 0x30, 0xfe, 0x47, 0xe0, 0x9, 0xf, 0x43, 0x13, 0x6, 0x55, 0xfc, 0xee, 0x15, 0x69, 0x99, 0x53, 0x3f}}
return a, nil
}
var __000002_add_unread_to_user_messagesDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x44\x8e\x31\x4e\xc5\x30\x10\x44\x7b\x4e\x31\x25\x14\xfe\x07\xa0\xa6\xa1\x4a\x03\x07\xd8\xd8\x43\x62\xc9\xde\xb5\xec\xb5\x42\x6e\x8f\x2c\x21\x68\xdf\xee\xbc\x99\x10\xf0\xb1\xbd\x6d\xcf\x92\xa4\xbe\xbc\x22\x8a\xaa\x39\x52\xb7\x86\x68\x65\x56\xc5\x95\xfd\xb4\xe9\x88\xd6\xee\xac\x07\x04\x2e\x7b\xe1\xe3\x29\x04\xbc\xd7\x56\x58\xa9\xff\xd7\x3c\x40\x19\x37\xf6\xe9\xb8\x08\x25\x13\xdc\x90\x66\x2b\x39\x8a\x13\x23\x9e\xac\xb2\xc2\x6e\xe8\x8c\x9d\x8b\x66\x7f\xe0\x53\x0b\xc7\x80\x9f\xec\x5c\x1e\xc1\xa8\xd2\x9d\x1d\x97\xdc\xeb\xfb\xa0\x2f\xf8\x27\xb0\x2f\x88\x82\xdf\x79\xf8\xaa\xfe\x9d\xf5\x13\x00\x00\xff\xff\x1c\xd9\x39\x28\xd2\x00\x00\x00")
func _000002_add_unread_to_user_messagesDownSqlBytes() ([]byte, error) {
return bindataRead(
__000002_add_unread_to_user_messagesDownSql,
"000002_add_unread_to_user_messages.down.sql",
)
}
func _000002_add_unread_to_user_messagesDownSql() (*asset, error) {
bytes, err := _000002_add_unread_to_user_messagesDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "000002_add_unread_to_user_messages.down.sql", size: 210, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdc, 0x47, 0x8e, 0x4b, 0x54, 0x6a, 0xfc, 0x61, 0xa5, 0x37, 0xc6, 0xd6, 0xd3, 0x22, 0xcd, 0xbe, 0xb3, 0x60, 0xd8, 0xa0, 0xe2, 0x67, 0x27, 0x5, 0xf3, 0x6d, 0xca, 0x84, 0xd5, 0xfc, 0x94, 0x1a}}
return a, nil
}
var __000002_add_unread_to_user_messagesUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xcc\x41\xca\xc2\x30\x10\x40\xe1\x7d\x4f\xf1\x2e\x50\xfe\x7f\xef\x2a\x9a\x08\xc2\x98\x82\x4c\xd6\x12\x70\x2c\xc5\xaa\x90\x21\x9e\x5f\x84\xae\xde\xea\x7d\x41\x34\x5d\xd0\xb0\x97\x44\x77\x6b\xd7\xa7\xb9\xd7\xd9\x7c\x00\x08\x31\x72\x98\xa4\x9c\x33\xf7\xb5\xce\xce\x29\x2b\x79\x52\x72\x11\x21\xa6\x63\x28\xa2\xfc\xef\x18\x47\x3e\xb5\x2d\xef\xee\x6c\xc0\x36\xac\xcb\xc3\x68\x56\x6f\x7f\xfd\xf5\xcb\xf0\x0d\x00\x00\xff\xff\xbc\x55\xda\x47\x71\x00\x00\x00")
func _000002_add_unread_to_user_messagesUpSqlBytes() ([]byte, error) {
return bindataRead(
__000002_add_unread_to_user_messagesUpSql,
"000002_add_unread_to_user_messages.up.sql",
)
}
func _000002_add_unread_to_user_messagesUpSql() (*asset, error) {
bytes, err := _000002_add_unread_to_user_messagesUpSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "000002_add_unread_to_user_messages.up.sql", size: 113, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x8a, 0x92, 0x67, 0x90, 0x5, 0xb4, 0x82, 0x13, 0x78, 0x83, 0xae, 0x5e, 0x13, 0x67, 0x2f, 0xdd, 0xe1, 0xcb, 0x11, 0x70, 0xdb, 0x5, 0xb6, 0xb0, 0x1c, 0x29, 0x99, 0xae, 0x1a, 0x32, 0xb0, 0x41}}
return a, nil return a, nil
} }
@ -168,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 0)} info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}}
return a, nil return a, nil
} }
@ -264,13 +222,9 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name. // _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){ var _bindata = map[string]func() (*asset, error){
"000001_add_messages_contacts.down.db.sql": _000001_add_messages_contactsDownDbSql, "000001_init.down.db.sql": _000001_initDownDbSql,
"000001_add_messages_contacts.up.db.sql": _000001_add_messages_contactsUpDbSql, "000001_init.up.db.sql": _000001_initUpDbSql,
"000002_add_unread_to_user_messages.down.sql": _000002_add_unread_to_user_messagesDownSql,
"000002_add_unread_to_user_messages.up.sql": _000002_add_unread_to_user_messagesUpSql,
"doc.go": docGo, "doc.go": docGo,
} }
@ -316,10 +270,8 @@ type bintree struct {
} }
var _bintree = &bintree{nil, map[string]*bintree{ var _bintree = &bintree{nil, map[string]*bintree{
"000001_add_messages_contacts.down.db.sql": &bintree{_000001_add_messages_contactsDownDbSql, map[string]*bintree{}}, "000001_init.down.db.sql": &bintree{_000001_initDownDbSql, map[string]*bintree{}},
"000001_add_messages_contacts.up.db.sql": &bintree{_000001_add_messages_contactsUpDbSql, map[string]*bintree{}}, "000001_init.up.db.sql": &bintree{_000001_initUpDbSql, map[string]*bintree{}},
"000002_add_unread_to_user_messages.down.sql": &bintree{_000002_add_unread_to_user_messagesDownSql, map[string]*bintree{}},
"000002_add_unread_to_user_messages.up.sql": &bintree{_000002_add_unread_to_user_messagesUpSql, map[string]*bintree{}},
"doc.go": &bintree{docGo, map[string]*bintree{}}, "doc.go": &bintree{docGo, map[string]*bintree{}},
}} }}

View File

@ -3,6 +3,7 @@ package statusproto
import ( import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"fmt"
"path/filepath" "path/filepath"
"time" "time"
@ -11,6 +12,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
whisper "github.com/status-im/whisper/whisperv6" whisper "github.com/status-im/whisper/whisperv6"
"github.com/status-im/status-protocol-go/datasync"
datasyncpeer "github.com/status-im/status-protocol-go/datasync/peer"
"github.com/status-im/status-protocol-go/encryption" "github.com/status-im/status-protocol-go/encryption"
"github.com/status-im/status-protocol-go/encryption/multidevice" "github.com/status-im/status-protocol-go/encryption/multidevice"
"github.com/status-im/status-protocol-go/encryption/sharedsecret" "github.com/status-im/status-protocol-go/encryption/sharedsecret"
@ -19,12 +22,10 @@ import (
transport "github.com/status-im/status-protocol-go/transport/whisper" transport "github.com/status-im/status-protocol-go/transport/whisper"
"github.com/status-im/status-protocol-go/transport/whisper/filter" "github.com/status-im/status-protocol-go/transport/whisper/filter"
protocol "github.com/status-im/status-protocol-go/v1" protocol "github.com/status-im/status-protocol-go/v1"
) datasyncnode "github.com/vacp2p/mvds/node"
datasyncpeers "github.com/vacp2p/mvds/peers"
const ( datasyncstate "github.com/vacp2p/mvds/state"
// messagesDatabaseFileName is a name of the SQL file in which datasyncstore "github.com/vacp2p/mvds/store"
// messages are stored.
messagesDatabaseFileName = "messages.sql"
) )
var ( var (
@ -44,13 +45,11 @@ type Messenger struct {
persistence persistence persistence persistence
adapter *whisperAdapter adapter *whisperAdapter
encryptor *encryption.Protocol encryptor *encryption.Protocol
logger *zap.Logger
ownMessages map[string][]*protocol.Message ownMessages map[string][]*protocol.Message
featureFlags featureFlags featureFlags featureFlags
messagesPersistenceEnabled bool messagesPersistenceEnabled bool
logger *zap.Logger
shutdownTasks []func() error shutdownTasks []func() error
} }
@ -61,6 +60,9 @@ type featureFlags struct {
// V1 messages adds additional wrapping // V1 messages adds additional wrapping
// which contains a signature and payload. // which contains a signature and payload.
sendV1Messages bool sendV1Messages bool
// datasync indicates whether messages should be sent using datasync, breaking change for non-v1 clients
datasync bool
} }
type config struct { type config struct {
@ -132,6 +134,13 @@ func WithSendV1Messages() func(c *config) error {
} }
} }
func WithDatasync() func(c *config) error {
return func(c *config) error {
c.featureFlags.datasync = true
return nil
}
}
func NewMessenger( func NewMessenger(
identity *ecdsa.PrivateKey, identity *ecdsa.PrivateKey,
server transport.Server, server transport.Server,
@ -186,9 +195,11 @@ func NewMessenger(
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
_, err := messenger.adapter.SendContactCode(ctx, messageSpec) _, err := messenger.adapter.SendContactCode(ctx, messageSpec)
if err != nil {
slogger.Warn("failed to send a contact code", zap.Error(err)) slogger.Warn("failed to send a contact code", zap.Error(err))
} }
} }
}
// Set default database file paths. // Set default database file paths.
if c.encryptionLayerFilePath == "" { if c.encryptionLayerFilePath == "" {
@ -224,6 +235,8 @@ func NewMessenger(
return nil, errors.Wrap(err, "failed to create the encryption layer") return nil, errors.Wrap(err, "failed to create the encryption layer")
} }
messagesDatabaseFileName := fmt.Sprintf("%s.messages.sql", installationID)
applicationLayerFilePath := filepath.Join(dataDir, messagesDatabaseFileName) applicationLayerFilePath := filepath.Join(dataDir, messagesDatabaseFileName)
applicationLayerPersistence, err := sqlite.Open(applicationLayerFilePath, dbKey, sqlite.MigrationConfig{ applicationLayerPersistence, err := sqlite.Open(applicationLayerFilePath, dbKey, sqlite.MigrationConfig{
AssetNames: migrations.AssetNames(), AssetNames: migrations.AssetNames(),
@ -234,9 +247,22 @@ func NewMessenger(
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to initialize messages db") return nil, errors.Wrap(err, "failed to initialize messages db")
} }
dataSyncTransport := datasync.NewDataSyncNodeTransport()
dataSyncStore := datasyncstore.NewDummyStore()
dataSyncNode := datasyncnode.NewNode(
&dataSyncStore,
dataSyncTransport,
datasyncstate.NewSyncState(), // @todo sqlite syncstate
datasync.CalculateSendTime,
0,
datasyncpeer.PublicKeyToPeerID(identity.PublicKey),
datasyncnode.BATCH,
datasyncpeers.NewMemoryPersistence(),
)
datasync := datasync.New(dataSyncNode, dataSyncTransport, c.featureFlags.datasync, logger)
persistence := &sqlitePersistence{db: applicationLayerPersistence} persistence := &sqlitePersistence{db: applicationLayerPersistence}
adapter := newWhisperAdapter(identity, t, encryptionProtocol, c.featureFlags, logger) adapter := newWhisperAdapter(identity, t, encryptionProtocol, datasync, c.featureFlags, logger)
messenger = &Messenger{ messenger = &Messenger{
identity: identity, identity: identity,
persistence: persistence, persistence: persistence,
@ -248,6 +274,7 @@ func NewMessenger(
shutdownTasks: []func() error{ shutdownTasks: []func() error{
persistence.Close, persistence.Close,
adapter.transport.Reset, adapter.transport.Reset,
func() error { datasync.Stop(); return nil },
// Currently this often fails, seems like it's safe to ignore them // Currently this often fails, seems like it's safe to ignore them
// https://github.com/uber-go/zap/issues/328 // https://github.com/uber-go/zap/issues/328
func() error { _ = logger.Sync; return nil }, func() error { _ = logger.Sync; return nil },
@ -260,6 +287,9 @@ func NewMessenger(
if err := encryptionProtocol.Start(identity); err != nil { if err := encryptionProtocol.Start(identity); err != nil {
return nil, err return nil, err
} }
if c.featureFlags.datasync {
dataSyncNode.Start(300 * time.Millisecond)
}
logger.Debug("messages persistence", zap.Bool("enabled", c.messagesPersistenceEnabled)) logger.Debug("messages persistence", zap.Bool("enabled", c.messagesPersistenceEnabled))
@ -402,6 +432,47 @@ var (
RetrieveLastDay = RetrieveConfig{latest: true, last24Hours: true} RetrieveLastDay = RetrieveConfig{latest: true, last24Hours: true}
) )
// RetrieveAll retrieves all previously fetched messages
func (m *Messenger) RetrieveAll(ctx context.Context, c RetrieveConfig) (allMessages []*protocol.Message, err error) {
latest, err := m.adapter.RetrieveAllMessages()
if err != nil {
err = errors.Wrap(err, "failed to retrieve messages")
return
}
for _, messages := range latest {
chatID := messages.ChatID
_, err = m.persistence.SaveMessages(chatID, messages.Messages)
if err != nil {
return nil, errors.Wrap(err, "failed to save messages")
}
if !messages.Public {
// Return any own messages for this chat as well.
if ownMessages, ok := m.ownMessages[chatID]; ok {
messages.Messages = append(messages.Messages, ownMessages...)
}
}
retrievedMessages, err := m.retrieveSaved(ctx, chatID, c, messages.Messages)
if err != nil {
return nil, errors.Wrap(err, "failed to get saved messages")
}
allMessages = append(allMessages, retrievedMessages...)
}
// Delete own messages as they were added to the result.
for _, messages := range latest {
if !messages.Public {
delete(m.ownMessages, messages.ChatID)
}
}
return
}
func (m *Messenger) Retrieve(ctx context.Context, chat Chat, c RetrieveConfig) (messages []*protocol.Message, err error) { func (m *Messenger) Retrieve(ctx context.Context, chat Chat, c RetrieveConfig) (messages []*protocol.Message, err error) {
var ( var (
latest []*protocol.Message latest []*protocol.Message
@ -442,40 +513,41 @@ func (m *Messenger) Retrieve(ctx context.Context, chat Chat, c RetrieveConfig) (
} }
} }
// We may need to add more messages from the past.
result, err := m.retrieveSaved(ctx, chat.ID(), c, append(latest, ownLatest...))
if err != nil {
return nil, err
}
// When our messages are returned, we can delete them. // When our messages are returned, we can delete them.
delete(m.ownMessages, chat.ID()) delete(m.ownMessages, chat.ID())
return m.retrieveSaved(ctx, chat, c, append(latest, ownLatest...)) return result, nil
} }
func (m *Messenger) retrieveSaved(ctx context.Context, chat Chat, c RetrieveConfig, latest []*protocol.Message) (messages []*protocol.Message, err error) { func (m *Messenger) retrieveSaved(ctx context.Context, chatID string, c RetrieveConfig, latest []*protocol.Message) (messages []*protocol.Message, err error) {
if !m.messagesPersistenceEnabled { if !m.messagesPersistenceEnabled {
return latest, nil return latest, nil
} }
if !c.latest { if !c.latest {
return m.persistence.Messages(chat.ID(), c.From, c.To) return m.persistence.Messages(chatID, c.From, c.To)
} }
if c.last24Hours { if c.last24Hours {
to := time.Now() to := time.Now()
from := to.Add(-time.Hour * 24) from := to.Add(-time.Hour * 24)
return m.persistence.Messages(chat.ID(), from, to) return m.persistence.Messages(chatID, from, to)
} }
return latest, nil return latest, nil
} }
// DEPRECATED // DEPRECATED
func (m *Messenger) RetrieveRawAll() (map[filter.Chat][]*whisper.Message, error) { func (m *Messenger) RetrieveRawAll() (map[filter.Chat][]*protocol.StatusMessage, error) {
return m.adapter.RetrieveRawAll() return m.adapter.RetrieveRawAll()
} }
// DEPRECATED
func (m *Messenger) RetrieveRawWithFilter(filterID string) ([]*whisper.Message, error) {
return m.adapter.RetrieveRaw(filterID)
}
// DEPRECATED // DEPRECATED
func (m *Messenger) LoadFilters(chats []*filter.Chat) ([]*filter.Chat, error) { func (m *Messenger) LoadFilters(chats []*filter.Chat) ([]*filter.Chat, error) {
return m.adapter.transport.LoadFilters(chats, m.featureFlags.genericDiscoveryTopicEnabled) return m.adapter.transport.LoadFilters(chats, m.featureFlags.genericDiscoveryTopicEnabled)

View File

@ -47,7 +47,7 @@ func (db sqlitePersistence) LastMessageClock(chatID string) (int64, error) {
} }
var last sql.NullInt64 var last sql.NullInt64
err := db.db.QueryRow("SELECT max(clock) FROM user_messages WHERE contact_id = ?", chatID).Scan(&last) err := db.db.QueryRow("SELECT max(clock) FROM user_messages WHERE chat_id = ?", chatID).Scan(&last)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -64,7 +64,7 @@ func (db sqlitePersistence) SaveMessages(chatID string, messages []*protocol.Mes
return return
} }
stmt, err = tx.Prepare(`INSERT INTO user_messages( stmt, err = tx.Prepare(`INSERT INTO user_messages(
id, contact_id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags) id, chat_id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
if err != nil { if err != nil {
return return
@ -111,7 +111,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
func (db sqlitePersistence) Messages(chatID string, from, to time.Time) (result []*protocol.Message, err error) { func (db sqlitePersistence) Messages(chatID string, from, to time.Time) (result []*protocol.Message, err error) {
rows, err := db.db.Query(`SELECT rows, err := db.db.Query(`SELECT
id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags
FROM user_messages WHERE contact_id = ? AND timestamp >= ? AND timestamp <= ? ORDER BY timestamp`, FROM user_messages WHERE chat_id = ? AND timestamp >= ? AND timestamp <= ? ORDER BY timestamp`,
chatID, protocol.TimestampInMsFromTime(from), protocol.TimestampInMsFromTime(to)) chatID, protocol.TimestampInMsFromTime(from), protocol.TimestampInMsFromTime(to))
if err != nil { if err != nil {
return nil, err return nil, err
@ -144,7 +144,7 @@ FROM user_messages WHERE contact_id = ? AND timestamp >= ? AND timestamp <= ? OR
func (db sqlitePersistence) NewMessages(chatID string, rowid int64) ([]*protocol.Message, error) { func (db sqlitePersistence) NewMessages(chatID string, rowid int64) ([]*protocol.Message, error) {
rows, err := db.db.Query(`SELECT rows, err := db.db.Query(`SELECT
id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags id, content_type, message_type, text, clock, timestamp, content_chat_id, content_text, public_key, flags
FROM user_messages WHERE contact_id = ? AND rowid >= ? ORDER BY clock`, FROM user_messages WHERE chat_id = ? AND rowid >= ? ORDER BY clock`,
chatID, rowid) chatID, rowid)
if err != nil { if err != nil {
return nil, err return nil, err
@ -192,7 +192,7 @@ func (db sqlitePersistence) UnreadMessages(chatID string) ([]*protocol.Message,
FROM FROM
user_messages user_messages
WHERE WHERE
contact_id = ? AND chat_id = ? AND
flags & ? == 0 flags & ? == 0
ORDER BY clock`, ORDER BY clock`,
chatID, protocol.MessageRead, chatID, protocol.MessageRead,

View File

@ -58,6 +58,10 @@ type Chat struct {
Listen bool `json:"listen"` Listen bool `json:"listen"`
} }
func (c *Chat) IsPublic() bool {
return !c.OneToOne
}
type ChatsManager struct { type ChatsManager struct {
whisper *whisper.Whisper whisper *whisper.Whisper
persistence *sqlitePersistence persistence *sqlitePersistence
@ -278,6 +282,7 @@ func (s *ChatsManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool)
Topic: filter.Topic, Topic: filter.Topic,
Identity: publicKeyToStr(publicKey), Identity: publicKeyToStr(publicKey),
Listen: listen, Listen: listen,
OneToOne: true,
} }
s.chats[chatID] = chat s.chats[chatID] = chat
@ -310,6 +315,7 @@ func (s *ChatsManager) LoadNegotiated(secret NegotiatedSecret) (*Chat, error) {
Identity: publicKeyToStr(secret.PublicKey), Identity: publicKeyToStr(secret.PublicKey),
Negotiated: true, Negotiated: true,
Listen: true, Listen: true,
OneToOne: true,
} }
s.chats[chat.ChatID] = chat s.chats[chat.ChatID] = chat
@ -354,6 +360,7 @@ func (s *ChatsManager) LoadDiscovery() ([]*Chat, error) {
Identity: identityStr, Identity: identityStr,
Discovery: true, Discovery: true,
Listen: true, Listen: true,
OneToOne: true,
} }
discoveryResponse, err = s.addAsymmetric(personalDiscoveryChat.ChatID, true) discoveryResponse, err = s.addAsymmetric(personalDiscoveryChat.ChatID, true)
@ -373,6 +380,7 @@ func (s *ChatsManager) LoadDiscovery() ([]*Chat, error) {
Identity: identityStr, Identity: identityStr,
Discovery: true, Discovery: true,
Listen: true, Listen: true,
OneToOne: true,
} }
discoveryResponse, err = s.addAsymmetric(discoveryChat.ChatID, true) discoveryResponse, err = s.addAsymmetric(discoveryChat.ChatID, true)
@ -411,6 +419,7 @@ func (s *ChatsManager) LoadPublic(chatID string) (*Chat, error) {
SymKeyID: filterAndTopic.SymKeyID, SymKeyID: filterAndTopic.SymKeyID,
Topic: filterAndTopic.Topic, Topic: filterAndTopic.Topic,
Listen: true, Listen: true,
OneToOne: false,
} }
s.chats[chatID] = chat s.chats[chatID] = chat

View File

@ -86,7 +86,7 @@ func _1561059285_add_whisper_keysDownSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1562956766, 0)} info := bindataFileInfo{name: "1561059285_add_whisper_keys.down.sql", size: 25, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0x31, 0x3f, 0xce, 0xfa, 0x44, 0x36, 0x1b, 0xb0, 0xec, 0x5d, 0xb, 0x90, 0xb, 0x21, 0x4f, 0xd5, 0xe5, 0x50, 0xed, 0xc7, 0x43, 0xdf, 0x83, 0xb4, 0x3a, 0xc1, 0x55, 0x2e, 0x53, 0x7c, 0x67}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb9, 0x31, 0x3f, 0xce, 0xfa, 0x44, 0x36, 0x1b, 0xb0, 0xec, 0x5d, 0xb, 0x90, 0xb, 0x21, 0x4f, 0xd5, 0xe5, 0x50, 0xed, 0xc7, 0x43, 0xdf, 0x83, 0xb4, 0x3a, 0xc1, 0x55, 0x2e, 0x53, 0x7c, 0x67}}
return a, nil return a, nil
} }
@ -106,7 +106,7 @@ func _1561059285_add_whisper_keysUpSql() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1562956695, 0)} info := bindataFileInfo{name: "1561059285_add_whisper_keys.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x41, 0xc, 0x92, 0xdd, 0x9e, 0xff, 0x5d, 0xd0, 0x93, 0xe4, 0x24, 0x50, 0x29, 0xcf, 0xc6, 0xf7, 0x49, 0x3c, 0x73, 0xd9, 0x8c, 0xfa, 0xf2, 0xcf, 0xf6, 0x6f, 0xbc, 0x31, 0xe6, 0xf7, 0xe2}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x25, 0x41, 0xc, 0x92, 0xdd, 0x9e, 0xff, 0x5d, 0xd0, 0x93, 0xe4, 0x24, 0x50, 0x29, 0xcf, 0xc6, 0xf7, 0x49, 0x3c, 0x73, 0xd9, 0x8c, 0xfa, 0xf2, 0xcf, 0xf6, 0x6f, 0xbc, 0x31, 0xe6, 0xf7, 0xe2}}
return a, nil return a, nil
} }
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
return nil, err return nil, err
} }
info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1562956695, 0)} info := bindataFileInfo{name: "doc.go", size: 377, mode: os.FileMode(0644), modTime: time.Unix(1564410717, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x94, 0xd1, 0x5c, 0x73, 0x47, 0x65, 0xf9, 0x6e, 0xa0, 0xee, 0xb, 0x3d, 0xbe, 0xff, 0xef, 0xae, 0xc9, 0x46, 0x21, 0x85, 0x12, 0x46, 0xa1, 0x73, 0x74, 0xca, 0x71, 0xb1, 0xe1, 0x69, 0xe1, 0x82}}
return a, nil return a, nil
} }

View File

@ -167,6 +167,34 @@ func (a *WhisperServiceTransport) LeavePrivate(publicKey *ecdsa.PublicKey) error
return a.chats.Remove(chats...) return a.chats.Remove(chats...)
} }
type ChatMessages struct {
Messages []*whisper.ReceivedMessage
Public bool
ChatID string
}
func (a *WhisperServiceTransport) RetrieveAllMessages() ([]ChatMessages, error) {
chatMessages := make(map[string]ChatMessages)
for _, chat := range a.chats.Chats() {
f := a.shh.GetFilter(chat.FilterID)
if f == nil {
return nil, errors.New("failed to return a filter")
}
messages := chatMessages[chat.ChatID]
messages.ChatID = chat.ChatID
messages.Public = chat.IsPublic()
messages.Messages = append(messages.Messages, f.Retrieve()...)
}
var result []ChatMessages
for _, messages := range chatMessages {
result = append(result, messages)
}
return result, nil
}
func (a *WhisperServiceTransport) RetrievePublicMessages(chatID string) ([]*whisper.ReceivedMessage, error) { func (a *WhisperServiceTransport) RetrievePublicMessages(chatID string) ([]*whisper.ReceivedMessage, error) {
chat, err := a.chats.LoadPublic(chatID) chat, err := a.chats.LoadPublic(chatID)
if err != nil { if err != nil {
@ -183,7 +211,7 @@ func (a *WhisperServiceTransport) RetrievePublicMessages(chatID string) ([]*whis
func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*whisper.ReceivedMessage, error) { func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*whisper.ReceivedMessage, error) {
chats := a.chats.ChatsByPublicKey(publicKey) chats := a.chats.ChatsByPublicKey(publicKey)
discoveryChats, err := a.chats.LoadDiscovery() discoveryChats, err := a.chats.Init(nil, nil, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,6 +223,7 @@ func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.Publi
if f == nil { if f == nil {
return nil, errors.New("failed to return a filter") return nil, errors.New("failed to return a filter")
} }
result = append(result, f.Retrieve()...) result = append(result, f.Retrieve()...)
} }
@ -211,6 +240,7 @@ func (a *WhisperServiceTransport) RetrieveRawAll() (map[filter.Chat][]*whisper.R
if f == nil { if f == nil {
return nil, errors.New("failed to return a filter") return nil, errors.New("failed to return a filter")
} }
result[*chat] = append(result[*chat], f.Retrieve()...) result[*chat] = append(result[*chat], f.Retrieve()...)
} }

View File

@ -0,0 +1,3 @@
# v1 statusproto package folder
This folder contains only data types mentioned in the specification and required for its implementation.

View File

@ -5,16 +5,14 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "github.com/pkg/errors"
"time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"log"
"strings" "strings"
"time"
) )
//go:generate protoc --go_out=. ./message.proto
const ( const (
// ContentTypeTextPlain means that the message contains plain text. // ContentTypeTextPlain means that the message contains plain text.
ContentTypeTextPlain = "text/plain" ContentTypeTextPlain = "text/plain"
@ -67,26 +65,6 @@ const (
MessageRead Flags = 1 << iota MessageRead Flags = 1 << iota
) )
// StatusMessage is any Status Protocol message.
type StatusMessage struct {
Message interface{}
ID []byte `json:"-"`
SigPubKey *ecdsa.PublicKey `json:"-"`
}
func (m *StatusMessage) MarshalJSON() ([]byte, error) {
type MessageAlias StatusMessage
item := struct {
*MessageAlias
ID string `json:"id"`
}{
MessageAlias: (*MessageAlias)(m),
ID: "0x" + hex.EncodeToString(m.ID),
}
return json.Marshal(item)
}
// Message is a chat message sent by an user. // Message is a chat message sent by an user.
type Message struct { type Message struct {
Text string `json:"text"` // TODO: why is this duplicated? Text string `json:"text"` // TODO: why is this duplicated?
@ -99,6 +77,8 @@ type Message struct {
Flags Flags `json:"-"` Flags Flags `json:"-"`
ID []byte `json:"-"` ID []byte `json:"-"`
SigPubKey *ecdsa.PublicKey `json:"-"` SigPubKey *ecdsa.PublicKey `json:"-"`
ChatID string `json:"-"`
Public bool `json:"-"`
} }
func (m *Message) MarshalJSON() ([]byte, error) { func (m *Message) MarshalJSON() ([]byte, error) {
@ -114,10 +94,6 @@ func (m *Message) MarshalJSON() ([]byte, error) {
return json.Marshal(item) return json.Marshal(item)
} }
func (m Message) Unread() bool {
return !m.Flags.Has(MessageRead)
}
// createTextMessage creates a Message. // createTextMessage creates a Message.
func createTextMessage(data []byte, lastClock int64, chatID, messageType string) Message { func createTextMessage(data []byte, lastClock int64, chatID, messageType string) Message {
text := strings.TrimSpace(string(data)) text := strings.TrimSpace(string(data))
@ -144,17 +120,12 @@ func CreatePrivateTextMessage(data []byte, lastClock int64, chatID string) Messa
return createTextMessage(data, lastClock, chatID, MessageTypePrivate) return createTextMessage(data, lastClock, chatID, MessageTypePrivate)
} }
func unwrapMessage(data []byte) (*StatusProtocolMessage, error) { func decodeTransitMessage(originalPayload []byte) (interface{}, error) {
var message StatusProtocolMessage payload := make([]byte, len(originalPayload))
err := proto.Unmarshal(data, &message) copy(payload, originalPayload)
if err != nil { // This modifies the payload
return nil, err buf := bytes.NewBuffer(payload)
}
return &message, nil
}
func decodeTransitMessage(data []byte) (interface{}, error) {
buf := bytes.NewBuffer(data)
decoder := NewMessageDecoder(buf) decoder := NewMessageDecoder(buf)
value, err := decoder.Decode() value, err := decoder.Decode()
if err != nil { if err != nil {
@ -163,42 +134,6 @@ func decodeTransitMessage(data []byte) (interface{}, error) {
return value, nil return value, nil
} }
// DecodeMessage decodes a raw payload to StatusMessage struct.
func DecodeMessage(transportPublicKey *ecdsa.PublicKey, data []byte) (message StatusMessage, err error) {
transitMessage := data
// Getting a signature from transport message should happen only if
// the signature was not defined in the payload itself.
message.SigPubKey = transportPublicKey
statusProtocolMessage, err := unwrapMessage(data)
if err == nil {
// Wrapped message, extract transit and signature
transitMessage = statusProtocolMessage.Payload
if statusProtocolMessage.Signature != nil {
recoveredKey, err := crypto.SigToPub(
crypto.Keccak256(transitMessage),
statusProtocolMessage.Signature,
)
if err != nil {
return message, err
}
message.SigPubKey = recoveredKey
}
}
message.ID = MessageID(message.SigPubKey, transitMessage)
value, err := decodeTransitMessage(transitMessage)
if err != nil {
log.Printf("[message::DecodeMessage] could not decode message: %#x", message.ID)
return message, err
}
message.Message = value
return message, nil
}
// EncodeMessage encodes a Message using Transit serialization. // EncodeMessage encodes a Message using Transit serialization.
func EncodeMessage(value Message) ([]byte, error) { func EncodeMessage(value Message) ([]byte, error) {
var buf bytes.Buffer var buf bytes.Buffer

View File

@ -21,8 +21,8 @@ var _ = math.Inf
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type StatusProtocolMessage struct { type StatusProtocolMessage struct {
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` Signature []byte `protobuf:"bytes,4001,opt,name=signature,proto3" json:"signature,omitempty"`
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` Payload []byte `protobuf:"bytes,4002,opt,name=payload,proto3" json:"payload,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -74,12 +74,12 @@ func init() {
func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) } func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) }
var fileDescriptor_33c57e4bae7b9afd = []byte{ var fileDescriptor_33c57e4bae7b9afd = []byte{
// 108 bytes of a gzipped FileDescriptorProto // 109 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x4d, 0x2d, 0x2e, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcd, 0x4d, 0x2d, 0x2e,
0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2e, 0x2e, 0x49, 0x2c, 0x29, 0x4e, 0x4c, 0x4f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2e, 0x2e, 0x49, 0x2c, 0x29,
0x2d, 0x06, 0x73, 0x94, 0xfc, 0xb9, 0x44, 0x83, 0xc1, 0xdc, 0x00, 0x10, 0x37, 0x39, 0x3f, 0xc7, 0x2d, 0x06, 0x73, 0x94, 0x02, 0xb9, 0x44, 0x83, 0xc1, 0xdc, 0x00, 0x10, 0x37, 0x39, 0x3f, 0xc7,
0x17, 0xa2, 0x56, 0x48, 0x86, 0x8b, 0xb3, 0x38, 0x33, 0x3d, 0x2f, 0xb1, 0xa4, 0xb4, 0x28, 0x55, 0x17, 0xa2, 0x56, 0x48, 0x96, 0x8b, 0xb3, 0x38, 0x33, 0x3d, 0x2f, 0xb1, 0xa4, 0xb4, 0x28, 0x55,
0x82, 0x51, 0x81, 0x51, 0x83, 0x27, 0x08, 0x21, 0x20, 0x24, 0xc1, 0xc5, 0x5e, 0x90, 0x58, 0x99, 0x62, 0xa1, 0xbc, 0x02, 0xa3, 0x06, 0x4f, 0x10, 0x42, 0x44, 0x48, 0x92, 0x8b, 0xbd, 0x20, 0xb1,
0x93, 0x9f, 0x98, 0x22, 0xc1, 0x04, 0x96, 0x83, 0x71, 0x93, 0xd8, 0xc0, 0xe6, 0x1a, 0x03, 0x02, 0x32, 0x27, 0x3f, 0x31, 0x45, 0x62, 0x11, 0x44, 0x12, 0xc6, 0x4f, 0x62, 0x03, 0x9b, 0x6c, 0x0c,
0x00, 0x00, 0xff, 0xff, 0xda, 0x9a, 0x88, 0x4b, 0x75, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xff, 0xff, 0x92, 0x1a, 0x92, 0xf0, 0x77, 0x00, 0x00, 0x00,
} }

View File

@ -1,8 +0,0 @@
syntax = "proto3";
package statusproto;
message StatusProtocolMessage {
bytes signature = 1;
bytes payload = 2;
}

View File

@ -0,0 +1,142 @@
package statusproto
import (
"crypto/ecdsa"
"github.com/pkg/errors"
"log"
"github.com/ethereum/go-ethereum/crypto"
"github.com/golang/protobuf/proto"
"github.com/jinzhu/copier"
"github.com/status-im/status-protocol-go/applicationmetadata"
"github.com/status-im/status-protocol-go/datasync"
"github.com/status-im/status-protocol-go/encryption"
whisper "github.com/status-im/whisper/whisperv6"
)
// StatusMessage is any Status Protocol message.
type StatusMessage struct {
// TransportMessage is the parsed message received from the trasport layer, i.e the input
TransportMessage *whisper.Message
// ParsedMessage is the parsed message by the application layer, i.e the output
ParsedMessage interface{}
// TransportPayload is the payload as received from the transport layer
TransportPayload []byte
// DecryptedPayload is the payload after having been processed by the encryption layer
DecryptedPayload []byte
// ID is the canonical ID of the message
ID []byte
// Hash is the transport layer hash
Hash []byte
// TransportLayerSigPubKey contains the public key provided by the transport layer
TransportLayerSigPubKey *ecdsa.PublicKey
// ApplicationMetadataLayerPubKey contains the public key provided by the application metadata layer
ApplicationMetadataLayerSigPubKey *ecdsa.PublicKey
}
// SigPubKey returns the most important signature, from the application layer to transport
func (s *StatusMessage) SigPubKey() *ecdsa.PublicKey {
if s.ApplicationMetadataLayerSigPubKey != nil {
return s.ApplicationMetadataLayerSigPubKey
}
return s.TransportLayerSigPubKey
}
func (s *StatusMessage) Clone() (*StatusMessage, error) {
copy := &StatusMessage{}
err := copier.Copy(&copy, s)
return copy, err
}
func (m *StatusMessage) HandleTransport(shhMessage *whisper.Message) error {
publicKey, err := crypto.UnmarshalPubkey(shhMessage.Sig)
if err != nil {
return errors.Wrap(err, "failed to get signature")
}
m.TransportMessage = shhMessage
m.Hash = shhMessage.Hash
m.TransportLayerSigPubKey = publicKey
m.TransportPayload = shhMessage.Payload
return nil
}
func (m *StatusMessage) HandleEncryption(myKey *ecdsa.PrivateKey, senderKey *ecdsa.PublicKey, enc *encryption.Protocol) error {
// As we handle non-encrypted messages, we make sure that DecryptPayload
// is set regardless of whether this step is successful
m.DecryptedPayload = m.TransportPayload
var protocolMessage encryption.ProtocolMessage
err := proto.Unmarshal(m.TransportPayload, &protocolMessage)
if err != nil {
return errors.Wrap(err, "failed to unmarshal ProtocolMessage")
}
payload, err := enc.HandleMessage(
myKey,
senderKey,
&protocolMessage,
m.Hash,
)
if err != nil {
return errors.Wrap(err, "failed to handle Encryption message")
}
m.DecryptedPayload = payload
return nil
}
func (m *StatusMessage) HandleDatasync(datasync *datasync.DataSync) ([]*StatusMessage, error) {
var statusMessages []*StatusMessage
payloads := datasync.Handle(
m.SigPubKey(),
m.DecryptedPayload,
)
for _, payload := range payloads {
message, err := m.Clone()
if err != nil {
return nil, err
}
message.DecryptedPayload = payload
statusMessages = append(statusMessages, message)
}
return statusMessages, nil
}
func (m *StatusMessage) HandleApplicationMetadata() error {
message, err := applicationmetadata.Unmarshal(m.DecryptedPayload)
// Not an applicationmetadata message, calculate ID using the previous
// signature
if err != nil {
m.ID = MessageID(m.SigPubKey(), m.DecryptedPayload)
return nil
}
recoveredKey, err := message.RecoverKey()
if err != nil {
return err
}
m.ApplicationMetadataLayerSigPubKey = recoveredKey
m.DecryptedPayload = message.Payload
m.ID = MessageID(m.SigPubKey(), m.DecryptedPayload)
return nil
}
func (m *StatusMessage) HandleApplication() error {
value, err := decodeTransitMessage(m.DecryptedPayload)
if err != nil {
log.Printf("[message::DecodeMessage] could not decode message: %#x", m.Hash)
return err
}
m.ParsedMessage = value
return nil
}

21
vendor/github.com/vacp2p/mvds/LICENSE generated vendored Normal file
View File

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

404
vendor/github.com/vacp2p/mvds/node/node.go generated vendored Normal file
View File

@ -0,0 +1,404 @@
// Package Node contains node logic.
package node
// @todo this is a very rough implementation that needs cleanup
import (
"context"
"fmt"
"log"
"sync/atomic"
"time"
"github.com/vacp2p/mvds/peers"
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
"github.com/vacp2p/mvds/store"
"github.com/vacp2p/mvds/transport"
)
// Mode represents the synchronization mode.
type Mode int
const (
INTERACTIVE Mode = iota
BATCH
)
// CalculateNextEpoch is a function used to calculate the next `SendEpoch` for a given message.
type CalculateNextEpoch func(count uint64, epoch int64) int64
// Node represents an MVDS node, it runs all the logic like sending and receiving protocol messages.
type Node struct {
ctx context.Context
cancel context.CancelFunc
store store.MessageStore
transport transport.Transport
syncState state.SyncState
peers peers.Persistence
payloads payloads
nextEpoch CalculateNextEpoch
ID state.PeerID
epoch int64
mode Mode
}
// NewNode returns a new node.
func NewNode(
ms store.MessageStore,
st transport.Transport,
ss state.SyncState,
nextEpoch CalculateNextEpoch,
currentEpoch int64,
id state.PeerID,
mode Mode,
pp peers.Persistence,
) *Node {
ctx, cancel := context.WithCancel(context.Background())
return &Node{
ctx: ctx,
cancel: cancel,
store: ms,
transport: st,
syncState: ss,
peers: pp,
payloads: newPayloads(),
nextEpoch: nextEpoch,
ID: id,
epoch: currentEpoch,
mode: mode,
}
}
// Start listens for new messages received by the node and sends out those required every epoch.
func (n *Node) Start(duration time.Duration) {
go func() {
for {
select {
case <-n.ctx.Done():
log.Print("Watch stopped")
return
default:
p := n.transport.Watch()
go n.onPayload(p.Sender, p.Payload)
}
}
}()
go func() {
for {
select {
case <-n.ctx.Done():
log.Print("Epoch processing stopped")
return
default:
log.Printf("Node: %x Epoch: %d", n.ID[:4], n.epoch)
time.Sleep(duration)
err := n.sendMessages()
if err != nil {
log.Printf("Error sending messages: %+v\n", err)
}
atomic.AddInt64(&n.epoch, 1)
}
}
}()
}
// Stop message reading and epoch processing
func (n *Node) Stop() {
log.Print("Stopping node")
n.cancel()
}
// AppendMessage sends a message to a given group.
func (n *Node) AppendMessage(groupID state.GroupID, data []byte) (state.MessageID, error) {
m := protobuf.Message{
GroupId: groupID[:],
Timestamp: time.Now().Unix(),
Body: data,
}
id := m.ID()
peers, err := n.peers.GetByGroupID(groupID)
if err != nil {
return state.MessageID{}, fmt.Errorf("trying to send to unknown group %x", groupID[:4])
}
err = n.store.Add(&m)
if err != nil {
return state.MessageID{}, err
}
for _, p := range peers {
t := state.OFFER
if n.mode == BATCH {
t = state.MESSAGE
}
n.insertSyncState(&groupID, id, p, t)
}
log.Printf("[%x] node %x sending %x\n", groupID[:4], n.ID[:4], id[:4])
// @todo think about a way to insta trigger send messages when send was selected, we don't wanna wait for ticks here
return id, nil
}
// RequestMessage adds a REQUEST record to the next payload for a given message ID.
func (n *Node) RequestMessage(group state.GroupID, id state.MessageID) error {
peers, err := n.peers.GetByGroupID(group)
if err != nil {
return fmt.Errorf("trying to request from an unknown group %x", group[:4])
}
for _, p := range peers {
exist, err := n.IsPeerInGroup(group, p)
if err != nil {
return err
}
if exist {
continue
}
n.insertSyncState(&group, id, p, state.REQUEST)
}
return nil
}
// AddPeer adds a peer to a specific group making it a recipient of messages.
func (n *Node) AddPeer(group state.GroupID, id state.PeerID) error {
return n.peers.Add(group, id)
}
// IsPeerInGroup checks whether a peer is in the specified group.
func (n *Node) IsPeerInGroup(g state.GroupID, p state.PeerID) (bool, error) {
return n.peers.Exists(g, p)
}
func (n *Node) sendMessages() error {
err := n.syncState.Map(n.epoch, func(s state.State) state.State {
m := s.MessageID
p := s.PeerID
switch s.Type {
case state.OFFER:
n.payloads.AddOffers(p, m[:])
case state.REQUEST:
n.payloads.AddRequests(p, m[:])
log.Printf("sending REQUEST (%x -> %x): %x\n", n.ID[:4], p[:4], m[:4])
case state.MESSAGE:
g := *s.GroupID
// TODO: Handle errors
exist, err := n.IsPeerInGroup(g, p)
if err != nil {
return s
}
if !exist {
return s
}
msg, err := n.store.Get(m)
if err != nil {
log.Printf("failed to retreive message %x %s", m[:4], err.Error())
return s
}
n.payloads.AddMessages(p, msg)
log.Printf("[%x] sending MESSAGE (%x -> %x): %x\n", g[:4], n.ID[:4], p[:4], m[:4])
}
return n.updateSendEpoch(s)
})
if err != nil {
log.Printf("error while mapping sync state: %s", err.Error())
return err
}
return n.payloads.MapAndClear(func(peer state.PeerID, payload protobuf.Payload) error {
err := n.transport.Send(n.ID, peer, payload)
if err != nil {
log.Printf("error sending message: %s", err.Error())
return err
}
return nil
})
}
func (n *Node) onPayload(sender state.PeerID, payload protobuf.Payload) {
// Acks, Requests and Offers are all arrays of bytes as protobuf doesn't allow type aliases otherwise arrays of messageIDs would be nicer.
if err := n.onAck(sender, payload.Acks); err != nil {
log.Printf("error processing acks: %s", err.Error())
}
if err := n.onRequest(sender, payload.Requests); err != nil {
log.Printf("error processing requests: %s", err.Error())
}
if err := n.onOffer(sender, payload.Offers); err != nil {
log.Printf("error processing offers: %s", err.Error())
}
messageIds := n.onMessages(sender, payload.Messages)
n.payloads.AddAcks(sender, messageIds)
}
func (n *Node) onOffer(sender state.PeerID, offers [][]byte) error {
for _, raw := range offers {
id := toMessageID(raw)
log.Printf("OFFER (%x -> %x): %x received.\n", sender[:4], n.ID[:4], id[:4])
exist, err := n.store.Has(id)
// @todo maybe ack?
if err != nil {
return err
}
if exist {
continue
}
n.insertSyncState(nil, id, sender, state.REQUEST)
}
return nil
}
func (n *Node) onRequest(sender state.PeerID, requests [][]byte) error {
for _, raw := range requests {
id := toMessageID(raw)
log.Printf("REQUEST (%x -> %x): %x received.\n", sender[:4], n.ID[:4], id[:4])
message, err := n.store.Get(id)
if err != nil {
return err
}
if message == nil {
log.Printf("message %x does not exist", id[:4])
continue
}
groupID := toGroupID(message.GroupId)
exist, err := n.IsPeerInGroup(groupID, sender)
if err != nil {
return err
}
if !exist {
log.Printf("[%x] peer %x is not in group", groupID, sender[:4])
continue
}
n.insertSyncState(&groupID, id, sender, state.MESSAGE)
}
return nil
}
func (n *Node) onAck(sender state.PeerID, acks [][]byte) error {
for _, ack := range acks {
id := toMessageID(ack)
err := n.syncState.Remove(id, sender)
if err != nil {
log.Printf("error while removing sync state %s", err.Error())
return err
}
log.Printf("ACK (%x -> %x): %x received.\n", sender[:4], n.ID[:4], id[:4])
}
return nil
}
func (n *Node) onMessages(sender state.PeerID, messages []*protobuf.Message) [][]byte {
a := make([][]byte, 0)
for _, m := range messages {
groupID := toGroupID(m.GroupId)
err := n.onMessage(sender, *m)
if err != nil {
log.Printf("Error processing messsage: %+v\n", err)
continue
}
id := m.ID()
log.Printf("[%x] sending ACK (%x -> %x): %x\n", groupID[:4], n.ID[:4], sender[:4], id[:4])
a = append(a, id[:])
}
return a
}
func (n *Node) onMessage(sender state.PeerID, msg protobuf.Message) error {
id := msg.ID()
groupID := toGroupID(msg.GroupId)
log.Printf("MESSAGE (%x -> %x): %x received.\n", sender[:4], n.ID[:4], id[:4])
err := n.syncState.Remove(id, sender)
if err != nil {
return err
}
err = n.store.Add(&msg)
if err != nil {
return err
// @todo process, should this function ever even have an error?
}
peers, err := n.peers.GetByGroupID(groupID)
if err != nil {
return err
}
for _, peer := range peers {
if peer == sender {
continue
}
n.insertSyncState(&groupID, id, peer, state.OFFER)
}
return nil
}
func (n *Node) insertSyncState(groupID *state.GroupID, messageID state.MessageID, peerID state.PeerID, t state.RecordType) {
s := state.State{
GroupID: groupID,
MessageID: messageID,
PeerID: peerID,
Type: t,
SendEpoch: n.epoch + 1,
}
err := n.syncState.Add(s)
if err != nil {
log.Printf("error (%s) setting sync state group: %x id: %x peer: %x", err.Error(), groupID, messageID, peerID)
}
}
func (n *Node) updateSendEpoch(s state.State) state.State {
s.SendCount += 1
s.SendEpoch += n.nextEpoch(s.SendCount, n.epoch)
return s
}
func toMessageID(b []byte) state.MessageID {
var id state.MessageID
copy(id[:], b)
return id
}
func toGroupID(b []byte) state.GroupID {
var id state.GroupID
copy(id[:], b)
return id
}

93
vendor/github.com/vacp2p/mvds/node/payloads.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
package node
import (
"sync"
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
)
type payloads struct {
sync.Mutex
payloads map[state.PeerID]protobuf.Payload
}
// @todo check in all the functions below that we aren't duplicating stuff
func newPayloads() payloads {
return payloads{
payloads: make(map[state.PeerID]protobuf.Payload),
}
}
func (p *payloads) AddOffers(peer state.PeerID, offers ...[]byte) {
p.Lock()
defer p.Unlock()
payload := p.get(peer)
payload.Offers = append(payload.Offers, offers...)
p.set(peer, payload)
}
func (p *payloads) AddAcks(peer state.PeerID, acks [][]byte) {
p.Lock()
defer p.Unlock()
payload := p.get(peer)
payload.Acks = append(payload.Acks, acks...)
p.set(peer, payload)
}
func (p *payloads) AddRequests(peer state.PeerID, request ...[]byte) {
p.Lock()
defer p.Unlock()
payload := p.get(peer)
payload.Requests = append(payload.Requests, request...)
p.set(peer, payload)
}
func (p *payloads) AddMessages(peer state.PeerID, messages ...*protobuf.Message) {
p.Lock()
defer p.Unlock()
payload := p.get(peer)
if payload.Messages == nil {
payload.Messages = make([]*protobuf.Message, 0)
}
payload.Messages = append(payload.Messages, messages...)
p.set(peer, payload)
}
func (p *payloads) MapAndClear(f func(state.PeerID, protobuf.Payload) error) error {
p.Lock()
defer p.Unlock()
for peer, payload := range p.payloads {
err := f(peer, payload)
if err != nil {
return err
}
}
// TODO: this should only be called upon confirmation that the message has been sent
p.payloads = make(map[state.PeerID]protobuf.Payload)
return nil
}
func (p *payloads) get(peer state.PeerID) protobuf.Payload {
payload, _ := p.payloads[peer]
return payload
}
func (p *payloads) set(peer state.PeerID, payload protobuf.Payload) {
p.payloads[peer] = payload
}

39
vendor/github.com/vacp2p/mvds/peers/persistence.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
package peers
import (
"github.com/vacp2p/mvds/state"
)
type Persistence interface {
Add(state.GroupID, state.PeerID) error
GetByGroupID(group state.GroupID) ([]state.PeerID, error)
Exists(state.GroupID, state.PeerID) (bool, error)
}
type MemoryPersistence struct {
peers map[state.GroupID][]state.PeerID
}
func NewMemoryPersistence() *MemoryPersistence {
return &MemoryPersistence{
peers: make(map[state.GroupID][]state.PeerID),
}
}
func (p *MemoryPersistence) Add(groupID state.GroupID, peerID state.PeerID) error {
p.peers[groupID] = append(p.peers[groupID], peerID)
return nil
}
func (p *MemoryPersistence) Exists(groupID state.GroupID, peerID state.PeerID) (bool, error) {
for _, peer := range p.peers[groupID] {
if peer == peerID {
return true, nil
}
}
return false, nil
}
func (p *MemoryPersistence) GetByGroupID(groupID state.GroupID) ([]state.PeerID, error) {
return p.peers[groupID], nil
}

20
vendor/github.com/vacp2p/mvds/protobuf/messageid.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
package protobuf
import (
"crypto/sha256"
"encoding/binary"
"github.com/vacp2p/mvds/state"
)
// ID creates the MessageID for a Message
func (m Message) ID() state.MessageID {
t := make([]byte, 8)
binary.LittleEndian.PutUint64(t, uint64(m.Timestamp))
b := append([]byte("MESSAGE_ID"), m.GroupId[:]...)
b = append(b, t...)
b = append(b, m.Body...)
return sha256.Sum256(b)
}

7
vendor/github.com/vacp2p/mvds/protobuf/payload.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
package protobuf
// IsValid checks whether there are any known field in the protobuf
// message
func (m *Payload) IsValid() bool {
return len(m.Messages)+len(m.Acks)+len(m.Offers)+len(m.Requests) != 0
}

164
vendor/github.com/vacp2p/mvds/protobuf/sync.pb.go generated vendored Normal file
View File

@ -0,0 +1,164 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: protobuf/sync.proto
package protobuf
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Payload struct {
Acks [][]byte `protobuf:"bytes,5001,rep,name=acks,proto3" json:"acks,omitempty"`
Offers [][]byte `protobuf:"bytes,5002,rep,name=offers,proto3" json:"offers,omitempty"`
Requests [][]byte `protobuf:"bytes,5003,rep,name=requests,proto3" json:"requests,omitempty"`
Messages []*Message `protobuf:"bytes,5004,rep,name=messages,proto3" json:"messages,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Payload) Reset() { *m = Payload{} }
func (m *Payload) String() string { return proto.CompactTextString(m) }
func (*Payload) ProtoMessage() {}
func (*Payload) Descriptor() ([]byte, []int) {
return fileDescriptor_2dca527c092c79d7, []int{0}
}
func (m *Payload) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Payload.Unmarshal(m, b)
}
func (m *Payload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Payload.Marshal(b, m, deterministic)
}
func (m *Payload) XXX_Merge(src proto.Message) {
xxx_messageInfo_Payload.Merge(m, src)
}
func (m *Payload) XXX_Size() int {
return xxx_messageInfo_Payload.Size(m)
}
func (m *Payload) XXX_DiscardUnknown() {
xxx_messageInfo_Payload.DiscardUnknown(m)
}
var xxx_messageInfo_Payload proto.InternalMessageInfo
func (m *Payload) GetAcks() [][]byte {
if m != nil {
return m.Acks
}
return nil
}
func (m *Payload) GetOffers() [][]byte {
if m != nil {
return m.Offers
}
return nil
}
func (m *Payload) GetRequests() [][]byte {
if m != nil {
return m.Requests
}
return nil
}
func (m *Payload) GetMessages() []*Message {
if m != nil {
return m.Messages
}
return nil
}
type Message struct {
GroupId []byte `protobuf:"bytes,6001,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
Timestamp int64 `protobuf:"varint,6002,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
Body []byte `protobuf:"bytes,6003,opt,name=body,proto3" json:"body,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Message) Reset() { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage() {}
func (*Message) Descriptor() ([]byte, []int) {
return fileDescriptor_2dca527c092c79d7, []int{1}
}
func (m *Message) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Message.Unmarshal(m, b)
}
func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Message.Marshal(b, m, deterministic)
}
func (m *Message) XXX_Merge(src proto.Message) {
xxx_messageInfo_Message.Merge(m, src)
}
func (m *Message) XXX_Size() int {
return xxx_messageInfo_Message.Size(m)
}
func (m *Message) XXX_DiscardUnknown() {
xxx_messageInfo_Message.DiscardUnknown(m)
}
var xxx_messageInfo_Message proto.InternalMessageInfo
func (m *Message) GetGroupId() []byte {
if m != nil {
return m.GroupId
}
return nil
}
func (m *Message) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *Message) GetBody() []byte {
if m != nil {
return m.Body
}
return nil
}
func init() {
proto.RegisterType((*Payload)(nil), "mvds.Payload")
proto.RegisterType((*Message)(nil), "mvds.Message")
}
func init() { proto.RegisterFile("protobuf/sync.proto", fileDescriptor_2dca527c092c79d7) }
var fileDescriptor_2dca527c092c79d7 = []byte{
// 215 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2e, 0x28, 0xca, 0x2f,
0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xae, 0xcc, 0x4b, 0xd6, 0x03, 0xf3, 0x84, 0x58, 0x72, 0xcb,
0x52, 0x8a, 0x95, 0x1a, 0x18, 0xb9, 0xd8, 0x03, 0x12, 0x2b, 0x73, 0xf2, 0x13, 0x53, 0x84, 0x84,
0xb9, 0x58, 0x12, 0x93, 0xb3, 0x8b, 0x25, 0x3a, 0xd5, 0x15, 0x98, 0x35, 0x78, 0x82, 0xc0, 0x1c,
0x21, 0x71, 0x2e, 0xb6, 0xfc, 0xb4, 0xb4, 0xd4, 0xa2, 0x62, 0x89, 0x2e, 0x88, 0x30, 0x94, 0x2b,
0x24, 0xcd, 0xc5, 0x51, 0x94, 0x5a, 0x58, 0x9a, 0x5a, 0x5c, 0x52, 0x2c, 0xd1, 0x0d, 0x91, 0x82,
0x0b, 0x08, 0x69, 0x71, 0x71, 0xe4, 0xa6, 0x16, 0x17, 0x27, 0xa6, 0xa7, 0x16, 0x4b, 0xf4, 0x80,
0x24, 0xb9, 0x8d, 0x78, 0xf5, 0x40, 0x16, 0xea, 0xf9, 0x42, 0x84, 0x83, 0xe0, 0xf2, 0x4a, 0x91,
0x5c, 0xec, 0x50, 0x41, 0x21, 0x29, 0x2e, 0x8e, 0xf4, 0xa2, 0xfc, 0xd2, 0x82, 0xf8, 0xcc, 0x14,
0x89, 0x8f, 0x7a, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0xec, 0x60, 0x01, 0xcf, 0x14, 0x21, 0x59, 0x2e,
0xce, 0x92, 0xcc, 0xdc, 0xd4, 0xe2, 0x92, 0xc4, 0xdc, 0x02, 0x89, 0x4f, 0x20, 0x49, 0xe6, 0x20,
0x84, 0x08, 0xc8, 0xf1, 0x49, 0xf9, 0x29, 0x95, 0x12, 0x9f, 0x21, 0xda, 0xc0, 0x1c, 0x27, 0xae,
0x28, 0x0e, 0x98, 0xd7, 0x93, 0xd8, 0xc0, 0x2c, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18,
0xdd, 0xc7, 0x8d, 0x0d, 0x01, 0x00, 0x00,
}

17
vendor/github.com/vacp2p/mvds/protobuf/sync.proto generated vendored Normal file
View File

@ -0,0 +1,17 @@
syntax = "proto3";
package mvds;
option go_package = "protobuf";
message Payload {
repeated bytes acks = 5001;
repeated bytes offers = 5002;
repeated bytes requests = 5003;
repeated Message messages = 5004;
}
message Message {
bytes group_id = 6001;
int64 timestamp = 6002;
bytes body = 6003;
}

4
vendor/github.com/vacp2p/mvds/state/peerid.go generated vendored Normal file
View File

@ -0,0 +1,4 @@
package state
// PeerID is the ID for a specific peer.
type PeerID [65]byte

29
vendor/github.com/vacp2p/mvds/state/state.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Package state contains everything related to the synchronization state for MVDS.
package state
// RecordType is the type for a specific record, either `OFFER`, `REQUEST` or `MESSAGE`.
type RecordType int
const (
OFFER RecordType = iota
REQUEST
MESSAGE
)
// State is a struct used to store a records [state](https://github.com/status-im/bigbrother-specs/blob/master/data_sync/mvds.md#state).
type State struct {
Type RecordType
SendCount uint64
SendEpoch int64
// GroupID is optional, thus nullable
GroupID *GroupID
PeerID PeerID
MessageID MessageID
}
type SyncState interface {
Add(newState State) error
Remove(id MessageID, peer PeerID) error
All() ([]State, error)
Map(epoch int64, process func(State) State) error
}

61
vendor/github.com/vacp2p/mvds/state/state_memory.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
package state
import (
"sync"
)
type memorySyncState struct {
sync.Mutex
state []State
}
func NewSyncState() *memorySyncState {
return &memorySyncState{}
}
func (s *memorySyncState) Add(newState State) error {
s.Lock()
defer s.Unlock()
s.state = append(s.state, newState)
return nil
}
func (s *memorySyncState) Remove(id MessageID, peer PeerID) error {
s.Lock()
defer s.Unlock()
var newState []State
for _, state := range s.state {
if state.MessageID != id || state.PeerID != peer {
newState = append(newState, state)
}
}
s.state = newState
return nil
}
func (s *memorySyncState) All() ([]State, error) {
s.Lock()
defer s.Unlock()
return s.state, nil
}
func (s *memorySyncState) Map(epoch int64, process func(State) State) error {
s.Lock()
defer s.Unlock()
for i, state := range s.state {
if state.SendEpoch > epoch {
continue
}
s.state[i] = process(state)
}
return nil
}

4
vendor/github.com/vacp2p/mvds/state/sync_types.go generated vendored Normal file
View File

@ -0,0 +1,4 @@
package state
type MessageID [32]byte
type GroupID [32]byte

13
vendor/github.com/vacp2p/mvds/store/messagestore.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Package store contains everything storage related for MVDS.
package store
import (
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
)
type MessageStore interface {
Has(id state.MessageID) (bool, error)
Get(id state.MessageID) (*protobuf.Message, error)
Add(message *protobuf.Message) error
}

View File

@ -0,0 +1,45 @@
package store
import (
"errors"
"sync"
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
)
type DummyStore struct {
sync.Mutex
ms map[state.MessageID]*protobuf.Message
}
func NewDummyStore() DummyStore {
return DummyStore{ms: make(map[state.MessageID]*protobuf.Message)}
}
func (ds *DummyStore) Has(id state.MessageID) (bool, error) {
ds.Lock()
defer ds.Unlock()
_, ok := ds.ms[id]
return ok, nil
}
func (ds *DummyStore) Get(id state.MessageID) (*protobuf.Message, error) {
ds.Lock()
defer ds.Unlock()
m, ok := ds.ms[id]
if !ok {
return nil, errors.New("message does not exist")
}
return m, nil
}
func (ds *DummyStore) Add(message *protobuf.Message) error {
ds.Lock()
defer ds.Unlock()
ds.ms[message.ID()] = message
return nil
}

View File

@ -0,0 +1,54 @@
package transport
import (
"errors"
math "math/rand"
"sync"
"time"
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
)
// ChannelTransport implements a basic MVDS transport using channels for basic testing purposes.
type ChannelTransport struct {
sync.Mutex
offline int
in <-chan Packet
out map[state.PeerID]chan<- Packet
}
func NewChannelTransport(offline int, in <-chan Packet) *ChannelTransport {
return &ChannelTransport{
offline: offline,
in: in,
out: make(map[state.PeerID]chan<- Packet),
}
}
func (t *ChannelTransport) AddOutput(id state.PeerID, c chan<- Packet) {
t.out[id] = c
}
func (t *ChannelTransport) Watch() Packet {
return <-t.in
}
func (t *ChannelTransport) Send(sender state.PeerID, peer state.PeerID, payload protobuf.Payload) error {
// @todo we can do this better, we put node onlineness into a goroutine where we just stop the nodes for x seconds
// outside of this class
math.Seed(time.Now().UnixNano())
if math.Intn(100) < t.offline {
return nil
}
c, ok := t.out[peer]
if !ok {
return errors.New("peer unknown")
}
c <- Packet{Sender: sender, Payload: payload}
return nil
}

18
vendor/github.com/vacp2p/mvds/transport/transport.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// Package transport contains transport related logic for MVDS.
package transport
import (
"github.com/vacp2p/mvds/protobuf"
"github.com/vacp2p/mvds/state"
)
type Packet struct {
Sender state.PeerID
Payload protobuf.Payload
}
// Transport defines an interface allowing for agnostic transport implementations.
type Transport interface {
Watch() Packet
Send(sender state.PeerID, peer state.PeerID, payload protobuf.Payload) error
}

16
vendor/modules.txt vendored
View File

@ -108,7 +108,7 @@ github.com/golang-migrate/migrate/v4/source
github.com/golang-migrate/migrate/v4 github.com/golang-migrate/migrate/v4
# github.com/golang/mock v1.2.0 # github.com/golang/mock v1.2.0
github.com/golang/mock/gomock github.com/golang/mock/gomock
# github.com/golang/protobuf v1.3.1 # github.com/golang/protobuf v1.3.2
github.com/golang/protobuf/proto github.com/golang/protobuf/proto
github.com/golang/protobuf/protoc-gen-go/descriptor github.com/golang/protobuf/protoc-gen-go/descriptor
# github.com/golang/snappy v0.0.1 # github.com/golang/snappy v0.0.1
@ -152,6 +152,8 @@ github.com/jbenet/goprocess
github.com/jbenet/goprocess/context github.com/jbenet/goprocess/context
github.com/jbenet/goprocess/periodic github.com/jbenet/goprocess/periodic
github.com/jbenet/goprocess/ratelimit github.com/jbenet/goprocess/ratelimit
# github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8
github.com/jinzhu/copier
# github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2 # github.com/karalabe/hid v0.0.0-20181128192157-d815e0c1a2e2
github.com/karalabe/hid github.com/karalabe/hid
# github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b # github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b
@ -315,11 +317,13 @@ github.com/status-im/migrate/v4/database/sqlcipher
github.com/status-im/rendezvous github.com/status-im/rendezvous
github.com/status-im/rendezvous/protocol github.com/status-im/rendezvous/protocol
github.com/status-im/rendezvous/server github.com/status-im/rendezvous/server
# github.com/status-im/status-protocol-go v0.1.1 # github.com/status-im/status-protocol-go v0.1.3
github.com/status-im/status-protocol-go github.com/status-im/status-protocol-go
github.com/status-im/status-protocol-go/encryption/multidevice github.com/status-im/status-protocol-go/encryption/multidevice
github.com/status-im/status-protocol-go/sqlite github.com/status-im/status-protocol-go/sqlite
github.com/status-im/status-protocol-go/transport/whisper/filter github.com/status-im/status-protocol-go/transport/whisper/filter
github.com/status-im/status-protocol-go/datasync
github.com/status-im/status-protocol-go/datasync/peer
github.com/status-im/status-protocol-go/encryption github.com/status-im/status-protocol-go/encryption
github.com/status-im/status-protocol-go/encryption/sharedsecret github.com/status-im/status-protocol-go/encryption/sharedsecret
github.com/status-im/status-protocol-go/internal/sqlite github.com/status-im/status-protocol-go/internal/sqlite
@ -329,6 +333,7 @@ github.com/status-im/status-protocol-go/transport/whisper/internal/sqlite
github.com/status-im/status-protocol-go/crypto github.com/status-im/status-protocol-go/crypto
github.com/status-im/status-protocol-go/encryption/internal/sqlite github.com/status-im/status-protocol-go/encryption/internal/sqlite
github.com/status-im/status-protocol-go/encryption/publisher github.com/status-im/status-protocol-go/encryption/publisher
github.com/status-im/status-protocol-go/applicationmetadata
# github.com/status-im/whisper v1.4.14 # github.com/status-im/whisper v1.4.14
github.com/status-im/whisper/whisperv6 github.com/status-im/whisper/whisperv6
# github.com/stretchr/testify v1.3.0 # github.com/stretchr/testify v1.3.0
@ -348,6 +353,13 @@ github.com/syndtr/goleveldb/leveldb/filter
github.com/syndtr/goleveldb/leveldb/journal github.com/syndtr/goleveldb/leveldb/journal
github.com/syndtr/goleveldb/leveldb/memdb github.com/syndtr/goleveldb/leveldb/memdb
github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/table
# github.com/vacp2p/mvds v0.0.19
github.com/vacp2p/mvds/node
github.com/vacp2p/mvds/peers
github.com/vacp2p/mvds/state
github.com/vacp2p/mvds/store
github.com/vacp2p/mvds/protobuf
github.com/vacp2p/mvds/transport
# github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc # github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc
github.com/whyrusleeping/go-logging github.com/whyrusleeping/go-logging
# github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f # github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f