forked from iotaledger/goshimmer
/
plugin.go
155 lines (127 loc) · 3.77 KB
/
plugin.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
package webapi
import (
"context"
"fmt"
"net/http"
"time"
"github.com/cockroachdb/errors"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"go.uber.org/dig"
"github.com/izuc/zipp.foundation/core/daemon"
"github.com/izuc/zipp.foundation/core/generics/event"
"github.com/izuc/zipp.foundation/core/logger"
"github.com/izuc/zipp.foundation/core/node"
"github.com/izuc/zipp/packages/node/shutdown"
)
// PluginName is the name of the web API plugin.
const PluginName = "WebAPI"
var (
// Plugin is the plugin instance of the web API plugin.
Plugin *node.Plugin
deps = new(dependencies)
log *logger.Logger
)
type dependencies struct {
dig.In
Server *echo.Echo
}
func init() {
Plugin = node.NewPlugin(PluginName, deps, node.Enabled, configure, run)
Plugin.Events.Init.Hook(event.NewClosure(func(event *node.InitEvent) {
if err := event.Container.Provide(func() *echo.Echo {
server := newServer()
return server
}); err != nil {
Plugin.Panic(err)
}
}))
}
// newServer creates a server instance.
func newServer() *echo.Echo {
server := echo.New()
server.Use(middleware.CORSWithConfig(middleware.CORSConfig{
Skipper: middleware.DefaultSkipper,
AllowOrigins: []string{"*"},
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
}))
// if enabled, configure basic-auth
if Parameters.BasicAuth.Enabled {
server.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
if username == Parameters.BasicAuth.Username &&
password == Parameters.BasicAuth.Password {
return true, nil
}
return false, nil
}))
}
server.HTTPErrorHandler = func(err error, c echo.Context) {
log.Warnf("Request failed: %s", err)
var statusCode int
var block string
switch errors.Unwrap(err) {
case echo.ErrUnauthorized:
statusCode = http.StatusUnauthorized
block = "unauthorized"
case echo.ErrForbidden:
statusCode = http.StatusForbidden
block = "access forbidden"
case echo.ErrInternalServerError:
statusCode = http.StatusInternalServerError
block = "internal server error"
case echo.ErrNotFound:
statusCode = http.StatusNotFound
block = "not found"
case echo.ErrBadRequest:
statusCode = http.StatusBadRequest
block = "bad request"
default:
statusCode = http.StatusInternalServerError
block = "internal server error"
}
block = fmt.Sprintf("%s, error: %+v", block, err)
resErr := c.String(statusCode, block)
if resErr != nil {
log.Warnf("Failed to send error response: %s", resErr)
}
}
return server
}
func configure(*node.Plugin) {
log = logger.NewLogger(PluginName)
// configure the server
deps.Server.HideBanner = true
deps.Server.HidePort = true
deps.Server.GET("/", IndexRequest)
}
func run(*node.Plugin) {
log.Infof("Starting %s ...", PluginName)
if err := daemon.BackgroundWorker("WebAPIServer", worker, shutdown.PriorityWebAPI); err != nil {
log.Panicf("Failed to start as daemon: %s", err)
}
}
func worker(ctx context.Context) {
defer log.Infof("Stopping %s ... done", PluginName)
stopped := make(chan struct{})
bindAddr := Parameters.BindAddress
go func() {
log.Infof("%s started, bind-address=%s, basic-auth=%v", PluginName, bindAddr, Parameters.BasicAuth.Enabled)
if err := deps.Server.Start(bindAddr); err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.Errorf("Error serving: %s", err)
}
close(stopped)
}
}()
// stop if we are shutting down or the server could not be started
select {
case <-ctx.Done():
case <-stopped:
}
log.Infof("Stopping %s ...", PluginName)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := deps.Server.Shutdown(ctx); err != nil {
log.Errorf("Error stopping: %s", err)
}
}