mirror of
https://github.com/PeernetOfficial/Cmd.git
synced 2026-07-17 02:47:52 +01:00
Add exit codes documentation. Add documentation to reduce binary file size. Implement /shutdown API endpoint for a graceful shutdown.
This commit is contained in:
74
API.go
74
API.go
@@ -8,11 +8,15 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core"
|
||||
"github.com/PeernetOfficial/core/webapi"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
@@ -28,12 +32,25 @@ func startAPI() {
|
||||
} else if len(config.APIListen) != 0 {
|
||||
// API settings via config file.
|
||||
webapi.Start(config.APIListen, config.APIUseSSL, config.APICertificateFile, config.APICertificateKey, parseDuration(config.APITimeoutRead), parseDuration(config.APITimeoutWrite))
|
||||
return
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
webapi.Router.HandleFunc("/console", apiConsole).Methods("GET")
|
||||
webapi.Router.HandleFunc("/shutdown", apiShutdown).Methods("GET")
|
||||
}
|
||||
|
||||
// parseCmdParamWebapi parses a "-webapi=" command line parameter
|
||||
func parseCmdParamWebapi() (apiListen []string) {
|
||||
var param string
|
||||
flag.StringVar(¶m, "webapi", "", "Specify the list of IP:Ports for the webapi to listen. Example: -webapi=127.0.0.1:1234")
|
||||
flag.Parse()
|
||||
|
||||
if len(param) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return strings.Split(param, ",")
|
||||
}
|
||||
|
||||
// parseDuration is the same as time.ParseDuration without returning an error. Valid units are ms, s, m, h. For example "10s".
|
||||
@@ -44,6 +61,7 @@ func parseDuration(input string) (result time.Duration) {
|
||||
|
||||
/*
|
||||
apiConsole provides a websocket to send/receive internal commands
|
||||
|
||||
Request: GET /console
|
||||
Result: 200 with JSON structure apiResponsePeerSelf
|
||||
*/
|
||||
@@ -100,15 +118,53 @@ func apiConsole(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// parseCmdParamWebapi parses a "-webapi=" command line parameter
|
||||
func parseCmdParamWebapi() (apiListen []string) {
|
||||
var param string
|
||||
flag.StringVar(¶m, "webapi", "", "Specify the list of IP:Ports for the webapi to listen. Example: -webapi=127.0.0.1:1234")
|
||||
flag.Parse()
|
||||
/*
|
||||
apiShutdown gracefully shuts down the application. Actions: 0 = Shutdown.
|
||||
|
||||
if len(param) == 0 {
|
||||
return nil
|
||||
Request: GET /shutdown?action=[action]
|
||||
Result: 200 with JSON structure apiShutdownStatus
|
||||
*/
|
||||
func apiShutdown(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
action, err := strconv.Atoi(r.Form.Get("action"))
|
||||
if err != nil || action != 0 {
|
||||
http.Error(w, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
return strings.Split(param, ",")
|
||||
if action == 0 {
|
||||
// Later: Initiate shutdown signal to core library and wait for all requests to complete.
|
||||
|
||||
core.Filters.LogError("apiShutdown", "Graceful shutdown via API requested from '%s'\n", r.RemoteAddr)
|
||||
|
||||
EncodeJSONFlush(w, r, &apiShutdownStatus{Status: 0})
|
||||
|
||||
os.Exit(core.ExitGraceful)
|
||||
}
|
||||
}
|
||||
|
||||
type apiShutdownStatus struct {
|
||||
Status int `json:"status"` // Status of the API call. 0 = Success.
|
||||
}
|
||||
|
||||
// EncodeJSONFlush encodes the data as JSON and flushes the writer. It sets the Content-Length header so no subsequent writes should be made.
|
||||
func EncodeJSONFlush(w http.ResponseWriter, r *http.Request, data interface{}) (err error) {
|
||||
response, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
core.Filters.LogError("EncodeJSONFlush", "Error marshalling data for route '%s': %v\n", r.URL.Path, err)
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
_, err = w.Write(response)
|
||||
|
||||
// Flushing the buffer immediately is needed in case the application exits immediately after this call.
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
9
Main.go
9
Main.go
@@ -31,22 +31,27 @@ var config struct {
|
||||
|
||||
func init() {
|
||||
if status, err := core.LoadConfigOut(configFile, &config); err != nil {
|
||||
var exitCode int
|
||||
switch status {
|
||||
case 0:
|
||||
exitCode = core.ExitErrorConfigAccess
|
||||
fmt.Printf("Unknown error accessing config file '%s': %s\n", configFile, err.Error())
|
||||
case 1:
|
||||
exitCode = core.ExitErrorConfigRead
|
||||
fmt.Printf("Error reading config file '%s': %s\n", configFile, err.Error())
|
||||
case 2:
|
||||
exitCode = core.ExitErrorConfigParse
|
||||
fmt.Printf("Error parsing config file '%s' (make sure it is valid YAML format): %s\n", configFile, err.Error())
|
||||
default:
|
||||
exitCode = core.ExitErrorConfigAccess
|
||||
fmt.Printf("Unknown error loading config file '%s': %s\n", configFile, err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
if err := core.InitLog(); err != nil {
|
||||
fmt.Printf("Error opening log file: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
os.Exit(core.ExitErrorLogInit)
|
||||
}
|
||||
|
||||
monitorKeys = make(map[string]struct{})
|
||||
|
||||
26
README.md
26
README.md
@@ -6,12 +6,18 @@ This client can be used as root peer to help speed up discovery of peers and dat
|
||||
|
||||
## Compile
|
||||
|
||||
To build:
|
||||
Download the [latest version of Go](https://golang.org/dl/). To build:
|
||||
|
||||
```
|
||||
go build
|
||||
```
|
||||
|
||||
To reduce the binary size provide the linker switch -s which will "Omit the symbol table and debug information". This reduced the Windows binary by 26% in a test.
|
||||
|
||||
```
|
||||
go build -ldflags "-s"
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
The config filename is hard-coded to `Config.yaml` and is created on the first run. Please see the core library for individual settings to change.
|
||||
@@ -70,3 +76,21 @@ APICertificateKey: "certificate.key" # Private Key
|
||||
APITimeoutRead: "10m" # The maximum duration for reading the entire request, including the body. In this example 10 minutes.
|
||||
APITimeoutWrite: "10m" # The maximum duration before timing out writes of the response. This includes processing time and is therefore the max time any HTTP function may take.
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The application exits in case of the errors listed below and uses the specified exit code. Applications that launch this application can monitor for those exit codes. End users should look into the log file for additional information in case any of these errors occur, although some of them are pre log file initialization.
|
||||
|
||||
| Exit Code | Constant | Info |
|
||||
| ---------- | ---------------------- | --------------------------------------------------- |
|
||||
| 0 | ExitSuccess | This is actually never used. |
|
||||
| 1 | ExitErrorConfigAccess | Error accessing the config file. |
|
||||
| 2 | ExitErrorConfigRead | Error reading the config file. |
|
||||
| 3 | ExitErrorConfigParse | Error parsing the config file. |
|
||||
| 4 | ExitErrorLogInit | Error initializing log file. |
|
||||
| 5 | ExitParamWebapiInvalid | Parameter for webapi is invalid. |
|
||||
| 6 | ExitPrivateKeyCorrupt | Private key is corrupt. |
|
||||
| 7 | ExitPrivateKeyCreate | Cannot create a new private key. |
|
||||
| 8 | ExitBlockchainCorrupt | Blockchain is corrupt. |
|
||||
| 9 | ExitGraceful | Graceful shutdown. |
|
||||
| 0xC000013A | STATUS_CONTROL_C_EXIT | The application terminated as a result of a CTRL+C. |
|
||||
|
||||
2
go.mod
2
go.mod
@@ -3,6 +3,6 @@ module github.com/PeernetOfficial/Cmd
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/PeernetOfficial/core v0.0.0-20211114213707-9626fa80882d
|
||||
github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65
|
||||
github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
||||
github.com/PeernetOfficial/core v0.0.0-20211114213707-9626fa80882d h1:PzpGyK69XH6j+lRVVB173jz3i7sU+Q+lx59vw43UGxM=
|
||||
github.com/PeernetOfficial/core v0.0.0-20211114213707-9626fa80882d/go.mod h1:0D/jIDYdV0WXg5WACS+fR5keafLhYB89WUs6ZEE8t4Y=
|
||||
github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65 h1:WD3/HFSv4+z/hxD5fAXrShgwbtcC8tigre3tQN9Ck8c=
|
||||
github.com/PeernetOfficial/core v0.0.0-20211115020024-d06c2e0b1a65/go.mod h1:0D/jIDYdV0WXg5WACS+fR5keafLhYB89WUs6ZEE8t4Y=
|
||||
github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w=
|
||||
github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
|
||||
Reference in New Issue
Block a user