132 lines
2.9 KiB
Go
132 lines
2.9 KiB
Go
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package gossip
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/ssbc/go-muxrpc/v2"
|
|
"go.mindeco.de/encodedTime"
|
|
)
|
|
|
|
// Ping implements the server side of gossip.ping.
|
|
// it's idea is mentioned here https://github.com/ssbc/ssb-gossip/#ping-duplex
|
|
// and implemented by https://github.com/dominictarr/pull-ping/
|
|
func Ping(ctx context.Context, req *muxrpc.Request, peerSrc *muxrpc.ByteSource, peerSnk *muxrpc.ByteSink) error {
|
|
type arg struct {
|
|
// The only argument is the delay between two pings.
|
|
// the Javascript code calls this "timeout", tho.
|
|
Delay int `json:"timeout"`
|
|
}
|
|
|
|
var args []arg
|
|
err := json.Unmarshal(req.RawArgs, &args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// var timeout = time.Minute * 5
|
|
// if len(args) == 1 {
|
|
// timeout = time.Minute * time.Duration(args[0].Timeout/(60*1000))
|
|
// }
|
|
|
|
// return sillyPingPong(ctx, peerSrc, peerSnk)
|
|
return actualPingPong(ctx, peerSrc, peerSnk)
|
|
}
|
|
|
|
// actually just read and write whenever...
|
|
func sillyPingPong(ctx context.Context, peerSrc *muxrpc.ByteSource, peerSnk *muxrpc.ByteSink) error {
|
|
var (
|
|
sendErr = make(chan error)
|
|
receiveErr = make(chan error)
|
|
)
|
|
|
|
go func() {
|
|
peerSnk.SetEncoding(muxrpc.TypeJSON)
|
|
enc := json.NewEncoder(peerSnk)
|
|
|
|
tick := time.NewTicker(5 * time.Second)
|
|
defer tick.Stop()
|
|
|
|
defer close(sendErr)
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-tick.C:
|
|
}
|
|
|
|
var pong = encodedTime.Millisecs(time.Now())
|
|
|
|
if err := enc.Encode(pong); err != nil {
|
|
sendErr <- err
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
defer close(receiveErr)
|
|
|
|
for peerSrc.Next(ctx) {
|
|
var ping encodedTime.Millisecs
|
|
err := peerSrc.Reader(func(rd io.Reader) error {
|
|
return json.NewDecoder(rd).Decode(&ping)
|
|
})
|
|
if err != nil {
|
|
receiveErr <- err
|
|
return
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
}()
|
|
|
|
select {
|
|
case e := <-sendErr:
|
|
return e
|
|
case e := <-receiveErr:
|
|
return e
|
|
case <-ctx.Done():
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// this is how it should work, i think, but it leads to disconnects...
|
|
// From the code it's hard to see but the client sends a timestamp in milliseconds (Date.now() in javascript/json)
|
|
// and the other side responds with it's own timestamp.
|
|
func actualPingPong(ctx context.Context, peerSrc *muxrpc.ByteSource, peerSnk *muxrpc.ByteSink) error {
|
|
peerSnk.SetEncoding(muxrpc.TypeJSON)
|
|
enc := json.NewEncoder(peerSnk)
|
|
|
|
for peerSrc.Next(ctx) {
|
|
var ping encodedTime.Millisecs
|
|
err := peerSrc.Reader(func(rd io.Reader) error {
|
|
return json.NewDecoder(rd).Decode(&ping)
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//when := time.Time(ping)
|
|
//fmt.Printf("got ping: %s - age: %s\n", when.String(), time.Since(when))
|
|
|
|
pong := encodedTime.Millisecs(time.Now())
|
|
err = enc.Encode(pong)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// time.Sleep(timeout)
|
|
}
|
|
|
|
return peerSrc.Err()
|
|
}
|