2023-07-11 05:07:44 +00:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2023-08-21 09:49:32 +00:00
|
|
|
|
"crypto/tls"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"fmt"
|
2023-09-19 11:16:26 +00:00
|
|
|
|
"fusenapi/utils/fsconfig"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"io"
|
2023-08-10 09:31:45 +00:00
|
|
|
|
"io/ioutil"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"log"
|
|
|
|
|
"net"
|
|
|
|
|
"net/http"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
"net/http/httputil"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"net/url"
|
2023-07-19 02:59:13 +00:00
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
"strings"
|
2023-07-12 06:11:04 +00:00
|
|
|
|
"sync"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"time"
|
2023-07-19 02:59:13 +00:00
|
|
|
|
|
2023-08-10 09:41:36 +00:00
|
|
|
|
"github.com/gorilla/websocket"
|
2023-07-19 02:59:13 +00:00
|
|
|
|
"gopkg.in/yaml.v2"
|
2023-09-21 03:57:31 +00:00
|
|
|
|
|
|
|
|
|
_ "fusenapi/utils/auth"
|
|
|
|
|
_ "fusenapi/utils/autoconfig"
|
|
|
|
|
_ "fusenapi/utils/check"
|
|
|
|
|
_ "fusenapi/utils/collect"
|
|
|
|
|
_ "fusenapi/utils/encryption_decryption"
|
|
|
|
|
_ "fusenapi/utils/fsconfig"
|
|
|
|
|
_ "fusenapi/utils/fssql"
|
|
|
|
|
|
|
|
|
|
_ "github.com/zeromicro/go-zero/rest"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
)
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// Backend结构体
|
2023-07-11 05:07:44 +00:00
|
|
|
|
var Backends []*Backend
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 设置跨域请求
|
2023-07-11 10:48:22 +00:00
|
|
|
|
func SetCors(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
|
|
|
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
|
|
|
|
w.Header().Set("Access-Control-Expose-Headers", "*")
|
|
|
|
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
|
|
|
|
|
|
|
|
// 如果请求方法为 OPTIONS,直接返回 200 状态码
|
|
|
|
|
if r.Method == "OPTIONS" {
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 存储路径的并发安全的Map
|
2023-07-12 06:11:04 +00:00
|
|
|
|
var pathdict sync.Map = sync.Map{}
|
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
func main() {
|
2023-08-21 09:49:32 +00:00
|
|
|
|
log.SetFlags(log.Llongfile)
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 将静态资源路径存储到pathdict
|
2023-07-12 06:11:04 +00:00
|
|
|
|
pathdict.Store("/css", true)
|
|
|
|
|
pathdict.Store("/fonts", true)
|
|
|
|
|
pathdict.Store("/img", true)
|
|
|
|
|
pathdict.Store("/js", true)
|
|
|
|
|
pathdict.Store("/svg", true)
|
|
|
|
|
pathdict.Store("/favicon.ico", true)
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
rootDir := "../server" // 更改为你的根目录
|
2023-07-12 06:23:10 +00:00
|
|
|
|
vueBuild := "/opt/fusenpack-vue-created"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
apiURL, err := url.Parse("http://localhost:9900")
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2023-07-11 05:07:44 +00:00
|
|
|
|
|
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 获取并解析服务信息
|
2023-07-11 05:07:44 +00:00
|
|
|
|
results := GetZeroInfo(rootDir)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
|
|
|
|
|
var allRoutes map[string]bool = make(map[string]bool)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
for _, result := range results {
|
|
|
|
|
fmt.Printf("FolderName: %s, Host: %s, Port: %d, PrefixRoute: %v\n", result.FolderName, result.Host, result.Port, result.PrefixRoute)
|
|
|
|
|
var routes []string
|
|
|
|
|
for k := range result.PrefixRoute {
|
|
|
|
|
routes = append(routes, k)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
allRoutes[k] = true
|
2023-07-11 05:07:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 根据获取的服务信息创建后端服务
|
2023-07-11 05:07:44 +00:00
|
|
|
|
Backends = append(Backends,
|
|
|
|
|
NewBackend(mux,
|
|
|
|
|
fmt.Sprintf("http://%s:%d", result.Host, result.Port),
|
|
|
|
|
routes...))
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 06:41:57 +00:00
|
|
|
|
Backends = append(Backends, NewBackend(mux,
|
|
|
|
|
fmt.Sprintf("http://%s:%d", "localhost", 9501),
|
|
|
|
|
"/api/v1/namespaces/kubernetes-dashboard"))
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 定义用于服务Vue dist文件夹的静态文件服务器
|
2023-07-11 08:50:18 +00:00
|
|
|
|
fs := http.FileServer(http.Dir(vueBuild))
|
2023-07-11 10:48:22 +00:00
|
|
|
|
indexHtmlPath := vueBuild + "/index.html"
|
|
|
|
|
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2023-07-18 05:04:29 +00:00
|
|
|
|
if strings.HasPrefix(r.URL.Path, "/api/") {
|
2023-09-22 02:53:05 +00:00
|
|
|
|
r.ParseMultipartForm(100 << 20)
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 对/api开头的请求进行反向代理
|
2023-07-11 08:50:18 +00:00
|
|
|
|
proxy := httputil.NewSingleHostReverseProxy(apiURL)
|
|
|
|
|
proxy.ServeHTTP(w, r)
|
2023-07-18 05:04:29 +00:00
|
|
|
|
return
|
2023-07-11 08:50:18 +00:00
|
|
|
|
} else {
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 根据请求路径判断是服务静态文件或者是返回index.html
|
2023-07-12 06:11:04 +00:00
|
|
|
|
idx := strings.Index(r.URL.Path[1:], "/")
|
|
|
|
|
var prefix string
|
|
|
|
|
if idx != -1 {
|
|
|
|
|
prefix = r.URL.Path[:idx+1]
|
2023-07-11 08:50:18 +00:00
|
|
|
|
} else {
|
2023-07-12 06:11:04 +00:00
|
|
|
|
prefix = r.URL.Path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, ok := pathdict.Load(prefix); ok {
|
2023-07-11 08:50:18 +00:00
|
|
|
|
fs.ServeHTTP(w, r)
|
2023-07-12 06:11:04 +00:00
|
|
|
|
} else {
|
|
|
|
|
http.ServeFile(w, r, indexHtmlPath)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
}
|
2023-07-12 06:11:04 +00:00
|
|
|
|
|
2023-07-11 08:50:18 +00:00
|
|
|
|
}
|
2023-07-11 10:48:22 +00:00
|
|
|
|
}))
|
2023-07-11 08:50:18 +00:00
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
ServerAddress := ":9900"
|
|
|
|
|
log.Println("listen on ", ServerAddress)
|
2023-08-21 09:49:32 +00:00
|
|
|
|
|
2023-09-19 11:16:26 +00:00
|
|
|
|
envcfg := fsconfig.GetEnvCofing()
|
|
|
|
|
|
|
|
|
|
keydata, err := os.ReadFile(envcfg.ProxyServer.KeyFile)
|
2023-08-21 09:49:32 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 11:16:26 +00:00
|
|
|
|
pemdata, err := os.ReadFile(envcfg.ProxyServer.PemFile)
|
2023-08-21 09:49:32 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cert, err := tls.X509KeyPair(pemdata, keydata)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tlscfg := &tls.Config{
|
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
|
MinVersion: tls.VersionTLS12,
|
|
|
|
|
MaxVersion: tls.VersionTLS13,
|
|
|
|
|
}
|
|
|
|
|
serv := http.Server{
|
|
|
|
|
Addr: ServerAddress,
|
|
|
|
|
Handler: mux,
|
|
|
|
|
TLSConfig: tlscfg,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Fatal(serv.ListenAndServeTLS("", ""))
|
2023-07-11 05:07:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 后端服务的类型
|
2023-07-11 05:07:44 +00:00
|
|
|
|
type Backend struct {
|
|
|
|
|
HttpAddress string
|
|
|
|
|
Client *http.Client
|
|
|
|
|
Handler http.HandlerFunc
|
2023-08-10 09:41:36 +00:00
|
|
|
|
Dialer *websocket.Dialer
|
2023-07-11 05:07:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Backend {
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 如果路径最后没有以'/'结尾,则添加'/'
|
2023-07-11 05:07:44 +00:00
|
|
|
|
for i, muxPath := range muxPaths {
|
|
|
|
|
if muxPath[len(muxPath)-1] != '/' {
|
|
|
|
|
muxPath = muxPath + "/"
|
|
|
|
|
muxPaths[i] = muxPath
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 创建HTTP客户端,设置相关的超时参数和连接数限制
|
2023-07-11 05:07:44 +00:00
|
|
|
|
client := &http.Client{
|
|
|
|
|
Transport: &http.Transport{
|
|
|
|
|
DialContext: (&net.Dialer{
|
2023-08-21 11:07:02 +00:00
|
|
|
|
Timeout: 300 * time.Second,
|
2023-07-19 02:59:13 +00:00
|
|
|
|
KeepAlive: 60 * time.Second,
|
2023-07-11 05:07:44 +00:00
|
|
|
|
}).DialContext,
|
|
|
|
|
ForceAttemptHTTP2: true,
|
|
|
|
|
MaxIdleConns: 100,
|
|
|
|
|
MaxIdleConnsPerHost: 100,
|
2023-08-21 11:07:02 +00:00
|
|
|
|
IdleConnTimeout: 300 * time.Second,
|
|
|
|
|
TLSHandshakeTimeout: 300 * time.Second,
|
2023-07-11 05:07:44 +00:00
|
|
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 创建后端服务对象,包含地址和客户端
|
2023-07-11 05:07:44 +00:00
|
|
|
|
backend := &Backend{
|
|
|
|
|
HttpAddress: httpAddress,
|
|
|
|
|
Client: client,
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 创建处理请求的函数
|
2023-07-11 05:07:44 +00:00
|
|
|
|
handleRequest := func(w http.ResponseWriter, r *http.Request) {
|
2023-08-10 09:41:36 +00:00
|
|
|
|
|
|
|
|
|
if websocket.IsWebSocketUpgrade(r) {
|
|
|
|
|
//todo: 建立websocket的代理
|
|
|
|
|
|
2023-08-10 10:30:02 +00:00
|
|
|
|
target := url.URL{Scheme: "ws", Host: strings.Split(backend.HttpAddress, "//")[1], Path: r.URL.Path}
|
2023-08-10 09:41:36 +00:00
|
|
|
|
|
|
|
|
|
var transfer = func(src, dest *websocket.Conn) {
|
2023-09-22 04:03:04 +00:00
|
|
|
|
defer src.Close()
|
|
|
|
|
defer dest.Close()
|
|
|
|
|
// TODO: 可以做错误处理
|
2023-08-10 09:41:36 +00:00
|
|
|
|
for {
|
|
|
|
|
mType, msg, err := src.ReadMessage()
|
|
|
|
|
if err != nil {
|
2023-08-10 10:30:02 +00:00
|
|
|
|
log.Println(err)
|
2023-09-22 04:03:04 +00:00
|
|
|
|
return
|
2023-08-10 09:41:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = dest.WriteMessage(mType, msg)
|
|
|
|
|
if err != nil {
|
2023-08-10 10:30:02 +00:00
|
|
|
|
log.Println(err)
|
2023-09-22 04:03:04 +00:00
|
|
|
|
return
|
2023-08-10 09:41:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-10 10:30:02 +00:00
|
|
|
|
header := r.Header.Clone()
|
|
|
|
|
// log.Println(target.String())
|
|
|
|
|
header.Del("Sec-Websocket-Extensions")
|
|
|
|
|
header.Del("Upgrade")
|
|
|
|
|
header.Del("Sec-Websocket-Key")
|
|
|
|
|
header.Del("Sec-Websocket-Version")
|
|
|
|
|
header.Del("Connection")
|
2023-08-21 07:27:24 +00:00
|
|
|
|
|
2023-08-10 10:30:02 +00:00
|
|
|
|
// header.Del("Origin")
|
|
|
|
|
proxyConn, _, err := backend.Dialer.Dial(target.String(), header)
|
2023-08-10 09:41:36 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
2023-08-10 10:30:02 +00:00
|
|
|
|
// defer proxyConn.Close()
|
2023-08-10 09:41:36 +00:00
|
|
|
|
|
2023-08-10 10:30:02 +00:00
|
|
|
|
upgrader := websocket.Upgrader{
|
|
|
|
|
CheckOrigin: func(r *http.Request) bool { return true },
|
|
|
|
|
}
|
2023-08-10 09:41:36 +00:00
|
|
|
|
conn, err := upgrader.Upgrade(w, r, nil)
|
|
|
|
|
if err != nil {
|
2023-09-22 03:55:39 +00:00
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-08-10 09:41:36 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
2023-08-10 10:30:02 +00:00
|
|
|
|
// defer conn.Close()
|
2023-08-10 09:41:36 +00:00
|
|
|
|
|
|
|
|
|
go transfer(proxyConn, conn)
|
2023-08-10 10:30:02 +00:00
|
|
|
|
// go transfer(conn, proxyConn)
|
|
|
|
|
return
|
2023-08-10 09:41:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 解析目标URL,包含了查询参数
|
2023-07-18 05:04:29 +00:00
|
|
|
|
targetURL, err := url.Parse(httpAddress + r.URL.String())
|
2023-07-11 05:07:44 +00:00
|
|
|
|
if err != nil {
|
2023-09-22 03:55:39 +00:00
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 创建新的请求
|
2023-07-11 05:07:44 +00:00
|
|
|
|
proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body)
|
|
|
|
|
if err != nil {
|
2023-09-22 03:55:39 +00:00
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 复制原始请求的 Header
|
|
|
|
|
for key, values := range r.Header {
|
|
|
|
|
for _, value := range values {
|
|
|
|
|
proxyReq.Header.Add(key, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置 Content-Length 和 Content-Type
|
|
|
|
|
proxyReq.ContentLength = r.ContentLength
|
|
|
|
|
proxyReq.Header.Set("Content-Type", r.Header.Get("Content-Type"))
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 发送请求
|
2023-07-11 05:07:44 +00:00
|
|
|
|
resp, err := backend.Client.Do(proxyReq)
|
|
|
|
|
if err != nil {
|
2023-09-22 03:55:39 +00:00
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
// 复制目标服务器的响应 Header
|
|
|
|
|
for key, values := range resp.Header {
|
|
|
|
|
for _, value := range values {
|
|
|
|
|
w.Header().Add(key, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 转发目标服务器的响应状态码和主体
|
|
|
|
|
w.WriteHeader(resp.StatusCode)
|
|
|
|
|
_, err = io.Copy(w, resp.Body)
|
|
|
|
|
if err != nil {
|
2023-09-22 03:55:39 +00:00
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-11 11:43:46 +00:00
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 为每个路径注册处理函数
|
2023-07-11 05:07:44 +00:00
|
|
|
|
for _, muxPath := range muxPaths {
|
|
|
|
|
mux.HandleFunc(muxPath, handleRequest)
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 11:43:43 +00:00
|
|
|
|
// 返回后端服务对象
|
2023-07-11 05:07:44 +00:00
|
|
|
|
return backend
|
|
|
|
|
}
|
2023-07-19 02:59:13 +00:00
|
|
|
|
|
|
|
|
|
// get_zero_info.go
|
|
|
|
|
|
|
|
|
|
// Config 结构体用于解析yaml配置文件
|
|
|
|
|
type Config struct {
|
|
|
|
|
Host string `yaml:"Host"`
|
|
|
|
|
Port int `yaml:"Port"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Result 结构体用于存储解析结果
|
|
|
|
|
type Result struct {
|
|
|
|
|
FolderName string
|
|
|
|
|
Host string
|
|
|
|
|
Port int
|
|
|
|
|
PrefixRoute map[string]bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetZeroInfo 遍历指定目录,并解析相关信息
|
|
|
|
|
func GetZeroInfo(rootDir string) (results []*Result) {
|
2023-08-10 09:31:45 +00:00
|
|
|
|
entries, err := ioutil.ReadDir(rootDir)
|
2023-07-19 02:59:13 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
|
// 只处理目录类型
|
|
|
|
|
if entry.IsDir() {
|
|
|
|
|
result, err := findFoldersAndExtractInfo(rootDir, entry)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
results = append(results, result)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findFoldersAndExtractInfo 查找目录并提取信息
|
2023-08-10 09:31:45 +00:00
|
|
|
|
func findFoldersAndExtractInfo(rootDir string, entry os.FileInfo) (*Result, error) {
|
2023-07-19 02:59:13 +00:00
|
|
|
|
var result *Result
|
|
|
|
|
|
|
|
|
|
folderName := entry.Name()
|
|
|
|
|
path := filepath.Join(rootDir, folderName)
|
|
|
|
|
|
|
|
|
|
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 跳过非目录类型
|
|
|
|
|
if !info.IsDir() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
relPath, err := filepath.Rel(path, path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 跳过非当前目录的子目录
|
|
|
|
|
if strings.Contains(relPath, string(os.PathSeparator)) {
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取配置文件
|
|
|
|
|
configPath := filepath.Join(path, "etc", folderName+".yaml")
|
|
|
|
|
routesPath := filepath.Join(path, "internal", "handler", "routes.go")
|
|
|
|
|
|
2023-08-10 09:31:45 +00:00
|
|
|
|
configContent, err := ioutil.ReadFile(configPath)
|
2023-07-19 02:59:13 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var config Config
|
|
|
|
|
err = yaml.Unmarshal(configContent, &config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取路由文件
|
2023-08-10 09:31:45 +00:00
|
|
|
|
routesContent, err := ioutil.ReadFile(routesPath)
|
2023-07-19 02:59:13 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PrefixRoute := extractPrefixRouteValues(string(routesContent))
|
|
|
|
|
|
|
|
|
|
// 构建结果
|
|
|
|
|
result = &Result{
|
|
|
|
|
FolderName: folderName,
|
|
|
|
|
Host: config.Host,
|
|
|
|
|
Port: config.Port,
|
|
|
|
|
PrefixRoute: PrefixRoute,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extractPrefixRouteValues 提取路由前缀
|
|
|
|
|
func extractPrefixRouteValues(content string) map[string]bool {
|
|
|
|
|
lines := strings.Split(content, "\n")
|
|
|
|
|
var prefixPath map[string]bool = make(map[string]bool)
|
|
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
|
// 查找包含 "Path:" 的行
|
|
|
|
|
if strings.Contains(line, "Path:") {
|
|
|
|
|
path := strings.TrimSpace(strings.TrimPrefix(line, "Path:"))
|
|
|
|
|
paths := strings.Split(strings.Trim(path, `"`), "/")
|
|
|
|
|
path1 := "/" + paths[1] + "/" + paths[2]
|
|
|
|
|
|
|
|
|
|
if _, ok := prefixPath[path1]; !ok {
|
|
|
|
|
prefixPath[path1] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prefixPath
|
|
|
|
|
}
|