initial import
This commit is contained in:
170
example/http/breaker/client/client.go
Normal file
170
example/http/breaker/client/client.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"zero/core/lang"
|
||||
"zero/core/threading"
|
||||
|
||||
"gopkg.in/cheggaaa/pb.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
freq = flag.Int("freq", 100, "frequence")
|
||||
duration = flag.String("duration", "10s", "duration")
|
||||
)
|
||||
|
||||
type (
|
||||
counting struct {
|
||||
ok int
|
||||
fail int
|
||||
reject int
|
||||
errs int
|
||||
unknown int
|
||||
}
|
||||
|
||||
metric struct {
|
||||
counting
|
||||
lock sync.Mutex
|
||||
}
|
||||
)
|
||||
|
||||
func (m *metric) addOk() {
|
||||
m.lock.Lock()
|
||||
m.ok++
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *metric) addFail() {
|
||||
m.lock.Lock()
|
||||
m.ok++
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *metric) addReject() {
|
||||
m.lock.Lock()
|
||||
m.ok++
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *metric) addErrs() {
|
||||
m.lock.Lock()
|
||||
m.errs++
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *metric) addUnknown() {
|
||||
m.lock.Lock()
|
||||
m.unknown++
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
func (m *metric) reset() counting {
|
||||
m.lock.Lock()
|
||||
result := counting{
|
||||
ok: m.ok,
|
||||
fail: m.fail,
|
||||
reject: m.reject,
|
||||
errs: m.errs,
|
||||
unknown: m.unknown,
|
||||
}
|
||||
|
||||
m.ok = 0
|
||||
m.fail = 0
|
||||
m.reject = 0
|
||||
m.errs = 0
|
||||
m.unknown = 0
|
||||
m.lock.Unlock()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func runRequests(url string, frequence int, metrics *metric, done <-chan lang.PlaceholderType) {
|
||||
ticker := time.NewTicker(time.Second / time.Duration(frequence))
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
go func() {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
metrics.addErrs()
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
metrics.addOk()
|
||||
case http.StatusInternalServerError:
|
||||
metrics.addFail()
|
||||
case http.StatusServiceUnavailable:
|
||||
metrics.addReject()
|
||||
default:
|
||||
metrics.addUnknown()
|
||||
}
|
||||
}()
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
fp, err := os.Create("result.csv")
|
||||
lang.Must(err)
|
||||
defer fp.Close()
|
||||
fmt.Fprintln(fp, "seconds,goodOk,goodFail,goodReject,goodErrs,goodUnknowns,goodDropRatio,"+
|
||||
"heavyOk,heavyFail,heavyReject,heavyErrs,heavyUnknowns,heavyDropRatio")
|
||||
|
||||
var gm, hm metric
|
||||
dur, err := time.ParseDuration(*duration)
|
||||
lang.Must(err)
|
||||
done := make(chan lang.PlaceholderType)
|
||||
group := threading.NewRoutineGroup()
|
||||
group.RunSafe(func() {
|
||||
runRequests("http://localhost:8080/heavy", *freq, &hm, done)
|
||||
})
|
||||
group.RunSafe(func() {
|
||||
runRequests("http://localhost:8080/good", *freq, &gm, done)
|
||||
})
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
var seconds int
|
||||
for range ticker.C {
|
||||
seconds++
|
||||
g := gm.reset()
|
||||
h := hm.reset()
|
||||
fmt.Fprintf(fp, "%d,%d,%d,%d,%d,%d,%.1f,%d,%d,%d,%d,%d,%.1f\n",
|
||||
seconds, g.ok, g.fail, g.reject, g.errs, g.unknown,
|
||||
float32(g.reject)/float32(g.ok+g.fail+g.reject+g.unknown),
|
||||
h.ok, h.fail, h.reject, h.errs, h.unknown,
|
||||
float32(h.reject)/float32(h.ok+h.fail+h.reject+h.unknown))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
bar := pb.New(int(dur / time.Second)).Start()
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
bar.Increment()
|
||||
}
|
||||
bar.Finish()
|
||||
}()
|
||||
|
||||
<-time.After(dur)
|
||||
close(done)
|
||||
group.Wait()
|
||||
time.Sleep(time.Millisecond * 900)
|
||||
}
|
||||
3
example/http/breaker/good.sh
Normal file
3
example/http/breaker/good.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
hey -z 60s http://localhost:8080/good
|
||||
3
example/http/breaker/heavy.sh
Normal file
3
example/http/breaker/heavy.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
hey -z 60s http://localhost:8080/heavy
|
||||
59
example/http/breaker/server.go
Normal file
59
example/http/breaker/server.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"zero/core/logx"
|
||||
"zero/core/service"
|
||||
"zero/core/stat"
|
||||
"zero/core/syncx"
|
||||
"zero/ngin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logx.Disable()
|
||||
stat.SetReporter(nil)
|
||||
server := ngin.MustNewEngine(ngin.NgConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Name: "breaker",
|
||||
Log: logx.LogConf{
|
||||
Mode: "console",
|
||||
},
|
||||
},
|
||||
Host: "0.0.0.0",
|
||||
Port: 8080,
|
||||
MaxConns: 1000,
|
||||
Timeout: 3000,
|
||||
})
|
||||
latch := syncx.NewLimit(10)
|
||||
server.AddRoute(ngin.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/heavy",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
if latch.TryBorrow() {
|
||||
defer latch.Return()
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
begin := time.Now()
|
||||
for {
|
||||
if time.Now().Sub(begin) > time.Millisecond*50 {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
},
|
||||
})
|
||||
server.AddRoute(ngin.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/good",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
},
|
||||
})
|
||||
defer server.Stop()
|
||||
server.Start()
|
||||
}
|
||||
5
example/http/breaker/start.sh
Normal file
5
example/http/breaker/start.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
GOOS=linux go build -ldflags="-s -w" server.go
|
||||
docker run --rm -it --cpus=1 -p 8080:8080 -v `pwd`:/app -w /app alpine /app/server
|
||||
rm -f server
|
||||
56
example/http/crypt/crypt.go
Normal file
56
example/http/crypt/crypt.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"zero/core/codec"
|
||||
)
|
||||
|
||||
const (
|
||||
pubKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD7bq4FLG0ctccbEFEsUBuRxkjE
|
||||
eJ5U+0CAEjJk20V9/u2Fu76i1oKoShCs7GXtAFbDb5A/ImIXkPY62nAaxTGK4KVH
|
||||
miYbRgh5Fy6336KepLCtCmV/r0PKZeCyJH9uYLs7EuE1z9Hgm5UUjmpHDhJtkAwR
|
||||
my47YlhspwszKdRP+wIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
body = "hello"
|
||||
)
|
||||
|
||||
var key = []byte("q4t7w!z%C*F-JaNdRgUjXn2r5u8x/A?D")
|
||||
|
||||
func main() {
|
||||
encrypter, err := codec.NewRsaEncrypter([]byte(pubKey))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
decrypter, err := codec.NewRsaDecrypter("private.pem")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
output, err := encrypter.Encrypt([]byte(body))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
actual, err := decrypter.Decrypt(output)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(actual)
|
||||
|
||||
out, err := codec.EcbEncrypt(key, []byte(body))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := codec.EcbDecrypt(key, out)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(string(ret))
|
||||
}
|
||||
70
example/http/demo/main.go
Normal file
70
example/http/demo/main.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/http"
|
||||
|
||||
"zero/core/httpx"
|
||||
"zero/core/logx"
|
||||
"zero/core/service"
|
||||
"zero/ngin"
|
||||
)
|
||||
|
||||
var (
|
||||
port = flag.Int("port", 3333, "the port to listen")
|
||||
timeout = flag.Int64("timeout", 0, "timeout of milliseconds")
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
User string `form:"user,options=a|b"`
|
||||
}
|
||||
|
||||
func first(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("X-Middleware", "first")
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func second(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("X-Middleware", "second")
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
var req Request
|
||||
err := httpx.Parse(r, &req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
httpx.OkJson(w, "helllo, "+req.User)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
engine := ngin.MustNewEngine(ngin.NgConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Log: logx.LogConf{
|
||||
Mode: "console",
|
||||
},
|
||||
},
|
||||
Port: *port,
|
||||
Timeout: *timeout,
|
||||
MaxConns: 500,
|
||||
})
|
||||
defer engine.Stop()
|
||||
|
||||
engine.Use(first)
|
||||
engine.Use(second)
|
||||
engine.AddRoute(ngin.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: handle,
|
||||
})
|
||||
engine.Start()
|
||||
}
|
||||
65
example/http/post/main.go
Normal file
65
example/http/post/main.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"zero/core/httpx"
|
||||
"zero/core/logx"
|
||||
"zero/core/service"
|
||||
"zero/ngin"
|
||||
)
|
||||
|
||||
var (
|
||||
port = flag.Int("port", 3333, "the port to listen")
|
||||
timeout = flag.Int64("timeout", 0, "timeout of milliseconds")
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
func handleGet(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func handlePost(w http.ResponseWriter, r *http.Request) {
|
||||
var req Request
|
||||
err := httpx.Parse(r, &req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
httpx.OkJson(w, fmt.Sprintf("Content-Length: %d, UserLen: %d", r.ContentLength, len(req.User)))
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
engine := ngin.MustNewEngine(ngin.NgConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Log: logx.LogConf{
|
||||
Mode: "console",
|
||||
},
|
||||
},
|
||||
Port: *port,
|
||||
Timeout: *timeout,
|
||||
MaxConns: 500,
|
||||
MaxBytes: 50,
|
||||
CpuThreshold: 500,
|
||||
})
|
||||
defer engine.Stop()
|
||||
|
||||
engine.AddRoute(ngin.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: handleGet,
|
||||
})
|
||||
engine.AddRoute(ngin.Route{
|
||||
Method: http.MethodPost,
|
||||
Path: "/",
|
||||
Handler: handlePost,
|
||||
})
|
||||
engine.Start()
|
||||
}
|
||||
11
example/http/shedding/Dockerfile
Normal file
11
example/http/shedding/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM alpine
|
||||
|
||||
RUN apk update --no-cache
|
||||
RUN apk add --no-cache ca-certificates
|
||||
RUN apk add --no-cache tzdata
|
||||
ENV TZ Asia/Shanghai
|
||||
|
||||
WORKDIR /app
|
||||
COPY main /app/main
|
||||
|
||||
CMD ["./main"]
|
||||
63
example/http/shedding/main.go
Normal file
63
example/http/shedding/main.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"zero/core/httpx"
|
||||
"zero/core/logx"
|
||||
"zero/core/service"
|
||||
"zero/ngin"
|
||||
)
|
||||
|
||||
var (
|
||||
port = flag.Int("port", 3333, "the port to listen")
|
||||
timeout = flag.Int64("timeout", 1000, "timeout of milliseconds")
|
||||
cpu = flag.Int64("cpu", 500, "cpu threshold")
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
User string `form:"user,optional"`
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
var req Request
|
||||
err := httpx.Parse(r, &req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var result float64
|
||||
for i := 0; i < 30000; i++ {
|
||||
result += math.Sqrt(float64(i))
|
||||
}
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
httpx.OkJson(w, result)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
logx.Disable()
|
||||
engine := ngin.MustNewEngine(ngin.NgConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Log: logx.LogConf{
|
||||
Mode: "console",
|
||||
},
|
||||
},
|
||||
Port: *port,
|
||||
Timeout: *timeout,
|
||||
CpuThreshold: *cpu,
|
||||
})
|
||||
defer engine.Stop()
|
||||
|
||||
engine.AddRoute(ngin.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/",
|
||||
Handler: handle,
|
||||
})
|
||||
engine.Start()
|
||||
}
|
||||
113
example/http/signature/client/client.go
Normal file
113
example/http/signature/client/client.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"zero/core/codec"
|
||||
)
|
||||
|
||||
const pubKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD7bq4FLG0ctccbEFEsUBuRxkjE
|
||||
eJ5U+0CAEjJk20V9/u2Fu76i1oKoShCs7GXtAFbDb5A/ImIXkPY62nAaxTGK4KVH
|
||||
miYbRgh5Fy6336KepLCtCmV/r0PKZeCyJH9uYLs7EuE1z9Hgm5UUjmpHDhJtkAwR
|
||||
my47YlhspwszKdRP+wIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
var (
|
||||
crypt = flag.Bool("crypt", false, "encrypt body or not")
|
||||
key = []byte("q4t7w!z%C*F-JaNdRgUjXn2r5u8x/A?D")
|
||||
)
|
||||
|
||||
func fingerprint(key string) string {
|
||||
h := md5.New()
|
||||
io.WriteString(h, key)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func hs256(key []byte, body string) string {
|
||||
h := hmac.New(sha256.New, key)
|
||||
io.WriteString(h, body)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
body := "hello world!"
|
||||
if *crypt {
|
||||
bodyBytes, err := codec.EcbEncrypt(key, []byte(body))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
body = base64.StdEncoding.EncodeToString(bodyBytes)
|
||||
}
|
||||
|
||||
r, err := http.NewRequest(http.MethodPost, "http://localhost:3333/a/b?c=first&d=second", strings.NewReader(body))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
sha := sha256.New()
|
||||
sha.Write([]byte(body))
|
||||
bodySign := fmt.Sprintf("%x", sha.Sum(nil))
|
||||
contentOfSign := strings.Join([]string{
|
||||
strconv.FormatInt(timestamp, 10),
|
||||
http.MethodPost,
|
||||
r.URL.Path,
|
||||
r.URL.RawQuery,
|
||||
bodySign,
|
||||
}, "\n")
|
||||
sign := hs256(key, contentOfSign)
|
||||
var mode string
|
||||
if *crypt {
|
||||
mode = "1"
|
||||
} else {
|
||||
mode = "0"
|
||||
}
|
||||
content := strings.Join([]string{
|
||||
"version=v1",
|
||||
"type=" + mode,
|
||||
fmt.Sprintf("key=%s", base64.StdEncoding.EncodeToString(key)),
|
||||
"time=" + strconv.FormatInt(timestamp, 10),
|
||||
}, "; ")
|
||||
|
||||
encrypter, err := codec.NewRsaEncrypter([]byte(pubKey))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
output, err := encrypter.Encrypt([]byte(content))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
encryptedContent := base64.StdEncoding.EncodeToString(output)
|
||||
r.Header.Set("X-Content-Security", strings.Join([]string{
|
||||
fmt.Sprintf("key=%s", fingerprint(pubKey)),
|
||||
"secret=" + encryptedContent,
|
||||
"signature=" + sign,
|
||||
}, "; "))
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(r)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
fmt.Println(resp.Status)
|
||||
io.Copy(os.Stdout, resp.Body)
|
||||
}
|
||||
59
example/http/signature/server/server.go
Normal file
59
example/http/signature/server/server.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"zero/core/httpx"
|
||||
"zero/core/logx"
|
||||
"zero/core/service"
|
||||
"zero/ngin"
|
||||
)
|
||||
|
||||
var keyPem = flag.String("prikey", "private.pem", "the private key file")
|
||||
|
||||
type Request struct {
|
||||
User string `form:"user,optional"`
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
var req Request
|
||||
err := httpx.Parse(r, &req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
io.Copy(w, r.Body)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
engine := ngin.MustNewEngine(ngin.NgConf{
|
||||
ServiceConf: service.ServiceConf{
|
||||
Log: logx.LogConf{
|
||||
Path: "logs",
|
||||
},
|
||||
},
|
||||
Port: 3333,
|
||||
Signature: ngin.SignatureConf{
|
||||
Strict: true,
|
||||
PrivateKeys: []ngin.PrivateKeyConf{
|
||||
{
|
||||
Fingerprint: "bvw8YlnSqb+PoMf3MBbLdQ==",
|
||||
KeyFile: *keyPem,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
defer engine.Stop()
|
||||
|
||||
engine.AddRoute(ngin.Route{
|
||||
Method: http.MethodPost,
|
||||
Path: "/a/b",
|
||||
Handler: handle,
|
||||
})
|
||||
engine.Start()
|
||||
}
|
||||
Reference in New Issue
Block a user