174 lines
4.5 KiB
Go
174 lines
4.5 KiB
Go
|
package main
|
|||
|
|
|||
|
import (
|
|||
|
"database/sql"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"github.com/gin-gonic/gin"
|
|||
|
_ "github.com/mattn/go-sqlite3"
|
|||
|
"log"
|
|||
|
"net/http"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
// MappingInfo 用于存储映射信息
|
|||
|
type MappingInfo struct {
|
|||
|
RuleName string `json:"rule_name"`
|
|||
|
IpAddr string `json:"ip_addr"`
|
|||
|
Ip string `json:"ip"`
|
|||
|
Port string `json:"port"`
|
|||
|
LastUpdate time.Time `json:"last_update"`
|
|||
|
}
|
|||
|
|
|||
|
// 全局变量,存储所有映射信息
|
|||
|
var mappings = make(map[string]*MappingInfo)
|
|||
|
|
|||
|
var db *sql.DB
|
|||
|
var dbFileName = "./mappings.db" // 数据库文件名
|
|||
|
var tableName = "mappings" // 数据库表名
|
|||
|
var query = `SELECT name FROM sqlite_master WHERE type='table' AND name=?;` // 查询表是否存在的SQL语句
|
|||
|
var createTableSQL = `CREATE TABLE IF NOT EXISTS ` + tableName + ` (
|
|||
|
"RuleName" TEXT PRIMARY KEY,
|
|||
|
"IPAddress" TEXT,
|
|||
|
"Ip" TEXT,
|
|||
|
"Port" TEXT,
|
|||
|
"LastUpdate" TEXT
|
|||
|
);` // 创建表的SQL语句
|
|||
|
|
|||
|
func main() {
|
|||
|
InitDB() // 初始化数据库
|
|||
|
defer func(db *sql.DB) {
|
|||
|
err := db.Close()
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
}(db)
|
|||
|
|
|||
|
router := gin.Default()
|
|||
|
|
|||
|
// 处理Webhook的路由
|
|||
|
router.POST("/webhook", func(c *gin.Context) {
|
|||
|
var info MappingInfo
|
|||
|
if err := c.BindJSON(&info); err != nil {
|
|||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|||
|
return
|
|||
|
}
|
|||
|
info.LastUpdate = time.Now()
|
|||
|
// 输出一下info
|
|||
|
fmt.Println(info)
|
|||
|
mappings[info.RuleName] = &info
|
|||
|
updateMapping(info) // 更新数据库中的映射信息
|
|||
|
c.JSON(http.StatusOK, gin.H{"status": "updated"})
|
|||
|
})
|
|||
|
|
|||
|
// 提供Web服务的路由,展示映射信息
|
|||
|
router.GET("/mappings", func(c *gin.Context) {
|
|||
|
c.JSON(http.StatusOK, mappings)
|
|||
|
})
|
|||
|
|
|||
|
// 根据RuleName查询映射信息
|
|||
|
router.GET("/mappings/:RuleName", func(c *gin.Context) {
|
|||
|
serviceName := c.Param("RuleName")
|
|||
|
if info, exists := mappings[serviceName]; exists {
|
|||
|
c.JSON(http.StatusOK, info)
|
|||
|
} else {
|
|||
|
c.JSON(http.StatusNotFound, gin.H{"code": http.StatusNotFound, "error": "service not found"})
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 根据RuleName跳转到映射的服务
|
|||
|
router.GET("/:RuleName", func(c *gin.Context) {
|
|||
|
serviceName := c.Param("RuleName")
|
|||
|
if info, exists := mappings[serviceName]; exists {
|
|||
|
url := "http://" + info.Ip + ":" + info.Port
|
|||
|
c.Redirect(http.StatusMovedPermanently, url)
|
|||
|
} else {
|
|||
|
c.JSON(http.StatusNotFound, gin.H{"code": http.StatusNotFound, "error": "service not found"})
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
// 启动定时任务,检查映射信息更新
|
|||
|
go checkMappings()
|
|||
|
|
|||
|
err := router.Run(":8080")
|
|||
|
if err != nil {
|
|||
|
return
|
|||
|
} // 在8080端口启动服务
|
|||
|
}
|
|||
|
|
|||
|
// 定时检查映射信息是否需要更新
|
|||
|
func checkMappings() {
|
|||
|
for {
|
|||
|
time.Sleep(24 * time.Hour) // 每天检查一次
|
|||
|
for _, info := range mappings {
|
|||
|
if time.Since(info.LastUpdate) > 24*time.Hour {
|
|||
|
// 如果超过一天没有更新,则主动查询API(这里需要实现API查询逻辑)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func InitDB() {
|
|||
|
log.Println("Init DB...")
|
|||
|
var err error
|
|||
|
db, err = sql.Open("sqlite3", dbFileName)
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
|
|||
|
err = db.QueryRow(query, tableName).Scan(&tableName)
|
|||
|
if errors.Is(err, sql.ErrNoRows) {
|
|||
|
log.Println("Table not exists, create it...")
|
|||
|
createTable()
|
|||
|
} else if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
} else {
|
|||
|
// 读取数据库中的映射信息
|
|||
|
mappings = readMappings()
|
|||
|
fmt.Println(mappings)
|
|||
|
}
|
|||
|
log.Println("Init DB done.")
|
|||
|
}
|
|||
|
|
|||
|
// 创建映射表
|
|||
|
func createTable() {
|
|||
|
_, err := db.Exec(createTableSQL)
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 从数据库读取映射信息
|
|||
|
func readMappings() map[string]*MappingInfo {
|
|||
|
mappings := make(map[string]*MappingInfo)
|
|||
|
rows, err := db.Query("SELECT RuleName, IPAddress, Ip, Port, LastUpdate FROM mappings")
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
defer rows.Close()
|
|||
|
|
|||
|
for rows.Next() {
|
|||
|
var info MappingInfo
|
|||
|
var lastUpdate string
|
|||
|
err = rows.Scan(&info.RuleName, &info.IpAddr, &info.Ip, &info.Port, &lastUpdate)
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
info.LastUpdate, err = time.Parse(time.RFC3339, lastUpdate)
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
mappings[info.RuleName] = &info
|
|||
|
}
|
|||
|
return mappings
|
|||
|
}
|
|||
|
|
|||
|
// 更新数据库中的映射信息
|
|||
|
func updateMapping(info MappingInfo) {
|
|||
|
_, err := db.Exec("INSERT OR REPLACE INTO mappings (RuleName, IPAddress, Ip, Port, LastUpdate) VALUES (?, ?, ?, ?, ?)",
|
|||
|
info.RuleName, info.IpAddr, info.Ip, info.Port, info.LastUpdate.Format(time.RFC3339))
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
}
|