/
resolver.go
167 lines (153 loc) · 4.02 KB
/
resolver.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package cmd
import (
"context"
"net/http"
"os"
"syscall"
"time"
"github.com/algorandfoundation/did-algo/client/internal"
"github.com/algorandfoundation/did-algo/info"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.bryk.io/pkg/cli"
pkgHttp "go.bryk.io/pkg/net/http"
"go.bryk.io/pkg/otel"
"google.golang.org/grpc"
)
var resolverCmd = &cobra.Command{
Use: "resolver",
Short: "Start a standalone resolver server",
RunE: runResolverServer,
Long: `Resolver server
Resolver server provides a DIF compatible endpoint for DID
document resolution. The server endpoint can be used as a
standalone Universal Resolver Driver.
More information:
https://github.com/decentralized-identity/universal-resolver`,
}
func init() {
params := []cli.Param{
{
Name: "port",
Usage: "TCP port to use for the server",
FlagKey: "resolver.port",
ByDefault: 9091,
Short: "p",
},
{
Name: "proxy-protocol",
Usage: "enable support for PROXY protocol",
FlagKey: "resolver.proxy_protocol",
ByDefault: false,
Short: "P",
},
{
Name: "tls",
Usage: "enable secure communications using TLS with provided credentials",
FlagKey: "resolver.tls.enabled",
ByDefault: false,
},
{
Name: "tls-ca",
Usage: "TLS custom certificate authority (path to PEM file)",
FlagKey: "resolver.tls.ca",
ByDefault: "",
},
{
Name: "tls-cert",
Usage: "TLS certificate (path to PEM file)",
FlagKey: "resolver.tls.cert",
ByDefault: "/etc/algoid/tls/tls.crt",
},
{
Name: "tls-key",
Usage: "TLS private key (path to PEM file)",
FlagKey: "resolver.tls.key",
ByDefault: "/etc/algoid/tls/tls.key",
},
{
Name: "agent",
Usage: "Network agent to communicate with",
FlagKey: "resolver.client.node",
ByDefault: internal.DefaultAgentEndpoint,
Short: "a",
},
{
Name: "agent-insecure",
Usage: "Use an insecure connection to the network agent",
FlagKey: "resolver.client.insecure",
ByDefault: false,
},
}
if err := cli.SetupCommandParams(resolverCmd, params, viper.GetViper()); err != nil {
panic(err)
}
rootCmd.AddCommand(resolverCmd)
}
func runResolverServer(cmd *cobra.Command, args []string) error {
// Observability operator
oop, err := otel.NewOperator([]otel.OperatorOption{
otel.WithLogger(log),
otel.WithServiceName("algoid"),
otel.WithServiceVersion(info.CoreVersion),
otel.WithHostMetrics(),
otel.WithRuntimeMetrics(5 * time.Second),
}...)
if err != nil {
return err
}
defer oop.Shutdown(context.Background())
// Load settings
conf := new(internal.ResolverSettings)
conf.Load(viper.GetViper())
// Resolver instance
conn, err := getClientConnection(conf.Client)
if err != nil {
return err
}
rr, err := conf.Resolver(conn)
if err != nil {
return err
}
// Start server
mux := http.NewServeMux()
mux.HandleFunc("/1.0/ping", pingHandler)
mux.HandleFunc("/1.0/ready", resolverReadyHandler(conn))
mux.HandleFunc("/1.0/identifiers/", rr.ResolutionHandler)
srv, err := pkgHttp.NewServer(conf.ServerOpts(mux, releaseCode())...)
if err != nil {
return err
}
go func() {
_ = srv.Start()
}()
// wait for system signals
log.Info("waiting for incoming requests")
<-cli.SignalsHandler([]os.Signal{
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT,
})
// stop server
log.Info("preparing to exit")
err = srv.Stop(true) // prevent further requests
_ = conn.Close() // close internal API client connection
return err
}
// Basic reachability test.
func pingHandler(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("pong"))
}
// Status reported is based on the connection to the agent being used.
func resolverReadyHandler(conn *grpc.ClientConn) func(w http.ResponseWriter, r *http.Request) {
fn := func(w http.ResponseWriter, r *http.Request) {
st := conn.GetState().String()
if st != "READY" && st != "IDLE" {
w.WriteHeader(http.StatusServiceUnavailable)
_, _ = w.Write([]byte(st))
return
}
}
return fn
}