Skip to content

Commit ba2bb47

Browse files
authored
feat: service discover (#153)
* support tls * remove debug * go mod tidy * make ci green * make ci green * make ci green
1 parent c697f83 commit ba2bb47

File tree

12 files changed

+462
-156
lines changed

12 files changed

+462
-156
lines changed

.codeclimate.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ checks:
1313
threshold: 1000
1414
method-complexity: # 函数和方法的逻辑复杂度
1515
config:
16-
threshold: 12
16+
threshold: 14
1717
method-count: # 结构体的方法限制
1818
config:
1919
threshold: 60

wechaty-puppet-service/ca.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package puppetservice
2+
3+
import "context"
4+
5+
// TLSInsecureServerCertCommonName Common Name:
6+
// - Server Name Indication (SNI)
7+
// - Case insensitive
8+
// Wechaty Token format: `${SNI}/${UUIDv4}`
9+
const TLSInsecureServerCertCommonName = "insecure"
10+
11+
// TLSCaCert Wechaty Certificate Authority Repo:
12+
/* https://github.com/wechaty/dotenv/tree/main/ca
13+
14+
The SSL_ROOT_CERT is a root certificate generated by and for wechaty community.
15+
16+
Because it's the default root cert for the puppet service,
17+
so all the Polyglot Wechaty SDK should set this cert to be trusted by default.
18+
19+
Update:
20+
- Huan(202108): init, expired in 3650 days (after 2031/07)
21+
*/
22+
const TLSCaCert = `-----BEGIN CERTIFICATE-----
23+
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
54+
-----END CERTIFICATE-----`
55+
56+
type callCredToken struct {
57+
token string
58+
}
59+
60+
func (r callCredToken) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
61+
return map[string]string{
62+
"authorization": "Wechaty " + r.token,
63+
}, nil
64+
}
65+
66+
func (r callCredToken) RequireTransportSecurity() bool {
67+
return true
68+
}

wechaty-puppet-service/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ var (
1515
WechatyPuppetHostieEndpoint string
1616

1717
// WechatyPuppetServiceToken ...
18+
// Deprecated
1819
WechatyPuppetServiceToken string
1920

2021
// WechatyPuppetServiceEndpoint ...
22+
// Deprecated
2123
WechatyPuppetServiceEndpoint string
2224
)
2325

wechaty-puppet-service/envvars.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package puppetservice
2+
3+
import (
4+
"errors"
5+
"os"
6+
)
7+
8+
// ErrTokenNotFound err token not found
9+
var ErrTokenNotFound = errors.New("wechaty-puppet-service: WECHATY_PUPPET_SERVICE_TOKEN not found")
10+
11+
func envServiceToken(token string) (string, error) {
12+
if token != "" {
13+
return token, nil
14+
}
15+
16+
token = os.Getenv("WECHATY_PUPPET_SERVICE_TOKEN")
17+
if token != "" {
18+
return token, nil
19+
}
20+
21+
token = os.Getenv("WECHATY_PUPPET_HOSTIE_ENDPOINT")
22+
if token != "" {
23+
log.Trace("WECHATY_PUPPET_HOSTIE_TOKEN has been deprecated," +
24+
"please use WECHATY_PUPPET_SERVICE_TOKEN instead.")
25+
return token, nil
26+
}
27+
28+
return "", ErrTokenNotFound
29+
}
30+
31+
func envEndpoint(endpoint string) string {
32+
if endpoint != "" {
33+
return endpoint
34+
}
35+
36+
endpoint = os.Getenv("WECHATY_PUPPET_SERVICE_ENDPOINT")
37+
if endpoint != "" {
38+
return endpoint
39+
}
40+
41+
endpoint = os.Getenv("WECHATY_PUPPET_HOSTIE_ENDPOINT")
42+
if endpoint != "" {
43+
log.Println("WECHATY_PUPPET_HOSTIE_ENDPOINT has been deprecated," +
44+
"please use WECHATY_PUPPET_SERVICE_ENDPOINT instead.")
45+
return endpoint
46+
}
47+
return ""
48+
}
49+
50+
func envAuthority(authority string) string {
51+
if authority != "" {
52+
return authority
53+
}
54+
55+
authority = os.Getenv("WECHATY_PUPPET_SERVICE_AUTHORITY")
56+
if authority != "" {
57+
return authority
58+
}
59+
60+
return "api.chatie.io"
61+
}
62+
63+
func envNoTLSInsecureClient(disable bool) bool {
64+
return disable || os.Getenv("WECHATY_PUPPET_SERVICE_NO_TLS_INSECURE_CLIENT") == "true"
65+
}
66+
67+
func envTLSServerName(serverName string) string {
68+
if serverName != "" {
69+
return serverName
70+
}
71+
72+
return os.Getenv("WECHATY_PUPPET_SERVICE_TLS_SERVER_NAME")
73+
}
74+
75+
func envTLSCaCert(caCert string) string {
76+
if caCert != "" {
77+
return caCert
78+
}
79+
caCert = os.Getenv("WECHATY_PUPPET_SERVICE_TLS_CA_CERT")
80+
if caCert != "" {
81+
return caCert
82+
}
83+
return TLSCaCert
84+
}

wechaty-puppet-service/grpc.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package puppetservice
2+
3+
import (
4+
pbwechaty "github.com/wechaty/go-grpc/wechaty"
5+
"google.golang.org/grpc"
6+
"google.golang.org/grpc/connectivity"
7+
"google.golang.org/grpc/credentials"
8+
"google.golang.org/grpc/credentials/insecure"
9+
"time"
10+
)
11+
12+
func (p *PuppetService) startGrpcClient() error {
13+
var err error
14+
var creds credentials.TransportCredentials
15+
var callOptions []grpc.CallOption
16+
if p.disableTLS {
17+
// TODO 目前不支持 tls,不用打印这个提醒
18+
//log.Warn("PuppetService.startGrpcClient TLS: disabled (INSECURE)")
19+
creds = insecure.NewCredentials()
20+
} else {
21+
callOptions = append(callOptions, grpc.PerRPCCredentials(callCredToken{token: p.token}))
22+
creds, err = p.createCred()
23+
if err != nil {
24+
return err
25+
}
26+
}
27+
28+
dialOptions := []grpc.DialOption{
29+
grpc.WithTransportCredentials(creds),
30+
grpc.WithDefaultCallOptions(callOptions...),
31+
grpc.WithResolvers(wechatyResolver()),
32+
}
33+
34+
if p.disableTLS {
35+
// Deprecated: this block will be removed after Dec 21, 2022.
36+
dialOptions = append(dialOptions, grpc.WithAuthority(p.token))
37+
}
38+
39+
conn, err := grpc.Dial(p.endpoint, dialOptions...)
40+
if err != nil {
41+
return err
42+
}
43+
p.grpcConn = conn
44+
45+
go p.autoReconnectGrpcConn()
46+
47+
p.grpcClient = pbwechaty.NewPuppetClient(conn)
48+
return nil
49+
}
50+
51+
func (p *PuppetService) autoReconnectGrpcConn() {
52+
<-p.started
53+
isClose := false
54+
ticker := p.newGrpcReconnectTicket()
55+
defer ticker.Stop()
56+
for {
57+
select {
58+
case <-ticker.C:
59+
connState := p.grpcConn.GetState()
60+
// 重新连接成功
61+
if isClose && connectivity.Ready == connState {
62+
isClose = false
63+
log.Warn("PuppetService.autoReconnectGrpcConn grpc reconnection successful")
64+
if err := p.startGrpcStream(); err != nil {
65+
log.Errorf("PuppetService.autoReconnectGrpcConn startGrpcStream err:%s", err.Error())
66+
}
67+
}
68+
69+
if p.grpcConn.GetState() == connectivity.Idle {
70+
isClose = true
71+
p.grpcConn.Connect()
72+
log.Warn("PuppetService.autoReconnectGrpcConn grpc reconnection...")
73+
}
74+
case <-p.stop:
75+
return
76+
}
77+
}
78+
}
79+
80+
func (p *PuppetService) newGrpcReconnectTicket() *time.Ticker {
81+
interval := 2 * time.Second
82+
if p.opts.GrpcReconnectInterval > 0 {
83+
interval = p.opts.GrpcReconnectInterval
84+
}
85+
return time.NewTicker(interval)
86+
}

wechaty-puppet-service/options.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package puppetservice
2+
3+
import (
4+
wechatypuppet "github.com/wechaty/go-wechaty/wechaty-puppet"
5+
"time"
6+
)
7+
8+
// TLSConfig tls config
9+
type TLSConfig struct {
10+
CaCert string
11+
ServerName string
12+
13+
Disable bool // only for compatible with old clients/servers
14+
}
15+
16+
// Options puppet-service options
17+
type Options struct {
18+
wechatypuppet.Option
19+
20+
GrpcReconnectInterval time.Duration
21+
Authority string
22+
TLS TLSConfig
23+
}

0 commit comments

Comments
 (0)