-
Notifications
You must be signed in to change notification settings - Fork 1
/
driver.go
139 lines (123 loc) · 3.09 KB
/
driver.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package native
import (
"flag"
"log"
"net"
"os"
"os/signal"
"path/filepath"
"strconv"
"syscall"
"time"
"github.com/docker/go-connections/sockets"
"github.com/ampchain/go-amp/contractsdk/go/code"
pbrpc "github.com/ampchain/go-amp/contractsdk/go/pbrpc"
"google.golang.org/grpc"
)
const (
AmpChainUnixSocketGid = "AChain_UNIXSOCK_GID"
AmpChainPingTimeout = "AChain_PING_TIMEOUT"
)
func redirectStderr() {
f, err := os.OpenFile("stderr.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
if err == nil {
syscall.Dup2(int(f.Fd()), 2)
f.Close()
}
}
type driver struct {
}
// New returns a native driver
func New() code.Driver {
return new(driver)
}
func (d *driver) Serve(contract code.Contract) {
redirectStderr()
var (
flagset = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
sockpath = flagset.String("sock", "", "the path of unix socket file(if use unix socket)")
chainSockpath = flagset.String("chain-sock", "", "the path of block chain service unix socket file(if use unix socket)")
listenport = flagset.String("port", "", "the listen port(if use tcp)")
)
flagset.Parse(os.Args[1:])
nativeCodeService := newNativeCodeService(*chainSockpath, contract)
rpcServer := grpc.NewServer()
pbrpc.RegisterNativeCodeServer(rpcServer, nativeCodeService)
var err error
var listener net.Listener
if *sockpath != "" {
uid := os.Getuid()
gid := getUnixSocketGroupid()
relpath, err := relPathOfCWD(*sockpath)
if err != nil {
panic(err)
}
listener, err = sockets.NewUnixSocketWithOpts(relpath, sockets.WithChown(uid, gid), sockets.WithChmod(0660))
if err != nil {
panic(err)
}
} else if *listenport != "" {
listener, err = sockets.NewTCPSocket(":"+*listenport, nil)
if err != nil {
panic(err)
}
} else {
panic("empty --sock and --port")
}
go rpcServer.Serve(listener)
sigch := make(chan os.Signal, 2)
signal.Notify(sigch, os.Interrupt, syscall.SIGTERM, syscall.SIGPIPE)
timer := time.NewTicker(1 * time.Second)
running := true
pingTimeout := getPingTimeout()
for running {
select {
case sig := <-sigch:
running = false
log.Print("receive signal ", sig)
case <-timer.C:
lastping := nativeCodeService.LastpingTime()
if time.Since(lastping) > pingTimeout {
log.Print("ping timeout")
running = false
}
}
}
rpcServer.GracefulStop()
nativeCodeService.Close()
log.Print("native code ended")
}
func getUnixSocketGroupid() int {
envgid := os.Getenv(AmpChainUnixSocketGid)
if envgid == "" {
return os.Getgid()
}
gid, err := strconv.Atoi(envgid)
if err != nil {
return os.Getgid()
}
return gid
}
func getPingTimeout() time.Duration {
envtimeout := os.Getenv(AmpChainPingTimeout)
if envtimeout == "" {
return 3 * time.Second
}
timeout, err := strconv.Atoi(envtimeout)
if err != nil {
return 3 * time.Second
}
return time.Duration(timeout) * time.Second
}
//RelPathOfCWD 返回工作目录的相对路径
func relPathOfCWD(rootpath string) (string, error) {
cwd, err := os.Getwd()
if err != nil {
return "", err
}
socketPath, err := filepath.Rel(cwd, rootpath)
if err != nil {
return "", err
}
return socketPath, nil
}