Skip to content

Commit

Permalink
Dial outbound connection
Browse files Browse the repository at this point in the history
It's not possible to dial an outbound connection which connects to the
event loop exactly like inbound connection.
  • Loading branch information
tidwall committed Nov 7, 2017
1 parent 7499153 commit 7da2f5a
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 219 deletions.
45 changes: 40 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,17 @@ events.Tick = func() (delay time.Duration, action Action){

### Wake up

A connection can be woken up using the `wake` function that is made available through the `Serving` event. This is useful for when you need to offload an operation to a background goroutine and then later notify the event loop that it's time to send some data.
A connection can be woken up using the `Wake` function that is made available through the `Serving` event. This is useful for when you need to offload an operation to a background goroutine and then later notify the event loop that it's time to send some data.

Example echo server that when encountering the line "exec" it waits 5 seconds before responding.

```go
var wake func(id int) bool
var srv evio.Server
var mu sync.Mutex
var execs = make(map[int]int)

events.Serving = func(wakefn func(id int) bool, addrs []net.Addr) (action evio.Action) {
wake = wakefn // hang on to the wake function
events.Serving = func(srvin evio.Server) (action evio.Action) {
srv = srvin // hang on to the server control, which has the Wake function
return
}
events.Data = func(id int, in []byte) (out []byte, action evio.Action) {
Expand All @@ -143,7 +143,7 @@ events.Data = func(id int, in []byte) (out []byte, action evio.Action) {
mu.Lock()
execs[id]++
mu.Unlock()
wake(id)
srv.Wake(id)
}()
} else {
out = in
Expand All @@ -152,6 +152,41 @@ events.Data = func(id int, in []byte) (out []byte, action evio.Action) {
}
```

### Dialing out

An outbound connection can created by using the `Dial` function that is
made available through the `Serving` event. Dialing a new connection will
return a new connection ID and attach that connection to the event loop in
the same manner as incoming connections. This operation is completely
non-blocking including any DNS resolution.

All new outbound connection attempts will immediately fire an `Opened`
event and end with a `Closed` event. A failed connection will send the
connection error through the `Closed` event.

```go
var srv evio.Server
var mu sync.Mutex
var execs = make(map[int]int)

events.Serving = func(srvin evio.Server) (action evio.Action) {
srv = srvin // hang on to the server control, which has the Dial function
return
}
events.Data = func(id int, in []byte) (out []byte, action evio.Action) {
if string(in) == "dial\r\n" {
id := srv.Dial("tcp://google.com:80")
// We now established an outbound connection to google.
// Treat it like you would incoming connection.
} else {
out = in
}
return
}
```



### Data translations

The `Translate` function wraps events and provides a `ReadWriter` that can be used to translate data off the wire from one format to another. This can be useful for transparently adding compression or encryption.
Expand Down
10 changes: 5 additions & 5 deletions evio.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ type Server struct {
// server and returns a new connection id. The new connection is added
// to the event loop and is managed exactly the same way as all the
// other connections. This operation only fails if the server/loop has
// been shut down. When `ok` is true there will always be exactly one
// Opened and one Closed event following this call. Look for socket
// errors from the Closed event.
Dial func(addr string, timeout time.Duration) (id int, ok bool)
// been shut down. An `id` that is not zero means the operation succeeded
// and then there always be exactly one Opened and one Closed event
// following this call. Look for socket errors from the Closed event.
Dial func(addr string, timeout time.Duration) (id int)
}

// Events represents the server events for the Serve call.
Expand Down Expand Up @@ -112,7 +112,7 @@ type Events struct {
// Addresses should use a scheme prefix and be formatted
// like `tcp://192.168.0.10:9851` or `unix://socket`.
// Valid network schemes:
// tcp - bind to both IPv4 and IPv6
// tcp - bind to both IPv4 and IPv6
// tcp4 - IPv4
// tcp6 - IPv6
// unix - Unix Domain Socket
Expand Down
6 changes: 3 additions & 3 deletions evio_loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ func serve(events Events, lns []*listener) error {
idconn := make(map[int]*unixConn)
timeoutqueue := internal.NewTimeoutQueue()
var id int
dial := func(addr string, timeout time.Duration) (int, bool) {
dial := func(addr string, timeout time.Duration) int {
lock()
if done {
unlock()
return 0, false
return 0
}
id++
c := &unixConn{id: id, opening: true}
Expand Down Expand Up @@ -207,7 +207,7 @@ func serve(events Events, lns []*listener) error {
}

}()
return id, true
return id
}

// wake wakes up a connection
Expand Down
Loading

0 comments on commit 7da2f5a

Please sign in to comment.