Skip to content

Commit 670efde

Browse files
authored
Persistent connections and unary handlers (#3)
1 parent a5ba1be commit 670efde

15 files changed

Lines changed: 4299 additions & 1193 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.DS_Store
22
.idea/
3+
.vscode/

conn.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ func (d *Daemon) handleConn(c net.Conn) {
146146
return
147147
}
148148

149+
case pb.Request_PERSISTENT_CONN_UPGRADE:
150+
d.handlePersistentConn(r, w)
151+
return
152+
149153
default:
150154
log.Debugw("unexpected request type", "type", req.GetType())
151155
return

daemon.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package p2pd
33
import (
44
"context"
55
"fmt"
6+
"time"
67

78
"os"
89
"sync"
@@ -39,12 +40,28 @@ type Daemon struct {
3940
handlers map[protocol.ID]ma.Multiaddr
4041
// closed is set when the daemon is shutting down
4142
closed bool
43+
44+
registeredUnaryProtocols map[protocol.ID]bool
45+
46+
// callID (int64) to chan *pb.PersistentConnectionResponse
47+
// used to return responses to goroutines awating them
48+
responseWaiters sync.Map
49+
// callID (int64) to chan context.CancelFunc
50+
// used to cancel request handlers
51+
cancelUnary sync.Map
52+
53+
// this sync.Once ensures the goroutine awaiting deamon termination is
54+
// only run once
55+
terminateOnce sync.Once
56+
terminateWG sync.WaitGroup
57+
cancelTerminateTimer context.CancelFunc
4258
}
4359

4460
func NewDaemon(ctx context.Context, maddr ma.Multiaddr, dhtMode string, opts ...libp2p.Option) (*Daemon, error) {
4561
d := &Daemon{
46-
ctx: ctx,
47-
handlers: make(map[protocol.ID]ma.Multiaddr),
62+
ctx: ctx,
63+
handlers: make(map[protocol.ID]ma.Multiaddr),
64+
registeredUnaryProtocols: make(map[protocol.ID]bool),
4865
}
4966

5067
if dhtMode != "" {
@@ -71,7 +88,6 @@ func NewDaemon(ctx context.Context, maddr ma.Multiaddr, dhtMode string, opts ...
7188
}
7289
d.listener = l
7390

74-
go d.listen()
7591
go d.trapSignals()
7692

7793
return d, nil
@@ -134,10 +150,10 @@ func (d *Daemon) Addrs() []ma.Multiaddr {
134150
return d.host.Addrs()
135151
}
136152

137-
func (d *Daemon) listen() {
153+
func (d *Daemon) Serve() error {
138154
for {
139155
if d.isClosed() {
140-
return
156+
return nil
141157
}
142158

143159
c, err := d.listener.Accept()
@@ -191,3 +207,22 @@ func (d *Daemon) Close() error {
191207

192208
return merr.ErrorOrNil()
193209
}
210+
211+
func (d *Daemon) awaitTermination() {
212+
d.terminateWG.Wait()
213+
d.Close()
214+
}
215+
216+
func (d *Daemon) KillOnTimeout(timeout time.Duration) {
217+
go func() {
218+
ctx, cancel := context.WithCancel(d.ctx)
219+
d.cancelTerminateTimer = cancel
220+
221+
select {
222+
case <-ctx.Done():
223+
return
224+
case <-time.NewTimer(timeout).C:
225+
d.Close()
226+
}
227+
}()
228+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.15
55
require (
66
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
77
github.com/gogo/protobuf v1.3.2
8+
github.com/google/uuid v1.3.0
89
github.com/hashicorp/go-multierror v1.1.0
910
github.com/ipfs/go-cid v0.0.7
1011
github.com/ipfs/go-log v1.0.5

go.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,9 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
184184
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
185185
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
186186
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
187-
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
188187
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
188+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
189+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
189190
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
190191
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
191192
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=

internal/utils/safe_writer.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package utils
2+
3+
import (
4+
"sync"
5+
6+
ggio "github.com/gogo/protobuf/io"
7+
"github.com/gogo/protobuf/proto"
8+
)
9+
10+
func NewSafeWriter(w ggio.WriteCloser) *safeWriter {
11+
return &safeWriter{w: w}
12+
}
13+
14+
type safeWriter struct {
15+
w ggio.WriteCloser
16+
m sync.Mutex
17+
}
18+
19+
func (sw *safeWriter) WriteMsg(msg proto.Message) error {
20+
sw.m.Lock()
21+
defer sw.m.Unlock()
22+
return sw.w.WriteMsg(msg)
23+
}
24+
25+
func (sw *safeWriter) Close() error {
26+
sw.m.Lock()
27+
defer sw.m.Unlock()
28+
return sw.w.Close()
29+
}

p2pclient/p2pclient.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ type Client struct {
2626

2727
mhandlers sync.Mutex
2828
handlers map[string]StreamHandlerFunc
29+
30+
openPersistentConn sync.Once
31+
persistentConnWriter ggio.WriteCloser
32+
33+
// callID (uuid.UUID) -> persistentConnectionFuture
34+
callFutures sync.Map
35+
unaryHandlers sync.Map
2936
}
3037

3138
// NewClient creates a new libp2p daemon client, connecting to a daemon

p2pclient/streams.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"net"
99

10+
"github.com/hashicorp/go-multierror"
1011
"github.com/libp2p/go-libp2p-core/peer"
1112

1213
ggio "github.com/gogo/protobuf/io"
@@ -125,11 +126,17 @@ func (c *Client) NewStream(peer peer.ID, protos []string) (*StreamInfo, io.ReadW
125126

126127
// Close stops the listener address.
127128
func (c *Client) Close() error {
129+
merr := &multierror.Error{}
130+
128131
if c.listener != nil {
129-
err := c.listener.Close()
130-
return err
132+
multierror.Append(merr, c.listener.Close())
131133
}
132-
return nil
134+
135+
if c.persistentConnWriter != nil {
136+
multierror.Append(merr, c.persistentConnWriter.Close())
137+
}
138+
139+
return merr.ErrorOrNil()
133140
}
134141

135142
func (c *Client) streamDispatcher() {

0 commit comments

Comments
 (0)