代码拉取完成,页面将自动刷新
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"io/ioutil"
"net/http"
"os"
"os/signal"
"path"
"path/filepath"
"plugin"
"strings"
"time"
"gitee.com/jason_elva8325/apigw-quickstart/common"
"gitee.com/jason_elva8325/apigw-quickstart/config"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/sd/etcdv3"
"github.com/gorilla/mux"
)
var (
confFile = flag.String("conf-file", "", "Host path of TOML format config file. If this param set, other params will be lose efficacy")
listenHost = flag.String("listen-host", "0.0.0.0", "TCP listen host")
httpPort = flag.String("http-port", "", "HTTP listen port")
httpCaCert = flag.String("http-ca-cert", "", "HTTPS root cert file")
httpCert = flag.String("http-cert", "", "HTTPS cert file")
httpKey = flag.String("http-key", "", "HTTPS cert key file")
verifyClientCert = flag.Bool("verify-client-cert", false, "Force verify client certification")
srdETCDServers = flag.String("srd-etcd-servers", "127.0.0.1:2379", "Comma-separated ETCD server addresses for Service Discovery & Registry. Example: '127.0.0.1:2379,127.0.0.1:13279'")
srdETCDCaCert = flag.String("srd-etcd-ca-cert", "", "ETCD client access root cert file path for Service Discovery & Registry")
srdETCDCert = flag.String("srd-etcd-cert", "", "ETCD client access cert file path for Service Discovery & Registry")
srdETCDKey = flag.String("srd-etcd-key", "", "ETCD client access cert's key file path for Service Discovery & Registry")
srdPrefix = flag.String("srd-prefix", "/svc/", "Service Discovery & Registry Prefix")
adapterDir = flag.String("adapter-dir", "", "Adapter files store location")
gracefulTimeout = flag.Duration("graceful-timeout", time.Duration(15)*time.Second, "Graceful shutdown timeout")
logger log.Logger
)
func init() {
// 全局日志对象定义
logger = log.NewJSONLogger(os.Stderr)
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
logger = log.With(logger, "caller", log.DefaultCaller)
}
func main() {
flag.Parse()
// 生成服务配置对象
conf := parseConfigure()
// 生成ETCD客户端连接
client, err := etcdv3.NewClient(context.Background(), strings.Split(conf.Common.SRDETCDServers, ","), etcdv3.ClientOptions{
DialTimeout: time.Second * 3,
DialKeepAlive: time.Second * 3,
CACert: conf.Common.SRDETCDCaCert,
Cert: conf.Common.SRDETCDCert,
Key: conf.Common.SRDETCDKey,
})
if err != nil {
logger.Log("Service regist to ETCD server fail", err)
os.Exit(1)
}
// 添加日志中间件及API列表信息查询
router := mux.NewRouter().PathPrefix("/api").Subrouter()
router.Use(headerInitMiddleware)
router.Use(loggingMiddleware)
router.HandleFunc("", func(w http.ResponseWriter, r *http.Request) {
// 利用router的walk功能遍历API接口
var apis = make([]common.APIResume, 0)
err := router.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
var api common.APIResume
pathTemplate, err := route.GetPathTemplate()
if err == nil {
api.Route = pathTemplate
}
pathRegexp, err := route.GetPathRegexp()
if err == nil {
api.PathRegexp = pathRegexp
}
queriesTemplates, err := route.GetQueriesTemplates()
if err == nil {
api.QueriesTemplates = strings.Join(queriesTemplates, ",")
}
queriesRegexps, err := route.GetQueriesRegexp()
if err == nil {
api.QueriesRegexps = strings.Join(queriesRegexps, ",")
}
methods, err := route.GetMethods()
if err == nil {
api.Methods = strings.Join(methods, ",")
}
apis = append(apis, api)
return nil
})
if err != nil {
logger.Log("API Index get fail", err)
w.WriteHeader(http.StatusExpectationFailed)
} else {
w.WriteHeader(http.StatusOK)
}
json.NewEncoder(w).Encode(apis)
}).Methods("GET")
// 获取adapter文件列表
if conf.Common.AdapterDir == "" {
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
logger.Log("Adapter absolutly file path get fail", err)
os.Exit(1)
}
conf.Common.AdapterDir = dir
} else {
dir, err := filepath.Abs(filepath.Dir(conf.Common.AdapterDir))
if err != nil {
logger.Log("Adapter absolutly file path get fail", err)
os.Exit(1)
}
conf.Common.AdapterDir = dir
}
rd, err := ioutil.ReadDir(conf.Common.AdapterDir)
if err != nil {
logger.Log("Read adapters from path fail", err)
os.Exit(1)
}
// 循环载入所有adapter
var adapterCnt = 0
for _, fi := range rd {
if !fi.IsDir() && path.Ext(fi.Name()) == ".so" {
p, err := plugin.Open(conf.Common.AdapterDir + "/" + fi.Name())
if err != nil {
logger.Log("adapter file open fail", err)
os.Exit(1)
}
f, err := p.Lookup("AdapterRegistry")
if err != nil {
logger.Log("adapter registry func get fail", err)
os.Exit(1)
}
f.(func(*mux.Router, log.Logger, etcdv3.Client, string, map[string]config.Adapter))(router, logger, client, *srdPrefix, conf.Adapters)
adapterCnt++
} else {
logger.Log("ignore file in adapter path", fi.Name())
}
}
logger.Log("Adapter load path", conf.Common.AdapterDir, "Load adapter count", adapterCnt)
// 启动HTTP监听
httpServe := &http.Server{
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: router,
}
// 判断是否启用SSL
if conf.Common.HTTPCert != "" && conf.Common.HTTPKey != "" {
// 如果没有指定HTTPS端口,默认为443端口
if conf.Common.HTTPPort == "" {
conf.Common.HTTPPort = "443"
}
httpServe.Addr = conf.Common.ListenHost + ":" + conf.Common.HTTPPort
httpServe.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS11,
}
// 判断是否开启客户端证书校验
if conf.Common.VerifyClientCert == true {
httpServe.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
// 判断是否载入私有验证(根)证书
if conf.Common.HTTPCACert != "" {
pool := x509.NewCertPool()
caData, err := ioutil.ReadFile(conf.Common.HTTPCACert)
if err != nil {
logger.Log("SSL Root Cert file load fail", err)
os.Exit(1)
}
pool.AppendCertsFromPEM(caData)
httpServe.TLSConfig.ClientCAs = pool
}
}
go func() {
if err := httpServe.ListenAndServeTLS(conf.Common.HTTPCert, conf.Common.HTTPKey); err != nil && err != http.ErrServerClosed {
logger.Log("HTTPS serve fail", err)
os.Exit(1)
}
}()
} else {
// 如果没有指定HTTP端口,默认为80端口
if conf.Common.HTTPPort == "" {
conf.Common.HTTPPort = "80"
}
httpServe.Addr = conf.Common.ListenHost + ":" + conf.Common.HTTPPort
go func() {
if err := httpServe.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Log("HTTP serve fail", err)
os.Exit(1)
}
}()
}
// 以下为优雅关闭过程
c := make(chan os.Signal, 1)
// 仅在接收到 SIGINT (Ctrl+C) 时才优雅的关闭
// 捕捉到 SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) 时不做处理
signal.Notify(c, os.Interrupt)
// 阻塞直至接收到信号
<-c
// 设置优雅关闭的超时时间(秒)
ctx, cancel := context.WithTimeout(context.Background(), conf.Common.GracefulTimeout)
defer cancel()
// 如果没有连接则直接关闭,否则需要等到关闭的超时时间
httpServe.Shutdown(ctx)
logger.Log("graceful shutdown", "true")
os.Exit(0)
}
// 生成服务配置对象
func parseConfigure() *config.ConfigFile {
// 当配置文件设置不为空时,优先使用配置文件内容
if strings.Trim(*confFile, " ") != "" {
return config.ParseConfigFile(*confFile, logger)
}
return &config.ConfigFile{
Common: &config.CommonConfig{
ListenHost: *listenHost,
HTTPPort: *httpPort,
HTTPCACert: *httpCaCert,
HTTPCert: *httpCert,
HTTPKey: *httpKey,
VerifyClientCert: *verifyClientCert,
SRDETCDServers: *srdETCDServers,
SRDETCDCaCert: *srdETCDCaCert,
SRDETCDCert: *srdETCDCert,
SRDETCDKey: *srdETCDKey,
SRDPrefix: *srdPrefix,
AdapterDir: *adapterDir,
GracefulTimeout: *gracefulTimeout,
},
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。