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:
parent
21a62c731f
commit
9de77b21b2
2
go.mod
2
go.mod
|
@ -19,7 +19,7 @@ require (
|
|||
github.com/status-im/doubleratchet v2.0.0+incompatible
|
||||
github.com/status-im/migrate/v4 v4.3.1-status
|
||||
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/stretchr/testify v1.3.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
|
|
13
go.sum
13
go.sum
|
@ -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.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
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-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
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/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/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/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
|
||||
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/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/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/go.mod h1:Ulij8LMpMvXnbnPcmDqrpI+iXoXSjxItuY/wmbasTZU=
|
||||
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/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-protocol-go v0.1.1 h1:PGKtMTgfk48LS2ZyNIEdJZJjQGVbkBfccf6EVYCjCpA=
|
||||
github.com/status-im/status-protocol-go v0.1.1/go.mod h1:rqlsXFR7WENTB4HDJRByRg95UfRo8pjGWvrvVrC2Dm4=
|
||||
github.com/status-im/status-protocol-go v0.1.3 h1:2ELZ3XR/11CHvElVUDIo9swUQRvrekFC5ZK9W1dB+Eo=
|
||||
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/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.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
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-20190716104307-221dbe5ed46703ee255b1da0dec05086f5035f62/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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/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/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/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-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
|
|
|
@ -409,6 +409,15 @@ type ShhextConfig struct {
|
|||
// WhisperCacheDir is a folder where whisper filters may persist messages before delivering them
|
||||
// to a client.
|
||||
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
|
||||
|
|
|
@ -176,17 +176,17 @@ func (s *Service) initProtocol(address, encKey, password string) error {
|
|||
os.Remove(v4Path)
|
||||
}
|
||||
|
||||
options, err := buildMessengerOptions(s.config, sessionsDatabasePath, transportDatabasePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
selectedKeyID := s.w.SelectedKeyPairID()
|
||||
identity, err := s.w.GetPrivateKey(selectedKeyID)
|
||||
if err != nil {
|
||||
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(
|
||||
identity,
|
||||
&server{server: s.server},
|
||||
|
@ -194,12 +194,7 @@ func (s *Service) initProtocol(address, encKey, password string) error {
|
|||
dataDir,
|
||||
encKey,
|
||||
s.config.InstallationID,
|
||||
protocol.WithDatabaseFilePaths(
|
||||
sessionsDatabasePath,
|
||||
transportDatabasePath,
|
||||
),
|
||||
protocol.WithGenericDiscoveryTopicSupport(),
|
||||
protocol.WithCustomLogger(zapLogger),
|
||||
options...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -226,11 +221,19 @@ func (s *Service) retrieveMessagesLoop(tick time.Duration, cancel <-chan struct{
|
|||
}
|
||||
|
||||
var signalMessages []*signal.Messages
|
||||
|
||||
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{
|
||||
Chat: chat,
|
||||
Error: nil, // TODO: what is it needed for?
|
||||
Messages: s.deduplicator.Deduplicate(messages),
|
||||
Messages: s.deduplicator.Deduplicate(retrievedMessages),
|
||||
}
|
||||
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 {
|
||||
s.envelopesMonitor.Add(common.BytesToHash(hash), newMessage)
|
||||
mID := messageID(newMessage)
|
||||
|
|
|
@ -38,7 +38,6 @@ package proto
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -194,7 +193,7 @@ func (p *Properties) Parse(s string) {
|
|||
// "bytes,49,opt,name=foo,def=hello!"
|
||||
fields := strings.Split(s, ",") // breaks def=, but handled below.
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -214,7 +213,7 @@ func (p *Properties) Parse(s string) {
|
|||
p.WireType = WireBytes
|
||||
// no numeric converter for non-numeric types
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
guard 'gotest' do
|
||||
watch(%r{\.go$})
|
||||
end
|
|
@ -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.
|
|
@ -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).
|
|
@ -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
|
||||
}
|
|
@ -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 ./...
|
|
@ -1,3 +1,8 @@
|
|||
run:
|
||||
concurrency: 4
|
||||
modules-download-mode: vendor
|
||||
deadline: 5m
|
||||
skip:
|
||||
- migrations.go
|
||||
- .*_mock.go
|
||||
- vendor/
|
||||
|
|
|
@ -2,26 +2,22 @@ notifications:
|
|||
email: false
|
||||
|
||||
language: go
|
||||
go:
|
||||
- "1.12.x"
|
||||
- "1.13beta1"
|
||||
|
||||
install: true
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
before_script:
|
||||
- make install-linter
|
||||
- GO111MODULE=on GOFLAGS=-mod=vendor
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: "1.11.x"
|
||||
env: GOFLAGS=-mod=vendor
|
||||
script:
|
||||
- make lint
|
||||
# fails without -a
|
||||
- go test -a ./... # make test
|
||||
- go: "1.12.x"
|
||||
env: GOFLAGS=-mod=vendor
|
||||
script:
|
||||
- make lint
|
||||
# fails without -a
|
||||
- go test -a ./... # make test
|
||||
allow_failures:
|
||||
- go: "1.13beta1"
|
||||
|
||||
before_script:
|
||||
- make install-linter
|
||||
|
||||
script:
|
||||
- make lint
|
||||
- make test
|
||||
|
|
|
@ -19,6 +19,9 @@ import (
|
|||
"github.com/status-im/status-protocol-go/encryption/multidevice"
|
||||
transport "github.com/status-im/status-protocol-go/transport/whisper"
|
||||
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.
|
||||
|
@ -34,6 +37,7 @@ type whisperAdapter struct {
|
|||
privateKey *ecdsa.PrivateKey
|
||||
transport *transport.WhisperServiceTransport
|
||||
protocol *encryption.Protocol
|
||||
datasync *datasync.DataSync
|
||||
logger *zap.Logger
|
||||
|
||||
featureFlags featureFlags
|
||||
|
@ -43,6 +47,7 @@ func newWhisperAdapter(
|
|||
pk *ecdsa.PrivateKey,
|
||||
t *transport.WhisperServiceTransport,
|
||||
p *encryption.Protocol,
|
||||
d *datasync.DataSync,
|
||||
featureFlags featureFlags,
|
||||
logger *zap.Logger,
|
||||
) *whisperAdapter {
|
||||
|
@ -50,13 +55,22 @@ func newWhisperAdapter(
|
|||
logger = zap.NewNop()
|
||||
}
|
||||
|
||||
return &whisperAdapter{
|
||||
adapter := &whisperAdapter{
|
||||
privateKey: pk,
|
||||
transport: t,
|
||||
protocol: p,
|
||||
datasync: d,
|
||||
featureFlags: featureFlags,
|
||||
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 {
|
||||
|
@ -75,6 +89,34 @@ func (a *whisperAdapter) LeavePrivate(publicKey *ecdsa.PublicKey) error {
|
|||
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.
|
||||
// It implies joining a chat if it has not been joined yet.
|
||||
func (a *whisperAdapter) RetrievePublicMessages(chatID string) ([]*protocol.Message, error) {
|
||||
|
@ -83,32 +125,7 @@ func (a *whisperAdapter) RetrievePublicMessages(chatID string) ([]*protocol.Mess
|
|||
return nil, err
|
||||
}
|
||||
|
||||
logger := a.logger.With(zap.String("site", "RetrievePublicMessages"))
|
||||
|
||||
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
|
||||
return a.handleRetrievedMessages(messages)
|
||||
}
|
||||
|
||||
// RetrievePrivateMessages retrieves the collected private messages.
|
||||
|
@ -119,47 +136,49 @@ func (a *whisperAdapter) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]
|
|||
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))
|
||||
for _, item := range messages {
|
||||
shhMessage := whisper.ToWhisperMessage(item)
|
||||
|
||||
hlogger := logger.With(zap.Binary("hash", shhMessage.Hash))
|
||||
hlogger.Debug("handling a received message")
|
||||
|
||||
hlogger.Debug("received a private message")
|
||||
|
||||
err := a.decryptMessage(context.Background(), shhMessage)
|
||||
statusMessages, err := a.handleMessages(shhMessage, true)
|
||||
if err != nil {
|
||||
hlogger.Error("failed to decrypt a message", zap.Error(err))
|
||||
}
|
||||
|
||||
statusMessage, err := a.decodeMessage(shhMessage)
|
||||
if err != nil {
|
||||
hlogger.Error("failed to decode a message", zap.Error(err))
|
||||
hlogger.Info("failed to decode messages", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
switch m := statusMessage.Message.(type) {
|
||||
case protocol.Message:
|
||||
m.ID = statusMessage.ID
|
||||
m.SigPubKey = statusMessage.SigPubKey
|
||||
decodedMessages = append(decodedMessages, &m)
|
||||
case protocol.PairMessage:
|
||||
fromOurDevice := isPubKeyEqual(statusMessage.SigPubKey, &a.privateKey.PublicKey)
|
||||
if !fromOurDevice {
|
||||
hlogger.Debug("received PairMessage from not our device, skipping")
|
||||
break
|
||||
}
|
||||
for _, statusMessage := range statusMessages {
|
||||
switch m := statusMessage.ParsedMessage.(type) {
|
||||
case protocol.Message:
|
||||
m.ID = statusMessage.ID
|
||||
m.SigPubKey = statusMessage.SigPubKey()
|
||||
decodedMessages = append(decodedMessages, &m)
|
||||
case protocol.PairMessage:
|
||||
fromOurDevice := isPubKeyEqual(statusMessage.SigPubKey(), &a.privateKey.PublicKey)
|
||||
if !fromOurDevice {
|
||||
hlogger.Debug("received PairMessage from not our device, skipping")
|
||||
break
|
||||
}
|
||||
|
||||
metadata := &multidevice.InstallationMetadata{
|
||||
Name: m.Name,
|
||||
FCMToken: m.FCMToken,
|
||||
DeviceType: m.DeviceType,
|
||||
}
|
||||
err := a.protocol.SetInstallationMetadata(&a.privateKey.PublicKey, m.InstallationID, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
metadata := &multidevice.InstallationMetadata{
|
||||
Name: m.Name,
|
||||
FCMToken: m.FCMToken,
|
||||
DeviceType: m.DeviceType,
|
||||
}
|
||||
err := a.protocol.SetInstallationMetadata(&a.privateKey.PublicKey, m.InstallationID, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
hlogger.Error("skipped a public message of unsupported type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,88 +186,81 @@ func (a *whisperAdapter) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]
|
|||
}
|
||||
|
||||
// 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 _, message := range messages {
|
||||
shhMessage := whisper.ToWhisperMessage(message)
|
||||
err := a.decryptMessage(context.Background(), shhMessage)
|
||||
statusMessages, err := a.handleMessages(shhMessage, false)
|
||||
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
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
func (a *whisperAdapter) RetrieveRaw(filterID string) ([]*whisper.Message, error) {
|
||||
messages, err := a.transport.RetrieveRaw(filterID)
|
||||
// handleMessages expects a whisper message as input, and it will go through
|
||||
// a series of transformations until the message is parsed into an application
|
||||
// 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 {
|
||||
hlogger.Error("failed to handle transport layer message", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger := a.logger.With(zap.String("site", "RetrieveRaw"))
|
||||
err = a.handleEncryptionLayer(context.Background(), &statusMessage)
|
||||
if err != nil {
|
||||
hlogger.Debug("failed to handle an encryption message", zap.Error(err))
|
||||
}
|
||||
|
||||
var result []*whisper.Message
|
||||
statusMessages, err := statusMessage.HandleDatasync(a.datasync)
|
||||
if err != nil {
|
||||
hlogger.Debug("failed to handle datasync message", zap.Error(err))
|
||||
|
||||
for _, message := range messages {
|
||||
shhMessage := whisper.ToWhisperMessage(message)
|
||||
err := a.decryptMessage(context.Background(), shhMessage)
|
||||
}
|
||||
|
||||
for _, statusMessage := range statusMessages {
|
||||
err := statusMessage.HandleApplicationMetadata()
|
||||
if err != nil {
|
||||
logger.Warn("failed to decrypt a message", zap.Error(err), zap.Binary("messageID", shhMessage.Hash))
|
||||
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")
|
||||
}
|
||||
}
|
||||
result = append(result, shhMessage)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger := a.logger.With(zap.String("site", "handleEncryptionLayer"))
|
||||
|
||||
decoded, err := protocol.DecodeMessage(publicKey, message.Payload)
|
||||
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,
|
||||
)
|
||||
err := message.HandleEncryption(a.privateKey, publicKey, a.protocol)
|
||||
if err == encryption.ErrDeviceNotFound {
|
||||
handleErr := a.handleErrDeviceNotFound(ctx, publicKey)
|
||||
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")
|
||||
}
|
||||
|
||||
message.Payload = payload
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
newMessage := whisper.NewMessage{
|
||||
TTL: whisperTTL,
|
||||
Payload: encodedMessage,
|
||||
PowTarget: whisperPoW,
|
||||
PowTime: whisperPoWTime,
|
||||
wrappedMessage, err := a.tryWrapMessageV1(encodedMessage)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to wrap message")
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -319,18 +337,27 @@ func (a *whisperAdapter) SendPublic(ctx context.Context, chatName, chatID string
|
|||
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.
|
||||
// DEPRECATED
|
||||
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,
|
||||
Payload: data,
|
||||
Payload: wrappedMessage,
|
||||
PowTarget: whisperPoW,
|
||||
PowTime: whisperPoWTime,
|
||||
}
|
||||
|
||||
hash, err := a.transport.SendPublic(ctx, newMessage, chatName)
|
||||
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))
|
||||
}
|
||||
|
||||
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) {
|
||||
encodedMessage, err := protocol.EncodeMessage(message)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -388,16 +420,43 @@ func (a *whisperAdapter) SendPrivate(
|
|||
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 {
|
||||
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 err != nil {
|
||||
return nil, nil, err
|
||||
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 {
|
||||
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.
|
||||
|
@ -415,7 +474,12 @@ func (a *whisperAdapter) SendPrivateRaw(
|
|||
|
||||
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 {
|
||||
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")
|
||||
}
|
||||
|
||||
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)
|
||||
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) {
|
||||
var newMessage whisper.NewMessage
|
||||
|
||||
|
|
85
vendor/github.com/status-im/status-protocol-go/applicationmetadata/message.pb.go
generated
vendored
Normal file
85
vendor/github.com/status-im/status-protocol-go/applicationmetadata/message.pb.go
generated
vendored
Normal 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,
|
||||
}
|
8
vendor/github.com/status-im/status-protocol-go/applicationmetadata/message.proto
generated
vendored
Normal file
8
vendor/github.com/status-im/status-protocol-go/applicationmetadata/message.proto
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package applicationmetadata;
|
||||
|
||||
message Message {
|
||||
bytes signature = 4001;
|
||||
bytes payload = 4002;
|
||||
}
|
22
vendor/github.com/status-im/status-protocol-go/applicationmetadata/pubkey.go
generated
vendored
Normal file
22
vendor/github.com/status-im/status-protocol-go/applicationmetadata/pubkey.go
generated
vendored
Normal 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
|
||||
}
|
17
vendor/github.com/status-im/status-protocol-go/applicationmetadata/service.go
generated
vendored
Normal file
17
vendor/github.com/status-im/status-protocol-go/applicationmetadata/service.go
generated
vendored
Normal 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
|
||||
}
|
67
vendor/github.com/status-im/status-protocol-go/datasync/datasync.go
generated
vendored
Normal file
67
vendor/github.com/status-im/status-protocol-go/datasync/datasync.go
generated
vendored
Normal 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()
|
||||
}
|
19
vendor/github.com/status-im/status-protocol-go/datasync/peer/utils.go
generated
vendored
Normal file
19
vendor/github.com/status-im/status-protocol-go/datasync/peer/utils.go
generated
vendored
Normal 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[:])
|
||||
}
|
61
vendor/github.com/status-im/status-protocol-go/datasync/transport.go
generated
vendored
Normal file
61
vendor/github.com/status-im/status-protocol-go/datasync/transport.go
generated
vendored
Normal 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.
|
||||
}
|
|
@ -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))
|
||||
}
|
80
vendor/github.com/status-im/status-protocol-go/encryption/internal/sqlite/migrations.go
generated
vendored
80
vendor/github.com/status-im/status-protocol-go/encryption/internal/sqlite/migrations.go
generated
vendored
|
@ -13,8 +13,6 @@
|
|||
// 1558588866_add_version.up.sql (57B)
|
||||
// 1559627659_add_contact_code.down.sql (32B)
|
||||
// 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.up.sql (267B)
|
||||
// doc.go (377B)
|
||||
|
@ -101,7 +99,7 @@ func _1536754952_initial_schemaDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -121,7 +119,7 @@ func _1536754952_initial_schemaUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -141,7 +139,7 @@ func _1539249977_update_ratchet_infoDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -161,7 +159,7 @@ func _1539249977_update_ratchet_infoUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -181,7 +179,7 @@ func _1540715431_add_versionDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -201,7 +199,7 @@ func _1540715431_add_versionUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -221,7 +219,7 @@ func _1541164797_add_installationsDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -241,7 +239,7 @@ func _1541164797_add_installationsUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -261,7 +259,7 @@ func _1558084410_add_secretDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -281,7 +279,7 @@ func _1558084410_add_secretUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -301,7 +299,7 @@ func _1558588866_add_versionUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -321,7 +319,7 @@ func _1559627659_add_contact_codeDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -341,51 +339,11 @@ func _1559627659_add_contact_codeUpSql() (*asset, error) {
|
|||
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}}
|
||||
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")
|
||||
|
||||
func _1561368210_add_installation_metadataDownSqlBytes() ([]byte, error) {
|
||||
|
@ -401,7 +359,7 @@ func _1561368210_add_installation_metadataDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -421,7 +379,7 @@ func _1561368210_add_installation_metadataUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -441,7 +399,7 @@ func docGo() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -563,10 +521,6 @@ var _bindata = map[string]func() (*asset, error){
|
|||
|
||||
"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.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{}},
|
||||
"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{}},
|
||||
"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.up.sql": &bintree{_1561368210_add_installation_metadataUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
|
|
|
@ -6,7 +6,8 @@ require (
|
|||
github.com/aristanetworks/goarista v0.0.0-20190704150520-f44d68189fd7 // indirect
|
||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||
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/mutecomm/go-sqlcipher v0.0.0-20170920224653-f799951b4ab2
|
||||
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/whisper v1.4.14
|
||||
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/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.10.0
|
||||
|
|
|
@ -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.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
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-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
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.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||
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/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=
|
||||
|
@ -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/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-20190716104307-221dbe5ed46703ee255b1da0dec05086f5035f62/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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/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/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/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-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8=
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Code generated by go-bindata. DO NOT EDIT.
|
||||
// sources:
|
||||
// 000001_add_messages_contacts.down.db.sql (91B)
|
||||
// 000001_add_messages_contacts.up.db.sql (685B)
|
||||
// 000002_add_unread_to_user_messages.down.sql (210B)
|
||||
// 000002_add_unread_to_user_messages.up.sql (113B)
|
||||
// 000001_init.down.db.sql (82B)
|
||||
// 000001_init.up.db.sql (840B)
|
||||
// doc.go (377B)
|
||||
|
||||
package sqlite
|
||||
|
@ -73,83 +71,43 @@ func (fi bindataFileInfo) Sys() interface{} {
|
|||
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(
|
||||
__000001_add_messages_contactsDownDbSql,
|
||||
"000001_add_messages_contacts.down.db.sql",
|
||||
__000001_initDownDbSql,
|
||||
"000001_init.down.db.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _000001_add_messages_contactsDownDbSql() (*asset, error) {
|
||||
bytes, err := _000001_add_messages_contactsDownDbSqlBytes()
|
||||
func _000001_initDownDbSql() (*asset, error) {
|
||||
bytes, err := _000001_initDownDbSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000001_add_messages_contacts.down.db.sql", size: 91, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 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}}
|
||||
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{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
|
||||
}
|
||||
|
||||
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(
|
||||
__000001_add_messages_contactsUpDbSql,
|
||||
"000001_add_messages_contacts.up.db.sql",
|
||||
__000001_initUpDbSql,
|
||||
"000001_init.up.db.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _000001_add_messages_contactsUpDbSql() (*asset, error) {
|
||||
bytes, err := _000001_add_messages_contactsUpDbSqlBytes()
|
||||
func _000001_initUpDbSql() (*asset, error) {
|
||||
bytes, err := _000001_initUpDbSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "000001_add_messages_contacts.up.db.sql", size: 685, mode: os.FileMode(0644), modTime: time.Unix(1562955202, 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}}
|
||||
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}}
|
||||
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{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
|
||||
}
|
||||
|
||||
|
@ -168,7 +126,7 @@ func docGo() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -264,13 +222,9 @@ func AssetNames() []string {
|
|||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
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,
|
||||
|
||||
"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,
|
||||
"000001_init.up.db.sql": _000001_initUpDbSql,
|
||||
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
@ -316,11 +270,9 @@ type bintree struct {
|
|||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"000001_add_messages_contacts.down.db.sql": &bintree{_000001_add_messages_contactsDownDbSql, map[string]*bintree{}},
|
||||
"000001_add_messages_contacts.up.db.sql": &bintree{_000001_add_messages_contactsUpDbSql, 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{}},
|
||||
"000001_init.down.db.sql": &bintree{_000001_initDownDbSql, map[string]*bintree{}},
|
||||
"000001_init.up.db.sql": &bintree{_000001_initUpDbSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
|
|
@ -3,6 +3,7 @@ package statusproto
|
|||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
|
@ -11,6 +12,8 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
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/multidevice"
|
||||
"github.com/status-im/status-protocol-go/encryption/sharedsecret"
|
||||
|
@ -19,12 +22,10 @@ import (
|
|||
transport "github.com/status-im/status-protocol-go/transport/whisper"
|
||||
"github.com/status-im/status-protocol-go/transport/whisper/filter"
|
||||
protocol "github.com/status-im/status-protocol-go/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// messagesDatabaseFileName is a name of the SQL file in which
|
||||
// messages are stored.
|
||||
messagesDatabaseFileName = "messages.sql"
|
||||
datasyncnode "github.com/vacp2p/mvds/node"
|
||||
datasyncpeers "github.com/vacp2p/mvds/peers"
|
||||
datasyncstate "github.com/vacp2p/mvds/state"
|
||||
datasyncstore "github.com/vacp2p/mvds/store"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -44,14 +45,12 @@ type Messenger struct {
|
|||
persistence persistence
|
||||
adapter *whisperAdapter
|
||||
encryptor *encryption.Protocol
|
||||
logger *zap.Logger
|
||||
|
||||
ownMessages map[string][]*protocol.Message
|
||||
featureFlags featureFlags
|
||||
messagesPersistenceEnabled bool
|
||||
|
||||
logger *zap.Logger
|
||||
|
||||
shutdownTasks []func() error
|
||||
shutdownTasks []func() error
|
||||
}
|
||||
|
||||
type featureFlags struct {
|
||||
|
@ -61,6 +60,9 @@ type featureFlags struct {
|
|||
// V1 messages adds additional wrapping
|
||||
// which contains a signature and payload.
|
||||
sendV1Messages bool
|
||||
|
||||
// datasync indicates whether messages should be sent using datasync, breaking change for non-v1 clients
|
||||
datasync bool
|
||||
}
|
||||
|
||||
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(
|
||||
identity *ecdsa.PrivateKey,
|
||||
server transport.Server,
|
||||
|
@ -186,7 +195,9 @@ func NewMessenger(
|
|||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
_, err := messenger.adapter.SendContactCode(ctx, messageSpec)
|
||||
slogger.Warn("failed to send a contact code", zap.Error(err))
|
||||
if err != nil {
|
||||
slogger.Warn("failed to send a contact code", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +235,8 @@ func NewMessenger(
|
|||
return nil, errors.Wrap(err, "failed to create the encryption layer")
|
||||
}
|
||||
|
||||
messagesDatabaseFileName := fmt.Sprintf("%s.messages.sql", installationID)
|
||||
|
||||
applicationLayerFilePath := filepath.Join(dataDir, messagesDatabaseFileName)
|
||||
applicationLayerPersistence, err := sqlite.Open(applicationLayerFilePath, dbKey, sqlite.MigrationConfig{
|
||||
AssetNames: migrations.AssetNames(),
|
||||
|
@ -234,9 +247,22 @@ func NewMessenger(
|
|||
if err != nil {
|
||||
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}
|
||||
adapter := newWhisperAdapter(identity, t, encryptionProtocol, c.featureFlags, logger)
|
||||
adapter := newWhisperAdapter(identity, t, encryptionProtocol, datasync, c.featureFlags, logger)
|
||||
messenger = &Messenger{
|
||||
identity: identity,
|
||||
persistence: persistence,
|
||||
|
@ -248,6 +274,7 @@ func NewMessenger(
|
|||
shutdownTasks: []func() error{
|
||||
persistence.Close,
|
||||
adapter.transport.Reset,
|
||||
func() error { datasync.Stop(); return nil },
|
||||
// Currently this often fails, seems like it's safe to ignore them
|
||||
// https://github.com/uber-go/zap/issues/328
|
||||
func() error { _ = logger.Sync; return nil },
|
||||
|
@ -260,6 +287,9 @@ func NewMessenger(
|
|||
if err := encryptionProtocol.Start(identity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.featureFlags.datasync {
|
||||
dataSyncNode.Start(300 * time.Millisecond)
|
||||
}
|
||||
|
||||
logger.Debug("messages persistence", zap.Bool("enabled", c.messagesPersistenceEnabled))
|
||||
|
||||
|
@ -402,6 +432,47 @@ var (
|
|||
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) {
|
||||
var (
|
||||
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.
|
||||
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 {
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
to := time.Now()
|
||||
from := to.Add(-time.Hour * 24)
|
||||
return m.persistence.Messages(chat.ID(), from, to)
|
||||
return m.persistence.Messages(chatID, from, to)
|
||||
}
|
||||
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
func (m *Messenger) RetrieveRawWithFilter(filterID string) ([]*whisper.Message, error) {
|
||||
return m.adapter.RetrieveRaw(filterID)
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
func (m *Messenger) LoadFilters(chats []*filter.Chat) ([]*filter.Chat, error) {
|
||||
return m.adapter.transport.LoadFilters(chats, m.featureFlags.genericDiscoveryTopicEnabled)
|
||||
|
|
|
@ -47,7 +47,7 @@ func (db sqlitePersistence) LastMessageClock(chatID string) (int64, error) {
|
|||
}
|
||||
|
||||
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 {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ func (db sqlitePersistence) SaveMessages(chatID string, messages []*protocol.Mes
|
|||
return
|
||||
}
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -111,7 +111,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|||
func (db sqlitePersistence) Messages(chatID string, from, to time.Time) (result []*protocol.Message, err error) {
|
||||
rows, err := db.db.Query(`SELECT
|
||||
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))
|
||||
if err != nil {
|
||||
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) {
|
||||
rows, err := db.db.Query(`SELECT
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -192,7 +192,7 @@ func (db sqlitePersistence) UnreadMessages(chatID string) ([]*protocol.Message,
|
|||
FROM
|
||||
user_messages
|
||||
WHERE
|
||||
contact_id = ? AND
|
||||
chat_id = ? AND
|
||||
flags & ? == 0
|
||||
ORDER BY clock`,
|
||||
chatID, protocol.MessageRead,
|
||||
|
|
9
vendor/github.com/status-im/status-protocol-go/transport/whisper/filter/chats.go
generated
vendored
9
vendor/github.com/status-im/status-protocol-go/transport/whisper/filter/chats.go
generated
vendored
|
@ -58,6 +58,10 @@ type Chat struct {
|
|||
Listen bool `json:"listen"`
|
||||
}
|
||||
|
||||
func (c *Chat) IsPublic() bool {
|
||||
return !c.OneToOne
|
||||
}
|
||||
|
||||
type ChatsManager struct {
|
||||
whisper *whisper.Whisper
|
||||
persistence *sqlitePersistence
|
||||
|
@ -278,6 +282,7 @@ func (s *ChatsManager) loadPartitioned(publicKey *ecdsa.PublicKey, listen bool)
|
|||
Topic: filter.Topic,
|
||||
Identity: publicKeyToStr(publicKey),
|
||||
Listen: listen,
|
||||
OneToOne: true,
|
||||
}
|
||||
|
||||
s.chats[chatID] = chat
|
||||
|
@ -310,6 +315,7 @@ func (s *ChatsManager) LoadNegotiated(secret NegotiatedSecret) (*Chat, error) {
|
|||
Identity: publicKeyToStr(secret.PublicKey),
|
||||
Negotiated: true,
|
||||
Listen: true,
|
||||
OneToOne: true,
|
||||
}
|
||||
|
||||
s.chats[chat.ChatID] = chat
|
||||
|
@ -354,6 +360,7 @@ func (s *ChatsManager) LoadDiscovery() ([]*Chat, error) {
|
|||
Identity: identityStr,
|
||||
Discovery: true,
|
||||
Listen: true,
|
||||
OneToOne: true,
|
||||
}
|
||||
|
||||
discoveryResponse, err = s.addAsymmetric(personalDiscoveryChat.ChatID, true)
|
||||
|
@ -373,6 +380,7 @@ func (s *ChatsManager) LoadDiscovery() ([]*Chat, error) {
|
|||
Identity: identityStr,
|
||||
Discovery: true,
|
||||
Listen: true,
|
||||
OneToOne: true,
|
||||
}
|
||||
|
||||
discoveryResponse, err = s.addAsymmetric(discoveryChat.ChatID, true)
|
||||
|
@ -411,6 +419,7 @@ func (s *ChatsManager) LoadPublic(chatID string) (*Chat, error) {
|
|||
SymKeyID: filterAndTopic.SymKeyID,
|
||||
Topic: filterAndTopic.Topic,
|
||||
Listen: true,
|
||||
OneToOne: false,
|
||||
}
|
||||
|
||||
s.chats[chatID] = chat
|
||||
|
|
|
@ -86,7 +86,7 @@ func _1561059285_add_whisper_keysDownSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ func _1561059285_add_whisper_keysUpSql() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func docGo() (*asset, error) {
|
|||
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}}
|
||||
return a, nil
|
||||
}
|
||||
|
|
32
vendor/github.com/status-im/status-protocol-go/transport/whisper/whisper_service.go
generated
vendored
32
vendor/github.com/status-im/status-protocol-go/transport/whisper/whisper_service.go
generated
vendored
|
@ -167,6 +167,34 @@ func (a *WhisperServiceTransport) LeavePrivate(publicKey *ecdsa.PublicKey) error
|
|||
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) {
|
||||
chat, err := a.chats.LoadPublic(chatID)
|
||||
if err != nil {
|
||||
|
@ -183,7 +211,7 @@ func (a *WhisperServiceTransport) RetrievePublicMessages(chatID string) ([]*whis
|
|||
|
||||
func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.PublicKey) ([]*whisper.ReceivedMessage, error) {
|
||||
chats := a.chats.ChatsByPublicKey(publicKey)
|
||||
discoveryChats, err := a.chats.LoadDiscovery()
|
||||
discoveryChats, err := a.chats.Init(nil, nil, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -195,6 +223,7 @@ func (a *WhisperServiceTransport) RetrievePrivateMessages(publicKey *ecdsa.Publi
|
|||
if f == nil {
|
||||
return nil, errors.New("failed to return a filter")
|
||||
}
|
||||
|
||||
result = append(result, f.Retrieve()...)
|
||||
}
|
||||
|
||||
|
@ -211,6 +240,7 @@ func (a *WhisperServiceTransport) RetrieveRawAll() (map[filter.Chat][]*whisper.R
|
|||
if f == nil {
|
||||
return nil, errors.New("failed to return a filter")
|
||||
}
|
||||
|
||||
result[*chat] = append(result[*chat], f.Retrieve()...)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# v1 statusproto package folder
|
||||
|
||||
This folder contains only data types mentioned in the specification and required for its implementation.
|
|
@ -5,16 +5,14 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:generate protoc --go_out=. ./message.proto
|
||||
|
||||
const (
|
||||
// ContentTypeTextPlain means that the message contains plain text.
|
||||
ContentTypeTextPlain = "text/plain"
|
||||
|
@ -67,26 +65,6 @@ const (
|
|||
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.
|
||||
type Message struct {
|
||||
Text string `json:"text"` // TODO: why is this duplicated?
|
||||
|
@ -99,6 +77,8 @@ type Message struct {
|
|||
Flags Flags `json:"-"`
|
||||
ID []byte `json:"-"`
|
||||
SigPubKey *ecdsa.PublicKey `json:"-"`
|
||||
ChatID string `json:"-"`
|
||||
Public bool `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Message) MarshalJSON() ([]byte, error) {
|
||||
|
@ -114,10 +94,6 @@ func (m *Message) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(item)
|
||||
}
|
||||
|
||||
func (m Message) Unread() bool {
|
||||
return !m.Flags.Has(MessageRead)
|
||||
}
|
||||
|
||||
// createTextMessage creates a Message.
|
||||
func createTextMessage(data []byte, lastClock int64, chatID, messageType string) Message {
|
||||
text := strings.TrimSpace(string(data))
|
||||
|
@ -144,17 +120,12 @@ func CreatePrivateTextMessage(data []byte, lastClock int64, chatID string) Messa
|
|||
return createTextMessage(data, lastClock, chatID, MessageTypePrivate)
|
||||
}
|
||||
|
||||
func unwrapMessage(data []byte) (*StatusProtocolMessage, error) {
|
||||
var message StatusProtocolMessage
|
||||
err := proto.Unmarshal(data, &message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &message, nil
|
||||
}
|
||||
func decodeTransitMessage(originalPayload []byte) (interface{}, error) {
|
||||
payload := make([]byte, len(originalPayload))
|
||||
copy(payload, originalPayload)
|
||||
// This modifies the payload
|
||||
buf := bytes.NewBuffer(payload)
|
||||
|
||||
func decodeTransitMessage(data []byte) (interface{}, error) {
|
||||
buf := bytes.NewBuffer(data)
|
||||
decoder := NewMessageDecoder(buf)
|
||||
value, err := decoder.Decode()
|
||||
if err != nil {
|
||||
|
@ -163,42 +134,6 @@ func decodeTransitMessage(data []byte) (interface{}, error) {
|
|||
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.
|
||||
func EncodeMessage(value Message) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
|
|
|
@ -21,8 +21,8 @@ var _ = math.Inf
|
|||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type StatusProtocolMessage struct {
|
||||
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
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:"-"`
|
||||
|
@ -74,12 +74,12 @@ func init() {
|
|||
func init() { proto.RegisterFile("message.proto", fileDescriptor_33c57e4bae7b9afd) }
|
||||
|
||||
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,
|
||||
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,
|
||||
0x17, 0xa2, 0x56, 0x48, 0x86, 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,
|
||||
0x93, 0x9f, 0x98, 0x22, 0xc1, 0x04, 0x96, 0x83, 0x71, 0x93, 0xd8, 0xc0, 0xe6, 0x1a, 0x03, 0x02,
|
||||
0x00, 0x00, 0xff, 0xff, 0xda, 0x9a, 0x88, 0x4b, 0x75, 0x00, 0x00, 0x00,
|
||||
0x2d, 0x06, 0x73, 0x94, 0x02, 0xb9, 0x44, 0x83, 0xc1, 0xdc, 0x00, 0x10, 0x37, 0x39, 0x3f, 0xc7,
|
||||
0x17, 0xa2, 0x56, 0x48, 0x96, 0x8b, 0xb3, 0x38, 0x33, 0x3d, 0x2f, 0xb1, 0xa4, 0xb4, 0x28, 0x55,
|
||||
0x62, 0xa1, 0xbc, 0x02, 0xa3, 0x06, 0x4f, 0x10, 0x42, 0x44, 0x48, 0x92, 0x8b, 0xbd, 0x20, 0xb1,
|
||||
0x32, 0x27, 0x3f, 0x31, 0x45, 0x62, 0x11, 0x44, 0x12, 0xc6, 0x4f, 0x62, 0x03, 0x9b, 0x6c, 0x0c,
|
||||
0x08, 0x00, 0x00, 0xff, 0xff, 0x92, 0x1a, 0x92, 0xf0, 0x77, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package statusproto;
|
||||
|
||||
message StatusProtocolMessage {
|
||||
bytes signature = 1;
|
||||
bytes payload = 2;
|
||||
}
|
142
vendor/github.com/status-im/status-protocol-go/v1/status_message.go
generated
vendored
Normal file
142
vendor/github.com/status-im/status-protocol-go/v1/status_message.go
generated
vendored
Normal 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(©, 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
|
||||
}
|
|
@ -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.
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package state
|
||||
|
||||
// PeerID is the ID for a specific peer.
|
||||
type PeerID [65]byte
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package state
|
||||
|
||||
type MessageID [32]byte
|
||||
type GroupID [32]byte
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -108,7 +108,7 @@ github.com/golang-migrate/migrate/v4/source
|
|||
github.com/golang-migrate/migrate/v4
|
||||
# github.com/golang/mock v1.2.0
|
||||
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/protoc-gen-go/descriptor
|
||||
# github.com/golang/snappy v0.0.1
|
||||
|
@ -152,6 +152,8 @@ github.com/jbenet/goprocess
|
|||
github.com/jbenet/goprocess/context
|
||||
github.com/jbenet/goprocess/periodic
|
||||
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
|
||||
# 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/protocol
|
||||
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/encryption/multidevice
|
||||
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/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/sharedsecret
|
||||
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/encryption/internal/sqlite
|
||||
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/whisperv6
|
||||
# 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/memdb
|
||||
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
|
||||
# github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f
|
||||
|
|
Loading…
Reference in New Issue