/
dial.go
108 lines (94 loc) · 2.66 KB
/
dial.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright 2013 Tumblr, Inc.
// Use of this source code is governed by the license for
// The Go Circuit Project, found in the LICENSE file.
//
// Authors:
// 2013 Petar Maymounkov <p@gocircuit.org>
package lang
import (
//"fmt"
//"runtime/debug"
"github.com/gocircuit/circuit/sys/lang/types"
"github.com/gocircuit/circuit/use/circuit"
"github.com/gocircuit/circuit/use/n"
)
func (r *Runtime) Listen(service string, receiver interface{}) {
if IsX(receiver) {
panic("listen service receiver cannot be a cross-interface")
}
types.RegisterValue(receiver)
r.srv.Add(service, receiver)
}
// Dial returns an ptr to the permanent xvalue of the addressed remote runtime.
// It panics if any errors get in the way.
func (r *Runtime) Dial(addr n.Addr, service string) circuit.PermX {
if addr == nil {
return nil
}
ptr, err := r.TryDial(addr, service)
if err != nil {
panic(err)
}
return ptr
}
// TryDial returns an ptr to the permanent xvalue of the addressed remote runtime
func (r *Runtime) TryDial(addr n.Addr, service string) (circuit.PermX, error) {
conn, err := r.t.Dial(addr)
if err != nil {
return nil, err
}
defer conn.Close()
retrn, err := writeReturn(conn, &dialMsg{Service: service})
if err != nil {
return nil, err
}
return r.importEitherPtr(retrn, addr)
}
func (r *Runtime) DialSelf(service string) interface{} {
return r.srv.Get(service)
}
func (r *Runtime) serveDial(req *dialMsg, conn n.Conn) {
// Go guarantees the defer runs even if panic occurs
defer conn.Close()
expDial, _ := r.exportValues([]interface{}{PermRef(r.srv.Get(req.Service))}, conn.Addr())
conn.Write(&returnMsg{Out: expDial})
// Waiting for export acks not necessary since expDial is always a permptr.
}
// Utils
func writeReturn(conn n.Conn, msg interface{}) ([]interface{}, error) {
if err := conn.Write(msg); err != nil {
return nil, err
}
reply, err := conn.Read()
if err != nil {
return nil, err
}
retrn, ok := reply.(*returnMsg)
if !ok {
return nil, NewError("foreign return type")
}
if retrn.Err != nil {
return nil, err
}
return retrn.Out, nil
}
func (r *Runtime) importEitherPtr(retrn []interface{}, exporter n.Addr) (circuit.PermX, error) {
//debug.PrintStack()
//println(fmt.Sprintf("retrn=%v exporter=%v", retrn, exporter))
out, err := r.importValues(retrn, nil, exporter, false, nil)
if err != nil {
return nil, err
}
if len(out) != 1 {
return nil, NewError("unexpected return value count")
}
if out[0] == nil {
return nil, nil
}
ptr, ok := out[0].(circuit.PermX)
if !ok {
return nil, NewError("value is not a permanent cross-interface")
}
// XXX: Shouldn't this also have a case for non-permanent crossreferences?
return ptr, nil
}