commit 4bbc05fe1fb1f65975608de0ae40aec4486af000 Author: luorijun Date: Tue Aug 5 10:51:35 2025 +0800 建立仓库 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c1ca2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +### Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# editor file +.idea/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a09d439 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +## TODO + +此实现目前并不是完全并发安全的: + +目前事务等级没有对 cityhash 表的 offset 字段做防丢失,并发操作可能会出问题 \ No newline at end of file diff --git a/actions/cities.go b/actions/cities.go new file mode 100644 index 0000000..ec742f6 --- /dev/null +++ b/actions/cities.go @@ -0,0 +1,43 @@ +package actions + +import ( + "fmt" + "gorm.io/gorm" + "zzman/model" +) + +func FindCities(tx *gorm.DB) ([]model.City, error) { + var cities []model.City + if err := tx.Find(&cities, "label is not null").Error; err != nil { + return nil, fmt.Errorf("failed to find cities: %w", err) + } + return cities, nil +} + +func FindCitiesWithEdgesCount(tx *gorm.DB) ([]model.City, error) { + var cities []model.City + err := tx.Debug(). + Select("cities.*, COUNT(edges.id) AS edges_count"). + Joins("LEFT JOIN edges ON edges.city_id = cities.id"). + Group("cities.id"). + Find(&cities).Error + if err != nil { + return nil, fmt.Errorf("failed to find cities with edges count: %w", err) + } + return cities, nil +} + +func AppendCityOffset(tx *gorm.DB, city int, offset int) error { + if offset < 0 { + return fmt.Errorf("offset must be non-negative") + } + + err := tx.Model(&model.City{}). + Where("id = ?", city). + Update("offset", offset).Error + if err != nil { + return fmt.Errorf("failed to update cities offset: %w", err) + } + + return nil +} diff --git a/actions/configs.go b/actions/configs.go new file mode 100644 index 0000000..cf31454 --- /dev/null +++ b/actions/configs.go @@ -0,0 +1,33 @@ +package actions + +import ( + "gorm.io/gorm" + "zzman/model" +) + +func FindConfigsByGateway(tx *gorm.DB, macaddr string) ([]model.Config, error) { + var configs []model.Config + err := tx.Find(&configs, "macaddr = ?", macaddr).Error + if err != nil { + return nil, err + } + return configs, nil +} + +func CreateConfigs(tx *gorm.DB, configs []model.Config) error { + if len(configs) == 0 { + return nil + } + + // 使用事务批量插入配置 + return tx.Create(&configs).Error +} + +func UpdateConfigs(tx *gorm.DB, configs []model.ConfigUpdate) error { + if len(configs) == 0 { + return nil + } + + // 使用事务批量更新配置 + return tx.Updates(&configs).Error +} diff --git a/actions/edges.go b/actions/edges.go new file mode 100644 index 0000000..e2abc76 --- /dev/null +++ b/actions/edges.go @@ -0,0 +1,73 @@ +package actions + +import ( + "fmt" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "zzman/model" +) + +const batchSize = 1000 + +func FindEdgesByCity(tx *gorm.DB, cityId int) ([]model.Edge, error) { + var edges []model.Edge + err := tx.Find(&edges, "city_id = ?", cityId).Error + if err != nil { + return nil, fmt.Errorf("failed to find edges: %w", err) + } + return edges, nil +} + +func SliceActiveEdgesByCity(tx *gorm.DB, cityId int, offset int, limit int) ([]model.Edge, error) { + var edges []model.Edge + err := tx.Limit(limit).Offset(offset).Find(&edges, "city_id = ? and active = 1", cityId).Error + if err != nil { + return nil, fmt.Errorf("failed to find edges with offset: %w", err) + } + return edges, nil +} + +func SaveEdges(tx *gorm.DB, edges []model.Edge) error { + if len(edges) == 0 { + return nil + } + + // 分批处理边缘设备数据 + for i := 0; i < len(edges); i += batchSize { + end := i + batchSize + if end > len(edges) { + end = len(edges) + } + + batch := edges[i:end] + err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "macaddr"}}, + UpdateAll: true, + }).Create(&batch).Error + if err != nil { + return fmt.Errorf("failed to save edges batch %d-%d: %w", i, end-1, err) + } + } + return nil +} + +func DisableEdgesByMacs(tx *gorm.DB, macs []string) error { + if len(macs) == 0 { + return nil + } + + // 分批处理MAC地址列表 + for i := 0; i < len(macs); i += batchSize { + end := i + batchSize + if end > len(macs) { + end = len(macs) + } + + batch := macs[i:end] + err := tx.Model(&model.Edge{}).Where("macaddr IN ?", batch).Update("active", false).Error + if err != nil { + return fmt.Errorf("failed to disable edges batch %d-%d: %w", i, end-1, err) + } + } + return nil +} diff --git a/actions/gateways.go b/actions/gateways.go new file mode 100644 index 0000000..8001ab6 --- /dev/null +++ b/actions/gateways.go @@ -0,0 +1,28 @@ +package actions + +import ( + "fmt" + "gorm.io/gorm" + "math" + "zzman/model" +) + +func FindGateways(tx *gorm.DB) ([]model.Gateway, error) { + var gateways []model.Gateway + err := tx.Find(gateways).Error + if err != nil { + return nil, err + } + return gateways, nil +} + +func AppendGatewayConfigVersion(tx *gorm.DB, gateway int) error { + expr := fmt.Sprintf("if(setid = %d, 1, setid + 1)", math.MaxInt32) + tx.Model(&model.Gateway{}). + Where("id = ?", gateway). + Update("setid", gorm.Expr(expr)) + if tx.Error != nil { + return fmt.Errorf("更新网关配置版本失败:%w", tx.Error) + } + return nil +} diff --git a/actions/sync.go b/actions/sync.go new file mode 100644 index 0000000..708398e --- /dev/null +++ b/actions/sync.go @@ -0,0 +1,98 @@ +package actions + +import ( + "fmt" + "gorm.io/gorm" + "log/slog" + "zzman/clients/jd" + "zzman/model" +) + +// Sync 同步城市节点数据 +// +// 数据库中保留云端已经移除的节点是有必要的,因为在节点轮换时需要保证能够从正确的位置开始, +// 而其之前所用的节点可能已经被云端移除,因此需要保留这些节点的记录以保持正确的轮换顺位。 +func Sync() (err error) { + slog.Info("开始同步城市节点数据") + + // 获取需要更新的城市列表 + cities, err := FindCities(model.DB) + if err != nil { + return fmt.Errorf("获取所有城市失败: %w", err) + } + slog.Info("成功获取城市列表", slog.Int("城市数量", len(cities))) + + // 获取所有城市的节点数据 + for i, city := range cities { + slog.Info("正在同步城市", slog.String("城市", city.Name), slog.String("哈希", city.Hash)) + + // 新节点信息 + resp, err := jd.EdgeDevice(jd.EdgeDeviceReq{ + Geo: city.Hash, + Offset: 0, + Num: 1000000, + }) + if err != nil { + return fmt.Errorf("获取城市 %s:%s 的边缘设备失败: %w", city.Name, city.Hash, err) + } + var newEdges = resp.Edges + slog.Info("获取节点数据完成", slog.String("城市", city.Name), slog.Int("节点数量", len(newEdges))) + + err = model.DB.Transaction(func(tx *gorm.DB) error { + // 旧节点信息 + oldEdges, err := FindEdgesByCity(tx, city.Id) + if err != nil { + return fmt.Errorf("获取所有边缘节点MAC地址失败: %w", err) + } + var oldEdgesMacSet = make(map[string]struct{}, len(oldEdges)) + for _, edge := range oldEdges { + oldEdgesMacSet[edge.Macaddr] = struct{}{} + } + + // 对比并更新节点信息(全量更新) + var edgeSaves = make([]model.Edge, 0) + for _, edge := range newEdges { + edgeSaves = append(edgeSaves, model.Edge{ + CityId: city.Id, + Macaddr: edge.Macaddr, + Public: edge.Public, + Isp: edge.Isp, + Single: edge.Single, + Sole: edge.Sole, + Arch: edge.Arch, + Online: edge.Online, + Active: true, + }) + delete(oldEdgesMacSet, edge.Macaddr) + } + + // 更新现有数据 + if err = SaveEdges(tx, edgeSaves); err != nil { + return fmt.Errorf("批量保存边缘节点失败: %w", err) + } + // 删除旧节点信息 + var oldEdgesMacs = make([]string, 0, len(oldEdgesMacSet)) + for mac := range oldEdgesMacSet { + oldEdgesMacs = append(oldEdgesMacs, mac) + } + if err = DisableEdgesByMacs(tx, oldEdgesMacs); err != nil { + return fmt.Errorf("通过MAC地址删除边缘节点失败: %w", err) + } + + slog.Info("城市同步完成", + slog.Int("新节点", len(newEdges)), + slog.Int("旧节点", len(oldEdges)), + slog.Int("移除", len(oldEdgesMacs)), + slog.Int("同步", len(edgeSaves)), + slog.String("进度", fmt.Sprintf("%d/%d", i+1, len(cities))), + ) + return nil + }) + if err != nil { + return fmt.Errorf("城市 %s 事务处理失败: %w", city.Name, err) + } + + } + + return nil +} diff --git a/actions/update.go b/actions/update.go new file mode 100644 index 0000000..8cc51ad --- /dev/null +++ b/actions/update.go @@ -0,0 +1,196 @@ +package actions + +import ( + "fmt" + "log/slog" + "strconv" + "zzman/clients/jd" + "zzman/model" + u "zzman/util" + + "gorm.io/gorm" +) + +type UpdateArgs struct { + Mock bool +} + +func Update(tx *gorm.DB, args ...UpdateArgs) error { + var arg UpdateArgs + if len(args) > 0 { + arg = args[0] + } else { + arg.Mock = false + } + + gateways, err := FindGateways(tx) + if err != nil { + return fmt.Errorf("获取所有网关失败:%w", err) + } + + cities, err := FindCitiesWithEdgesCount(tx) + if err != nil { + return fmt.Errorf("获取所有城市失败:%w", err) + } + + // 准备网关查找表,初始化网关配置表 + type ConfigInfo struct { + Item jd.EdgeInfo + Type int // 0: 不变, 1: 更新, 2: 新增 + } + var oldConfigsMap = make(map[model.Gateway]map[string]model.Config) + var newConfigs = make(map[model.Gateway][]ConfigInfo) + for _, gateway := range gateways { + newConfigs[gateway] = make([]ConfigInfo, len(cities)) + + oldConfigs, err := FindConfigsByGateway(tx, gateway.Macaddr) + if err != nil { + return fmt.Errorf("获取网关 %s 城市节点失败:%w", gateway.Macaddr, err) + } + + oldConfigsMap[gateway] = make(map[string]model.Config) + for _, config := range oldConfigs { + oldConfigsMap[gateway][config.Cityhash] = config + } + } + + // 按城市循环,对比并更新网关配置 + for iCity, city := range cities { + + // 如果每个网关在此城市都有节点且无需改变,就不需要从云端拉取城市节点信息 + // 相当于直接重新提交配置,此流程下配置更新是幂等的 + var gateways2Update []model.Gateway + for _, gateway := range gateways { + oldConfig, exists := oldConfigsMap[gateway][city.Hash] + if exists && oldConfig.IsChange != 1 { + newConfigs[gateway][iCity] = ConfigInfo{ + Type: 0, // 不变 + Item: jd.EdgeInfo{ + Mac: oldConfig.Macaddr, + City: oldConfig.Cityhash, + }, + } + } else { + gateways2Update = append(gateways2Update, gateway) + } + } + if len(gateways2Update) == 0 { + continue + } + + // 否则,正常从云端拉取城市节点信息 + offset := city.Offset + count := len(gateways2Update) + if count > city.EdgesCount { + slog.Warn("城市节点数量不足,跳过本次更新", "城市", city.Name, "节点数", city.EdgesCount, "网关数", count) + continue + } + + if offset+count > city.EdgesCount { + slog.Debug("城市节点不足,将循环使用节点", "城市", city.Name, "节点数", city.EdgesCount, "网关数", count) + offset = 0 + } + + edges, err := SliceActiveEdgesByCity(tx, city.Id, offset, count) + if err != nil { + return fmt.Errorf("查询城市 %s 可用节点失败:%w", city.Name, err) + } + + // 更新网关配置 + var configs2Create []model.Config + var configs2Update []model.ConfigUpdate + + for iGateway, gateway := range gateways2Update { + + oldConfig, exists := oldConfigsMap[gateway][city.Hash] + newConfig := edges[iGateway] + + if exists { + fmt.Printf("\t网关 %s 变更节点: %s -> %s\n", gateway.Macaddr, oldConfig.Macaddr, newConfig.Macaddr) + + configs2Update = append(configs2Update, model.ConfigUpdate{ + Id: oldConfig.Id, + Macaddr: u.P(oldConfig.Macaddr), + IsChange: u.P(0), + }) + + newConfigs[gateway][iCity] = ConfigInfo{ + Type: 1, // 更新 + Item: jd.EdgeInfo{ + Mac: oldConfig.Macaddr, + City: city.Hash, + }, + } + } else { + fmt.Printf("\t网关 %s 新增节点: %s\n", gateway.Macaddr, newConfig.Macaddr) + + configs2Create = append(configs2Create, model.Config{ + Cityhash: city.Hash, + CityLabel: city.Label, + GatewayMac: gateway.Macaddr, + Macaddr: newConfig.Macaddr, + Table: strconv.Itoa(iCity + 1), + User: fmt.Sprintf("jdzz%ddt%d", iGateway+1, iCity+1), + Network: fmt.Sprintf("172.30.168.%d", iCity+2), + InnerIp: fmt.Sprintf("172.16.%d.%d", iGateway+1, iCity+2), + }) + + newConfigs[gateway][iCity] = ConfigInfo{ + Type: 2, // 新增 + Item: jd.EdgeInfo{ + Mac: oldConfig.Macaddr, + City: city.Hash, + }, + } + } + } + + err = CreateConfigs(tx, configs2Create) + if err != nil { + return fmt.Errorf("创建新配置失败:%w", err) + } + err = UpdateConfigs(tx, configs2Update) + if err != nil { + return fmt.Errorf("更新配置失败:%w", err) + } + err = AppendCityOffset(tx, city.Id, offset+count) + if err != nil { + return fmt.Errorf("更新城市 %s 的偏移量失败:%w", city.Name, err) + } + } + + // 提交所有网关配置到云端 + for gateway, infos := range newConfigs { + change := 0 + setup := 0 + edges := make([]jd.EdgeInfo, len(infos)) + for i, info := range infos { + edges[i] = info.Item + switch info.Type { + case 1: + change++ + case 2: + setup++ + } + } + fmt.Printf("提交网关 %s 配置: %d 变更, %d 新增\n", gateway.Macaddr, change, setup) + + // 提交配置到云端:配置版本 gateway.ConfigVersion + if arg.Mock { + fmt.Printf("[MOCK] 配置网关 %s:\n%v\n", gateway.Macaddr, edges) + } else { + err := jd.GatewayConfigSet(gateway.ConfigVersion, gateway.Macaddr, edges) + if err != nil { + return fmt.Errorf("配置网关 %s 失败:%w", gateway.Macaddr, err) + } + } + + // 更新配置版本 + err = AppendGatewayConfigVersion(tx, gateway.Id) + if err != nil { + return fmt.Errorf("更新网关 %s 配置版本失败:%w", gateway.Macaddr, err) + } + } + + return nil +} diff --git a/clients/jd/client-auth.go b/clients/jd/client-auth.go new file mode 100644 index 0000000..78d4073 --- /dev/null +++ b/clients/jd/client-auth.go @@ -0,0 +1,45 @@ +package jd + +import ( + "encoding/json" + "errors" + "os" +) + +func ClientAuth() (*ClientAuthResp, error) { + var username = os.Getenv("JD_USERNAME") + if username == "" { + return nil, errors.New("JD_USERNAME 环境变量未设置") + } + + var password = os.Getenv("JD_PASSWORD") + if password == "" { + return nil, errors.New("JD_PASSWORD 环境变量未设置") + } + + path := "/client/auth" + resp, err := Post(path, map[string]any{ + "username": username, + "password": password, + }, false) + if err != nil { + return nil, err + } + + var respData = new(ClientAuthResp) + if err := json.NewDecoder(resp).Decode(respData); err != nil { + panic("响应解析失败: " + err.Error()) + } + + if respData.Code != 0 { + panic("响应失败: " + respData.Meta) + } + + return respData, nil +} + +type ClientAuthResp struct { + Code int `json:"code"` + Meta string `json:"meta"` + Data string +} diff --git a/clients/jd/common.go b/clients/jd/common.go new file mode 100644 index 0000000..f5e7278 --- /dev/null +++ b/clients/jd/common.go @@ -0,0 +1,77 @@ +package jd + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "github.com/redis/go-redis/v9" + "io" + "net/http" + "time" + "zzman/clients" +) + +const base = "https://smart.jdbox.xyz:58001" + +func Post(path string, data any, auth ...bool) (io.ReadCloser, error) { + + reqBytes, err := json.Marshal(data) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", base+path, bytes.NewReader(reqBytes)) + if err != nil { + return nil, err + } + defer req.Body.Close() + + req.Header.Set("Content-Type", "application/json") + + if len(auth) == 0 || auth[0] { + token, err := Token() + if err != nil { + return nil, fmt.Errorf("获取令牌失败: %w", err) + } + req.Header.Set("X-Token", token) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%s 响应失败: %s", path, resp.Status) + } + + return resp.Body, nil +} + +func Token() (string, error) { + + // 尝试从 Redis 获取缓存的 token + token, err := clients.Redis.Get(context.Background(), "token").Result() + if err != nil && !errors.Is(err, redis.Nil) { + return "", fmt.Errorf("获取 token 失败: %w", err) + } + if token != "" { + return token, nil + } + + // 如果缓存中没有 token,则进行认证请求 + resp, err := ClientAuth() + if err != nil { + return "", fmt.Errorf("认证请求失败: %w", err) + } + + // 返回请求的 token + token = resp.Data + if err := clients.Redis.Set(context.Background(), "token", token, 6*24*time.Hour).Err(); err != nil { + return "", fmt.Errorf("缓存 token 失败: %w", err) + } + + return token, nil +} diff --git a/clients/jd/edge-device.go b/clients/jd/edge-device.go new file mode 100644 index 0000000..2c3e619 --- /dev/null +++ b/clients/jd/edge-device.go @@ -0,0 +1,52 @@ +package jd + +import ( + "encoding/json" + "fmt" +) + +func EdgeDevice(req EdgeDeviceReq) (*EdgeDeviceData, error) { + path := "/edge/device" + resp, err := Post(path, req) + if err != nil { + return nil, err + } + + var respData EdgeDeviceResp + if err := json.NewDecoder(resp).Decode(&respData); err != nil { + return nil, fmt.Errorf("%s 响应解析失败: %v", path, err) + } + + if respData.Code != 0 { + return nil, fmt.Errorf("%s 响应失败: %s", path, respData.Meta) + } + + return &respData.Data, nil +} + +type EdgeDeviceReq struct { + Geo string `json:"geo"` + Offset int `json:"offset"` + Num int `json:"num"` +} + +type EdgeDeviceResp struct { + Code int `json:"code"` + Meta string `json:"meta"` + Data EdgeDeviceData `json:"data"` +} + +type EdgeDeviceData struct { + Count int `json:"count"` + Edges []EdgeDeviceEdge `json:"edges"` +} + +type EdgeDeviceEdge struct { + Macaddr string `json:"macaddr"` + Public string `json:"public"` + Isp string `json:"isp"` + Single int `json:"single"` + Sole bool `json:"sole"` + Arch int `json:"arch"` + Online int `json:"online"` +} diff --git a/clients/jd/getway-config-set.go b/clients/jd/getway-config-set.go new file mode 100644 index 0000000..8cb294d --- /dev/null +++ b/clients/jd/getway-config-set.go @@ -0,0 +1,61 @@ +package jd + +import "fmt" + +type EdgeInfo struct { + Mac string + City string +} + +func GatewayConfigSet(version int, macaddr string, edges []EdgeInfo) error { + if version < 0 { + return fmt.Errorf("版本号不能小于 0") + } + if macaddr == "" { + return fmt.Errorf("macaddr 不能为空") + } + if len(edges) > 250 { + return fmt.Errorf("边缘节点数量不能超过 250") + } + + rules := make([]GateConfigSetReqRule, len(edges)) + for i, edge := range edges { + rules[i] = GateConfigSetReqRule{ + Enable: true, + Edge: []string{edge.Mac}, + Network: []string{fmt.Sprintf("172.30.168.%d", i+2)}, + Cityhash: edge.City, // 每个 edge 的城市应当相同 + } + } + + req := GatewayConfigSetReq{ + Macaddr: macaddr, + Config: GateConfigSetReqConfig{ + Id: version, + Rules: rules, + }, + } + + if _, err := Post("/gateway/config/set", req); err != nil { + return fmt.Errorf("设置网关配置失败: %v", err) + } + + return nil +} + +type GatewayConfigSetReq struct { + Macaddr string `json:"macaddr"` + Config GateConfigSetReqConfig `json:"config"` +} + +type GateConfigSetReqConfig struct { + Id int `json:"id"` + Rules []GateConfigSetReqRule `json:"rules"` +} + +type GateConfigSetReqRule struct { + Enable bool `json:"enable"` + Edge []string `json:"edge"` + Network []string `json:"network"` + Cityhash string `json:"cityhash"` +} diff --git a/clients/redis.go b/clients/redis.go new file mode 100644 index 0000000..c9da4e0 --- /dev/null +++ b/clients/redis.go @@ -0,0 +1,31 @@ +package clients + +import ( + redis "github.com/redis/go-redis/v9" + "log/slog" + "os" +) + +var Redis *redis.Client + +func InitRedis() { + host := os.Getenv("REDIS_HOST") + if host == "" { + slog.Debug("REDIS_HOST 环境变量未设置,使用默认值 localhost") + host = "localhost" + } + port := os.Getenv("REDIS_PORT") + if port == "" { + slog.Debug("REDIS_PORT 环境变量未设置,使用默认值 6379") + port = "6379" + } + password := os.Getenv("REDIS_PASSWORD") + if password == "" { + slog.Debug("REDIS_PASSWORD 环境变量未设置,使用默认值空字符串") + } + + Redis = redis.NewClient(&redis.Options{ + Addr: host + ":" + port, + Password: password, + }) +} diff --git a/cmd/tmp.go b/cmd/tmp.go new file mode 100644 index 0000000..c12d434 --- /dev/null +++ b/cmd/tmp.go @@ -0,0 +1,15 @@ +package main + +func main() { + //slog.Debug("初始化环境变量") + //err := godotenv.Load() + //if err != nil { + // slog.Error(fmt.Errorf("初始化变量失败:%w", err).Error()) + //} + // + //model.Init() + //clients.InitRedis() + // + //cities, _ := actions.FindCitiesWithEdgesCount(model.DB) + //fmt.Printf("%v\n", cities) +} diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..ef5a2fc --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,26 @@ +name: zz-man + +services: + + redis: + image: redis:7 + environment: + REDIS_PASSWORD: 123456 + ports: + - "6379:6379" + volumes: + - redis_data:/data + + mariadb: + image: mariadb:10 + environment: + MYSQL_ROOT_PASSWORD: "hljuip916..." + MYSQL_DATABASE: jdbox + ports: + - "3306:3306" + volumes: + - mariadb_data:/var/lib/mysql + +volumes: + redis_data: + mariadb_data: \ No newline at end of file diff --git a/docs/city.json b/docs/city.json new file mode 100644 index 0000000..284914e --- /dev/null +++ b/docs/city.json @@ -0,0 +1,422 @@ +{ + "code": 0, + "meta": "success", + "data": { + "山西": { + "忻州": "13a944200fe1e5081c31072089ee4f011ae8fbc7619554cd06c9aca8b7e09381", + "阳泉": "2d93fad9848518a4f8d12dc3a28b8f121d79066a6c3053e95da3e2e88d0445da", + "朔州": "3408f89a6ffbecc5ed21797a7c60d6496eb25e367f35835241e63c4fbf659395", + "吕梁": "65174e5170d8a1580c8bb6a20e5ce16f8ce9709991d3a4c8c9c1bde7b31e157a", + "临汾": "be75cfd425cc9865b56e59bef1a18a1ebb42cfc4eeadfe1e54656618ec5d21d6", + "晋城": "1d751d94e699f55fa9f72bfdd71f1f08eec6006b0581b1557787759767db8bb3", + "大同": "7d3c78dd39947de4b7454c6264242065b3a9d7f674db990ff1598bad38813c1e", + "运城": "f8091151e1758231a8d09d5154ba53559c25c317bd97521b55b770ee6e1bed68", + "晋中": "a5ca4557df12250ad590776f07d84153d5edbc1c4d6529740ad4bd6394d10e9a", + "长治": "441dd4291cafc1a39a71bb1f1a80e91ffa3aefb6843c78a1b30b1ce528aea3a6", + "太原": "52a8972972f33c7842eefadb048e2046ff6245703d54eeaa64354afa44e82b46" + }, + "黑龙江": { + "大兴安岭地区": "89553c7802d23d535b7e6c124845a200e69ca51573f62c0be89af6720446ad7e", + "七台河": "58370ef051a7f4a3d5d40a3f505bb109420c2b347ba09b579b06c774cc3fbc3e", + "鹤岗": "da09eba79b16b8f4af4ece51bd391070ee8919d5865126b0c720904a5b0d1415", + "哈尔滨": "6a2f940902bcf9c3e62e81be970ff1bd6e2a237d5ab0be0fe9bd17b3eb9175e6", + "黑河": "acabeac9e6a7a6f2668bfb7cd2ef974890511d409ee6b3f92d62803a9df2fe63", + "伊春": "be932c1f1e4804ec2855c7e5b7019f965b430a1dde74f14d363a65bb28a25b47", + "牡丹江": "686a8e5fe478b85f62d4c76f72d83468662a37388c176117d0c8d5ab4797d219", + "鸡西": "a4894931403f940cb001a5f31a3eea8310fa7d581da1e7c23a1d239ffb1d5a9c", + "绥化": "4039556920151733b96d2237183fc48583d1b6625411e5276ebabba37d8fffb8", + "佳木斯": "161144622f00c9832cd8ef648836f224bf3a33459296a668e7cfa2b2534c1531", + "齐齐哈尔": "722f020d63c61dce7fda0a7bdd11b5ec96ad23646661d7f8495b2cbd6d66447d", + "双鸭山": "6099babcecf7a9c9c8d704b02670b59070675242a34e113020e542a6a7e83cda", + "大庆": "da49875b6877c7e4d84a0d5e353dc6afb3ab502ad35f754aa2bb87c3f29cd6a5" + }, + "江西": { + "吉安": "6babbd2339d53fe041556a775b3963e63f66153b7ac9ce3bd698f5334de84f91", + "萍乡": "0843bcecb7af552fb816bc9db2f66ce70fecec9834961988b1807013d6f48618", + "赣州": "bf4f5193031c3a3abc76db98bb9aaabcdda63b7f4b6bbc2acbc2049153eefc49", + "上饶": "7eb867dcd8b62172f075b2bbb7e87b31702e3eaa0f09dadbd004541ab486b59f", + "南昌": "44ee84d6b4acec5d65d468f3b968e1dada861c0a1c4009fb769a813ea5357b83", + "宜春": "77f7397a6a929a34600d4b517e012c4cd78098e30c89d85d7e88f7d786bcfd85", + "九江": "f9d7d1453fb46ad290295fefc2857341d7f7085711d1cc6ccecb1ab67f0e80bc", + "鹰潭": "321ec26a30f3597224596688b2dcbf11f68d006efb67c5fc99eaa204a802387f", + "景德镇": "7ec1d0f886b21747fe7a39f3fee2b6f1a462fefa78dbe126f12a502106edfe69", + "新余": "13de0c850c7f51c3a215ecd30c6d4edf8bfd1b62c3354e87e05a60cbacf51523", + "抚州": "ebc3b0f48cb638bebfaac264ed95c455102f5acd87e31dae5b1342d8f68b6df4" + }, + "青海": { + "海东": "0b2cc305cd7ffaeed98ba63f1b5e2e7a6213b341968386e3eeb2245d488ebf6f", + "玉树藏族自治州": "ee0b3722c01ed1b47bece6b8069e2ca6c7a180914b56f06225efea4bf6dccd34", + "海北藏族自治州": "4650ae9e3b783adb2c32c5ad97fd97e26485bdcc75f51067f28ae268d9a7991b", + "海西蒙古族藏族自治州": "16b7c4f0594fbc8d44009e933118611075d0d49644c6fccb5fb10e35a83b4100", + "果洛藏族自治州": "aa222d78cb5ac4df5dede6fac079451169067ff38a3921897b771a0459c207a0", + "西宁": "6b34658a83583f2dddeea41b290ef9adf3e1cff4fbe8935b9286fe50e666634f" + }, + "上海": { + "上海": "f8a5e9b04178490cf8e71f5b273538aa75ef2c978ecac974a176d93af966ef53" + }, + "湖北": { + "天门": "91a4f75b283e9373507ef16645b23894157db8e9a3004427c506955a056406a6", + "恩施土家族苗族自治州": "ec4a7129c9f9d8976fd9207809d2fef1e1fbceda2939ace6d722d5b6cb90fe92", + "荆州": "f5f1593b3aa0d7918b0b71a837ae082c6a359f86f19ed8bb9e70952068a3449d", + "鄂州": "5b46101880b4cd0f15300d215ee2acfa1d193443616b9201086809d0c9c66ee9", + "仙桃": "9f6bc74ead0ca6eb41eaa9eaa2ad4a0235b1f18e9cdc1dd4a2b2ad3ec630e047", + "荆门": "51da574feb20dbc0ee7697585feeac4bddbe53933115519cd09ec3a4a29e183b", + "宜昌": "4c79e67cd6f616ab1710dc15f8ba7594be5bd758becd4bd8d681c9d717d31aa7", + "襄阳": "85767a31a443803091f92086a3fe12ccea5bded0694251635005602445fb9a99", + "十堰": "85105a54a6480b4a97d6559aa1e83545453f2a7c7b0595433e800e00daf477f7", + "咸宁": "83472e3684d2df1f3825dc02a606eed9b019cfd9f802abfeab4d3d85e12ad7be", + "神农架林区": "3401d987392220548e0bebf07a3ab37c1c214ab5b4e3d25dc9ff1677e714c885", + "武汉": "f7fa6dd7e26bf54d2650eb58a8c74c8f248ead5bdfa25650e15132ae95f9c41f", + "黄石": "916441cdf755c27216c4bdcae294d190c2fc1e10fd2e9addd0a995ac92f460d2", + "黄冈": "94ae0e68351dc53dba8f21631a02c23d5b23b8cdb75272215d7ca82295383a32", + "潜江": "66c2f6b3ad6cb578652b925adcac5050d7db26d956faa394f09bb0f4fa08b92f", + "随州": "8db88373bb4a82aa0699ed2f9828bc71722611630d6576b1e147b2c79b2a959a", + "孝感": "b3ab968e65219b8100addd802dd0b9b6fda0169868a6081756b01aada8450be5" + }, + "海南": { + "昌江黎族自治县": "56d5cc921a9c34ec44615e3ac7898794440c884ff70fcd94b95ae8a68449b2f0", + "乐东黎族自治县": "fb5661fd8ea061b4cfe539ba5deff2421b4aad6122e5cff9454312ad91deba7e", + "海口": "8527af3a62cab64f98f40266a2dc1adde23d5a617b953a9b092cb30730eb1348", + "定安县": "47c9cffed65d04bcfe76d8ef1b8262b904d7f29c92b64778d796af2fa8a69791", + "东方": "7af722bf9ec4e1aaa73f49bed272ec9fd9a637417c207a7b5712eb67d23d8c98", + "临高县": "6d6de688c55c2b167f9531118e4d698fce8e53ca89fdbd94b6743ad5ed519d45", + "万宁": "3b18a54cddf7a7387893b2995a8cfe3992724471f479e9fb55d4ac163169354e", + "陵水黎族自治县": "80c4b0eb9e4e131449379cdc58a51f3b6bb9b45847bca53383e74b569af5750f", + "文昌": "017358c21a8fca07fbd06f306af1a59d001685436ef8298859e8062312ac42de", + "白沙黎族自治县": "5873aef16c8d6b272a3bb573a90b4790fae5b0a9b5622df1cea06fe0d7463cfd", + "屯昌县": "d174862cd52af19f72f791f2e9d288e2a3148101623aa08f8b9e5f4bed2ae355", + "琼中黎族苗族自治县": "c7e8553c8ba95acfe8879e64c4c2b0b28b0b16255a2890673a54ab2fcbfb3091", + "琼海": "a35c20a52102cbcf3d9ad109d9dba0fcc2666f77c644aaa7eb5904b90def1dfd", + "澄迈县": "99951cd2fefe9678ac0bf8a181bac0c8cdc651fd6081c7395c35ce3e8da4bd24", + "三亚": "9277f60dbdb857135ae3c755479b8cad7752245df697d0a6b9fe6585cd4c3284", + "儋州": "33e83af31b59b0ba980f2d5c282bdd90e78ff6e24780646640b0c86cda763425" + }, + "湖南": { + "邵阳": "6cf1b44b1b1148b16da681de21ad837dcdfb8b2aa732a43c5c54472a8cd10148", + "株洲": "495178dbf2b2a5cc37544d1e24c9780f78fa8344d89d6da8c828d21a5d2d1ad2", + "怀化": "20c5485e25a2f55681fa38f3598b34a6876e60c3188e4b5174042e4e390a1808", + "湘潭": "c6c2657ef32f404227f07e0ce8f17bebfee4747661e499382442a1d16664ddf8", + "郴州": "bdb5cb91b4290e4c7655637ebfe73106d073dc73012231afcea22e8c70a71bd8", + "永州": "781f88f2079649d795d8663fb6037223a868f729c5b65b3b44ef9fd3b1b02e68", + "衡阳": "0e4a0624c63f52e856ba61874f0f4fa6b96328bc40f3483cbf784dc24412d009", + "湘西土家族苗族自治州": "2dcae7c10849fe53081181e1d3e53023f85d4e37f489efb96cb71212268038ca", + "张家界": "da3357fcafd57d479c70cccdee8a76048fd41b5adfce9126c68cb5cb6fbaff4b", + "常德": "8c08c6f82360a0f996790f594feff5702aff398658e701f78c7d1457f0090d57", + "岳阳": "e33daa9c38379b67ec055303832254284e09d7c04fc7234d871e7a2766ae11b9", + "娄底": "2f6242d5ea29e7e0ff9cd59f70abcb3054c0622992385abb72af71dbce9f2ece", + "长沙": "8710a691dd8c48d594107b61ff1e0cc63ae03bdfb7951785e885a4f2e1ebc6b9", + "益阳": "08397b1ba554e93dedaa897b474ea24f2965766fe880f6c00652756574287a19" + }, + "广西": { + "百色": "63bc50e406f4fd4473528647f57a2c5058dae1ddbf2f611ff7e23d4af4850c5d", + "北海": "a24753b01f3362ace753144a328367e82d2f8e642e6af38501802d36ec1fb9ba", + "钦州": "a152edec15ba77cc79dd900f7edd001d608e54a7720de17379d0b5664006113d", + "南宁": "0c3279290673cd0d8626b1ca4a56048651414f56be06e379f6c969e97e840f22", + "梧州": "0ec47b6039f5523692835abf0f3447b3e45a75a5929ddecd102eb304c2ce44a6", + "防城港": "2e670c9c5d332a8d717d17acee789094d2b1c57978d9c969512965cb51f96294", + "柳州": "521630c8b6d213e8c0395c3e89bb3bfdafcf1a2adb099800a17e4bf3e31296f2", + "崇左": "fa2f4796e2498ec3b4ef42e873a243fa2698877443cdeb59c6a4de7cdc57b796", + "来宾": "5933459cbec72c77d2d28df05a7cdb0d67a5a10fa45d67330d9b4a25596c3a11", + "桂林": "397ffe1176f6fbc6995c6e5dc6bd10bea4fa9bda0ea77ef4b5621f521341fa01", + "玉林": "4e220c3c74d856927f83c2f703e31eed3f311a49870711bcec535ce55ede9bea", + "贵港": "a96ca6d792beecfc3ff16d9f915b9cbbb9785df2ac6f8e2c4a7a3de12955d93e", + "贺州": "a27904a6b411af796345327b53f1b2172f2072ec7a965f4ed2e832b8370470e4", + "河池": "722fb89a1e888d9aadb67d055be3f412e82e4d8e3b8904c14db23ccdc19e0449" + }, + "安徽": { + "马鞍山": "a486733631ad2d10a16fb1741780c4d5d830284357c7da9ae1b855bcce8d2209", + "阜阳": "33695ad43b73cc70f93d1313ae1dc0b254feeebffd3d3ace3c6d3b27487c1a59", + "淮北": "5767c29a9bd74c6ac408abb53c93a14e79c9635e439bbc52c399d19745bf336f", + "滁州": "fdd9d1b2da2f8379173fb46ff753ef7a9a4a4d531132594fad1ef9e02f63beda", + "铜陵": "259452fe2bd5106b62ba9b09b62aa599dd8894fbbb886de889b5ab372c2909c6", + "芜湖": "54562d4501486f3ea56d2e2d1e1db3aefdc9b32bc69ab35a7614575b428c89b7", + "亳州": "ce4db8b85e6e87fc099516d0c00ef12810899e01d6398f6d7dc5267110f6c5b2", + "六安": "25f79f127abbd4a4fbb03f49cf867af8914f7e538bec03bcc4252c765b51a83f", + "淮南": "fc823a725f8d65c7f84ffb15a0ae47a587dbbc95d6aa8dff642573943d90c607", + "池州": "1fbbebf5e91217f53c75298927ce763887243c14d1567f7218ecfa5fba5c6d96", + "黄山": "e1b50cab69f96fe95886cff325995051e87531a2efa3def15f164d4d8ee4f9f7", + "合肥": "f6a209bd0da8c0049c35d48deb56569f79f662a9202b814ce019055cb1b3bb5c", + "宿州": "4e0c060554c45b8de2e0665966bf3e12fb9ac865ab04664208160508d8ccaf2a", + "安庆": "ea574e08dd3132cfcd8ff10d61b7cd966e3c5dd35791704e5b4fbf18ceca35b3", + "蚌埠": "2eab90f937b71898e7697554140eeef83fe0b5301a6e992b234c791821be5b5b", + "宣城": "beae5eeaa5a02b19afbae9f03b088d3c5a4c1986c99d3f3deb9c2833fa1ec51e" + }, + "新疆": { + "图木舒克": "25989991e09e1a906667406b1f30142fd93050b862f50c0d699297c2cf6d91a8", + "喀什地区": "cd844af6fb9288c40b4c9b59567e0d81f32d8c16c955fc26553d3ac0575efeb7", + "五家渠": "e7e1e8a4f80fb623805d5526010b26a38b9304039a91aac0802b919918aca2be", + "巴音郭楞蒙古自治州": "f486a6a0db1f6c0307f2c5295a675fb8158add2adb7973a3981fa1fd60000e13", + "克拉玛依": "8d35daa05b16b6b0eca24db6f8d783621f500ccd728eed28a0548c599f5289bd", + "阿勒泰地区": "a4df561a2d85a8c3f9624deb2b7825ea7a6a8917f1b9c33f8637d82ead1cd657", + "阿拉尔": "1f345b7a58c83cfd7d74826eaf199983833452a68f3dce9fc69ddefc49e2d1ce", + "塔城地区": "672df7487dd18ef1a84ad17905e8a87ac7e477445d44e97484f75ad34da7195f", + "克孜勒苏柯尔克孜自治州": "a6a6b1fa3ddb78820e113d70ec81e913bc87315637e2543bedd3a7d928379f01", + "和田地区": "677860c2b64bacecd748cf261203de8b2d61be3fb584b2331d9c9551f225ef7f", + "乌鲁木齐": "08a4b89703cb47f718cc9c2505b7e5cb783a49e75db80a4052f60aebd8e40495", + "阿克苏地区": "c50c89e25ab7f493510d72d71ee28f4281b130c4720cd9aa232a76c733df5cf3", + "吐鲁番": "f2f31db4a10b527ad62dfe0f01ac3c383a15c2369a0503d69ee4a6d745990aa9", + "博尔塔拉蒙古自治州": "c1d66a1666d57799f809cb02cd6a74bb65b1aa3b70fe21d38fcbce3025e45937", + "哈密": "c546ed2abfa04684697603ae256d4c7eb373935db996c021077f5669375687ac", + "昌吉回族自治州": "f9babd2b7ccac45ca74bffd316be7b20b42c7fc26f5875256c1a8f0f4cb902de", + "石河子": "828d503f3d3ece9d927167a1bdf07887ce6d49093d94b143d35cda83e93365b2", + "伊犁哈萨克自治州": "ed140f77597b48b8ba22e239e005f34f56fd06693038bcf36e415446aeb5b8ff" + }, + "贵州": { + "毕节": "7a0ce626537da17533822b9b193e7e52cc81a72e6635f94157a3e3dd9f43e7b3", + "安顺": "0067f4bd5364b21053203955c4ce388aa2cc71ff8e433791592013949d2c268a", + "铜仁": "45915d452488c8172f8a75ca47ec6702a429554ce95215803673df84298f8ab8", + "遵义": "7dbb8806b7208fecbca03c7ec3ca9c1e5aa6fc41ba549fd559ef798e46fe6327", + "贵阳": "50e73ce253bd1a6ca03d9a6ddada0d5b8eaf3fd8f9b36379c5fa6805ca24c5fd", + "黔东南苗族侗族自治州": "f1ab4230be39dffdc5dc9d225906c29136d354d2051c4d9515a656e433042f72", + "黔西南布依族苗族自治州": "3ad2fe7e6e5958189cf10cca222e0b0c9b4e63df1726e89a5d3541f351ea7dac", + "六盘水": "30daec188f07c554848f85edba10f30b6116af1fa762806567a306faafe98811", + "黔南布依族苗族自治州": "137a314334c8a599b270acf7595d5e91a9f1de6cf3f0d13c15bb9236e384bd8a" + }, + "天津": { + "天津": "a7592e635f9ecdf5ec2c6264d74132d8984dab1542a7b69874328df8d6cbb9de" + }, + "辽宁": { + "阜新": "732f28fd60e511db1db85ae8e5f26c75e3be7f2ddee85c4007358188588f2899", + "朝阳": "3b544535da4d1a59f06c84c7a940c1f2f5a8b769d5287616660268c21f967cf9", + "沈阳": "21b8338af3a947b676e398e23535608d4abac51585f5169b1326543e99f2b16f", + "丹东": "4268488e4da0a244f5fe560337f9e1008712d2b4b870fb968187ac25703344ab", + "锦州": "f6c89bfc5c82ae8debc8e83a14306feb19a6f47b0487bfcd5117b4998236b2bb", + "鞍山": "2c3e4ee9675b08aa262d4ceeda4ff1b174e0c983baa0cbba15366fcac967f457", + "盘锦": "005925bfc67991e9b34a2cb760dc5a7df34f14c92ba2806cae9d671586061f9d", + "辽阳": "401a6a9bb2bad235da16475eca76eaa7dafd0f39d21ca27158497f9b653b89f6", + "本溪": "80658a4556dbd03947ee01f3e47acdd2a03251f2b79715a6a645a21734ea0fbd", + "营口": "294766a3c4aac58af47306b34821b192d2b4ad2cfcb661d88563fe3ee544bd14", + "铁岭": "cdad8012d9a5b12a2b898c2c1350d42cb037618efe1a3e6270962e3333763618", + "大连": "5c47af45660511fd9a03896189c4d424eb1c4acfee874944caa11ee9cb879fee", + "抚顺": "0b41e1b94381ca5fa24f516a5eb785135b2a2327761731278657867d5c2d84ee", + "葫芦岛": "717f7afeb6e2182f23340f6de7752b879388cf57f025a06b4f164fa4a6c82fd3" + }, + "宁夏": { + "银川": "60a5f061a47381709ae5463c13ec3ad17bcfeba930a82bc1bb84a0f9875b9ebf", + "中卫": "8431cda158d1c98ceabaa40fdaac4e915caf9d51b05257ed00a03ed7d4cea94a", + "吴忠": "b2401bd669d3ef7047dacd0be84f099a09b57d91595cf02fde43675c4fe0b4ec", + "石嘴山": "b771f2884a95df3952a88529ecf8906337eeac7a70e1347cb27e20ef1b1de74e", + "固原": "14b5e52ba02dc318a9673aa9000feec4b8d19abed7cb629a39d917763cb9b203" + }, + "浙江": { + "丽水": "edb6128328af61e4dda9cd4044f4f4f8008b29106ee7fea31ba20264a482c35e", + "台州": "80df907846f7b37e4af59437aa78c329b67e567c6a2fb33477e990d20cf5ed39", + "衢州": "07d6949c39f860eedb5c285bd844bdad572ab8a0001c53b29791955be7217394", + "宁波": "b229917740b7dde6a3c135b9db485a3c335b1a936b809c7d87bf94df8cb1338b", + "舟山": "75a9592dd3baeb59962b7ab7bb1f7ff77cf2d25f829a4dd024faf05cecb7f9e5", + "杭州": "f4e2e63dfcc978dbca62acfb7b4a1f3af049f91e80bde2aba47d2f1dfbeea2f6", + "嘉兴": "bc0b15239f293e635cb4047513d519ee9a604503be8c43bcb3dba974ea38a5dc", + "温州": "807deb1e7e56a8926342fc7a2b8dd0f4cfad0218fc14dbd2834613340bf87db1", + "湖州": "2f5efee3185269172ea9d5ff14e84106a3779801cd4dbf4b3b6b2779dbabd474", + "绍兴": "2b87378e7ec09455a9f4298398343eb1de1ae844b9557fea1e51a91d3c1b4547", + "金华": "8f5a04e833a5ad0b1edf00ba9229a3b0d706eb3340c40ec8fb383e9949e6cdda" + }, + "江苏": { + "宿迁": "fb14dd83b3e1bebe4854270310b7a43a94037ca537d030c57321641e0f2a8cc2", + "连云港": "7ba3e8eb85c3f93470d8d2ecce67f873a563b2934ad64ead2899d0b0269c4b60", + "常州": "9324841f94e58e1352b1b56d49c017726d5f604d781690390d38040fe02404f5", + "镇江": "6357bdb47e7baa15947c7825f0f02d2bb6c7858475a6f5445cf03506ac37dc78", + "无锡": "915467a82c43b854da8194cc405143ecd0e4a1dd95aa7624437ed94d3fbadeca", + "扬州": "ff4185687c14630fceb95f2b5f1cb553fe39946279d2d452c28b020631f8faa3", + "泰州": "f873b74b459064838e58248d1d266ac3071a374a77719b5c8b64eb30366dc27a", + "苏州": "def92baf4c44a2a758c6bba8d4720942497441a057fea35e26563f9baa75c4a6", + "淮安": "6998147cf1e33b0524cbef714ff3bbc128575880262f29b7e8466aab1d5891b1", + "徐州": "8daa7dee0b759894382e3eb1cf53dc567d4af482b5bf99a03c557bede52290b3", + "盐城": "d01d03a7047f2ce60e4f278976784e1ada32cea72ad1b276573ede5455a14755", + "南京": "ac7a6bd71272fecd3c2581cfc33c13c06990ed39a734fa151c854dcfaae8cd7b", + "南通": "f8af0c3ec1d5c2809e49817171d723e88612f0ce3b71f5aa9360ffc0d454a980" + }, + "陕西": { + "西安": "10a949a9ea60c62b85398a426cad724b7a8cdd4b6c782e03849b76bbaccf2a2c", + "商洛": "e3f3a7aa8343f1cb7c2fef4fe9865cf516011eb1ec1697f47d9a8c0e1e042502", + "榆林": "719c4c06424af87274cee1fab24f94b19010a9a5467b6cb1e39942265c275cbe", + "汉中": "edc47e4ff952417449e460d84ceff7a775c478e246ad1ca8916d15818216293a", + "安康": "5e19992fd60cbd22d13d237f7aadc46714e0b6b8d4a8f223796eafb9d04311c3", + "铜川": "89b1576896695414a9332988d03991adcca146fbf93044639398981121254a50", + "延安": "82dc5180aadc67e6897f9788111744111a4c14f9109275463cf7a796977f09da", + "渭南": "34d236814dad0ce1ae984d3a197a7ae2e4881d5d7796efe11b111ec08f695074", + "宝鸡": "dac72c01c94bd3d9f7301893d2627836f1640d797f16724ce33c8126ed5a4a53", + "咸阳": "8da50c12630cbf3c45500ff886e3bc8f7992214f17dda97d1be1633d8322c680" + }, + "四川": { + "达州": "475e46ceb4b3444de5a289a24e6a9261e1ed4c4e4881bcaa9f54d77211f2b770", + "德阳": "01c2d1acf783b5ac014f87dfe06d9a731c654d42aef402dc68965b9194ee7b2a", + "甘孜藏族自治州": "093ab1e0119613935c5709a67af2b5722f61f807d49534a80e1b5d8e7b288dd4", + "阿坝藏族羌族自治州": "820def821c8572fe8590624d840605c8e69db41577b8d7e85a3a2a98b580063f", + "绵阳": "988dd0008c5b1cda2c1a602226343742281d9d723c475ac7216e6c23a8e26c61", + "广元": "ec51fd8fb1a1563ef8434599cbd9a7995d6bd72c94a4a4880811e6fbbfaa6085", + "乐山": "4e61e41d9f37eec9ee10c1dbe06d0ee4811b167aeed0b56fb8f0c4cdaaada187", + "内江": "f222ada64b15fd48922e0d27a517c21d3cacd4723004b14b76dffcb697af6f55", + "资阳": "902d065119a5f1826ea26e1c748325e03948fc716f8fda94f5350f11fb929c77", + "遂宁": "3e438d1e20398f676851302e40b9d1f2a086cc552bd81dcb7c661c6ce4f7a93d", + "成都": "69cb4668ba9bc5d70b80ea2b48eff549215126ce412a2287755b4f494c459ae1", + "自贡": "0d9ecc66423452edd9d2fe9e9ec5fddae1ef1e5b0d6d6994164dca4aa85b7976", + "巴中": "aeaf6197d6c6d2f5279283c7dc471e509efe67fe34b9d1ecdae10b8d1d037fef", + "凉山彝族自治州": "c8c2bb88c71d70ed022dc7513e8a1e4bc9100ca76beb702a3397ba28e857e2db", + "南充": "4a04a1900273abaddc0ac4cda52d50fa84816c30a50467c1fb85c294736c114e", + "广安": "fb97ee4fed88c5dec325c30bdd144ce61484630173a0faffba4157efd9dce73e", + "眉山": "081309c7c236a6444e2a1c2e0482c265c2f2cd867555cfdba4d3c43bf50156b2", + "雅安": "477fce41f300a2782ee7ab9f9d7adeca59db64a6087f9afac7ab72b2d558b27a", + "攀枝花": "94f422d28120b90268aa489437952d88592765d81214d32488dec64eb8da9401", + "宜宾": "a14269764eb749b59c13f3d53c74b1aa47c9dbbb56bb6e9cc5fa9a492a7f03df", + "泸州": "8a63941727e5f8f3dd1462bc938f3e8e7357fbf7327c11070a0f8cad2ad93806" + }, + "河北": { + "秦皇岛": "f9e54ddc5f122e9621aeaec9cc09089764feb41c4fa09883de8f0053fe0ec0ff", + "保定": "2d6f8cb78cfb37062aed2e372b790f1f8a0983d8c57c07442bf4a94dbd5c390e", + "承德": "2c44d1b61490017e9d559e9340031e9d8a3332948d7ce8ed57d97bd0ec570f12", + "唐山": "6d1fcf8cecef4360d0dce5bb748d29d886cbd77dc28a63c3889ae588ed6a745d", + "邢台": "09b867aaaa27966c5baa9e506f7ea2fdf2c7101e10133a8bd1a51d68c523c4ab", + "衡水": "7a87e60b8467486590114d7afee60e06db96f4a1e94b1c767466d84805c86da3", + "石家庄": "29e410a42310a65dc858eb3edde06b3d5eb62a6822d861ff51c2af5703f4dadf", + "廊坊": "d1abd4a7bdfe90578217e032908f66b648f955da5170ee3b29d5c3ac0aa8dfde", + "邯郸": "caa4b77aeaf88fe86fe89347bd9e3c7df7f45ca15dab5a89b25fdf175c094be9", + "张家口": "c54a64e21318cde713535712f9dc885a8770912c18b1162c6712a8daba7f6b51", + "沧州": "7e92f292147f124f01b0e02525396fb46f4e8e58f8f757ba46efe7ddb05266f4" + }, + "山东": { + "威海": "3f91b9a7661c746b1fff9b02dbdbbd0e283b53a5a60374681a358edc34d6a1c4", + "滨州": "6195152f0ef054996154923162f3fb7c3dae08d4bd97c322233f36fb3d552d7c", + "泰安": "3025b7a8ef7642e4db1990c3a2df4fe1826983fba2bfb036c395498728c4fb84", + "烟台": "a0c8aa1904e744129d94859c4a770c0b877ed724405ebdf14fed50f400779b76", + "济宁": "478d415c9656cd813bf46d89f28199980372f192723d815feb688a3c3dd3e02e", + "临沂": "383149d5d21b8857937949b34a55036c842656dd49b308c357574b481e129e0b", + "淄博": "31b9426133fe3964d31b77f9a60b3fb0f921878ad007941a3cd9f00fb641f6e2", + "菏泽": "7010e97fce38f0a1ea4a38df513db182daed68888e18c7b95f6b72af99445be3", + "日照": "48cfa55e1b8629546ee525668dc0bed9a3127d6b061a874e9a6ba14cf139a0d7", + "济南": "162cce80baae804917ab0deab913b20520a85758712a9dec24f143d0617e1288", + "东营": "5747815b2e3b66dc9cdee10f3a0e2b0a06e7e52f9068b92928f6cd1b3edc4181", + "潍坊": "2d779be33d220ddc6085b188e0fbc4c2397bb3c96c36f6a78d7ee9990e85c622", + "聊城": "84281e52f5705d0334e53677c3d5163849704231aebe5073a42a2a984e911e05", + "德州": "aea7168dec3a43d8c0bfa761aa0414858407c28d8dc4a9689b933026cd56e558", + "枣庄": "122564980cbc3615f8a713862bd945f4f3bb23e82224697ae88c33c492824311", + "青岛": "e7f70b6b689a187c12f2c76ff94e38dcf0ae6a9a57dfd30d1501330c07fa7b2d" + }, + "甘肃": { + "兰州": "4380e94169ed0ffe6cef4e21c948c9f019a0085f40037f0798f68e0f5f6fccac", + "嘉峪关": "49cf4a71419c01cd9e62b08768bec2347be87d48b4e7bd7b85b161573f173820", + "平凉": "95eb177e28a866eca52353abb2c81af25b43b05bccb804ad6f3f31a146a35582", + "金昌": "9f1b31685d1a871e633649468379c7b4072037540ca7732c53d0195c7c5bb1ce", + "酒泉": "8113c9122286bd10eac8e89c3c1aa0f335cb53a9b33e1bf8762412b350b3cfe3", + "陇南": "3ccd3850f97058d8d2b0068dc6581f0e65e939e92c5c91718330bd634c712844", + "临夏回族自治州": "1f04b454f31658801344eac92a563e507952f59e0fac2d984ef5973e72aa390a", + "白银": "d818f779752d0b82dfd12eeccc7aedc757a8d15cbe5f5a05e266fcb267ff98a6", + "张掖": "a2aca4796e86c1dfde7ebb3d0db807bd76e41a6efddd73d64abaefb933bdba60", + "庆阳": "1928732413c69cd4e5624f8ffd7f3b2f5158c0dbc54574404d5b4da6eafecc67", + "天水": "f5d329369ffebfc892ea0344939ff9226fe6039b993bb5148cb518140e9f94b8", + "武威": "7ed9793a78a5b6c90222f78315c77ab2c0b04a71a93f7022367fb3bc0da09b96", + "定西": "1c99cd710a13e38848b0695f020dd0cdaeef099cdc41d01ebea2d3ec896646ea" + }, + "西藏": { + "拉萨": "52e5ec9b88e072482f49aa8eebb9d0ece5e3ae51d70d2c71eddddff0c154f2c1", + "林芝": "eaabf5146d073f8f9659d97538dc9f6b48d86aa472793ac3ad7817562db85b77", + "日喀则": "12bf81609e081e2ba8798debf4b8924e35cde201f284f7d419f837f808e0345f", + "山南": "b2382db47277f8ec8aa34d74d38b76c973d4dfe6aee72abb079826b0164bf10e", + "阿里地区": "7c4ded71a672b171b2cdb0ece3a28ed6339dfb97fc2c7f4f1a4b658d75ceff22", + "昌都": "476f5f01d149d6f7fa5cffcc5846b3976cc3dd7774654ef04664956ce14be84e" + }, + "内蒙古": { + "乌兰察布": "093326b72938f2b2d636ad1a392aaab4978e61694aebaf7a88cb9fb85727165c", + "兴安盟": "2984bf0ffe5c6fff61138fe038bf6a8d1cc7ea582767012e722a978357312f9d", + "鄂尔多斯": "35317092916e9667193f6d87b3e610a396da1e9e02c992dd80c2b18b012c33fc", + "锡林郭勒盟": "61121b20c9652e616b72cb222e11495007f0991248cbc5b74fdba145bf0d7e22", + "巴彦淖尔": "debb9c9c4f109b8c5a9213e980632f708ff13eed666a6d73c546566fd0ebb815", + "包头": "d4a291c95b66aec05e6a7c81cedd639354baa280dee07ed5af9b5750e7a4fea4", + "乌海": "08a57588cdd5003c223f67a9eea92634bcff7cd8b8b121c763ce010cbf13caf1", + "赤峰": "18394066775092d3268febda26c5593d24a2b1e06120d5945c8f00dd9ec8ef58", + "通辽": "d6114245103ec6f1c6a9fae406660aa8fa630dfcc10c38a6a2762fd1c8442f96", + "呼伦贝尔": "b64a71e92db203285da9cf8de095ba4c3159fa88670c33be2fa59d2797a18500", + "阿拉善盟": "ce9a09c5026efa30e2d2852a8cba2136b999872d026c85ad981de77f4104dbf7", + "呼和浩特": "287e8d6fc15c71fe267865194e7ec8e14a8a0d1e8aa62e22bb19e8dc2fb6354c" + }, + "云南": { + "保山": "49bb63acf8bab79f272025be7e1e7b56877c4e24096a9430831be0b34c6230ce", + "临沧": "9ad1663c65e820a1d826306591f19544e9e49b450231029eb6a66a1841c361a9", + "大理白族自治州": "511ca60b4d6cf0dd0ebf02f9a5e78bd6936a6fb20219da5b8f346e03cb419ebb", + "玉溪": "24289ebd3ef33888c9931a5259c0cbace80c4eb1d6d24cffb130aa64532ec666", + "普洱": "398c2f0448b09d822aa12132903390cbb929d4d87ef578c77f978e98ff27f66f", + "德宏傣族景颇族自治州": "16dd42f4b8a5e5c8929e64a59015249c1e6728f5f6f1cc5376ebadd08b193c62", + "昭通": "5515148d6a50997b367a88985abafd67af6c9181b8c444f478bbde343a96c6b8", + "西双版纳傣族自治州": "d1391a7c498fd9dbd861c388882268517aade395ae4674919f650eaed3e760cf", + "文山壮族苗族自治州": "6dafce691415eeb72b86b9529e6d05773cf7e94df13957d3df64b37267cc2fe8", + "昆明": "0cd882c20fadcb22c4f57ac445e40e8720564c42e9f344d461c27a33e15e7302", + "怒江傈僳族自治州": "01c0d12c36bd84290e6f00efa890e9e6e502fb888f2e3ad46f1de04ea3004939", + "曲靖": "3e650b4767b3580bb8fc45aaa583b37e0f28a40183203b4079f1f91834303120", + "红河哈尼族彝族自治州": "eb544e910b8d5ebed8e4c27c215e7b80a1c08e15742f31b8a70848a229f7cf9b", + "丽江": "6b018596f498a4ea06ceac55ad0921efded19a608c92c7b893b671000498bf1e", + "楚雄彝族自治州": "480775b883401f2ffb45a610f8e1d689b3e918d169164f4b68ca6c580c9c63cf", + "迪庆藏族自治州": "8c8b304abcf5bed5f0de2243f2bbef134b24810ce3383a004ff94766813e1415" + }, + "北京": { + "北京": "fc5b91e92919fa705d71dde222b3fb5e7da26bfa0489c9dc60c0a0117f692481" + }, + "重庆": { + "重庆": "4b0b86dd5a879aad9c356fe23559fc0456894e0b1fd580c7cf12172ae4014bb6" + }, + "广东": { + "清远": "7de860dbd0737ce60177ab16ce7448e67303179928cae696d979922af14ea0e2", + "韶关": "cccaa03d2beff9078c26b26532c7c08a52d6d097252d994619bba7454d767093", + "云浮": "4ccdf8d5214f08ea9b1fd4f4e8caf198eebab00409d38994bbf8d14a3aadea38", + "汕头": "84e4ab89d632efa6fd5e9e9d2f9e48c042c48207092fd61f53e14adc1286c731", + "肇庆": "f6eaff0e140de33e510b0285337e6d3c0371ef8e4aec042c111d70745f0047e8", + "梅州": "ce3ff2def5ed1768ca4fc783e032af802577e3d8ab54c003126cbea82c6e9a8c", + "深圳": "2bd4cdcb39010610777f48014f78016f39e8a0b29171e8b7035d0ae4e831ab8a", + "佛山": "625d17f7359cbcf47504ee30a2e30189faee9637a72ad321e497dbd9cd6420b1", + "湛江": "e8a8a198f537af53045f0df2604454a2407e46d2ceeb96c47b4e0cfac16a3cdc", + "河源": "2a8dc5b6ce2f186bd987e616eea29600b06bf6fc65f6e2ba2b0d5e03b857366b", + "广州": "ef26cdf15454e2aaba125512dcb6b509f0a9c02e0807ac13d4b77cbff52fe05d", + "汕尾": "eb8625b5c32e0dd451e11f2ee99be1d06257e27255459617686d93b3240ac50d", + "揭阳": "357581967dc2b4424f9713838937ddbb28de24087979969e58b52164141dd2e2", + "潮州": "fa204f0c04b172c5a4625df6ca911705a6e997a895372fa66b516d679b5bd892", + "珠海": "f74f2b15ea4ae3e5bdb11d2896384a148920af47f4b02a97b1ee9df9d7048079", + "东莞": "64e55d5c9494cdf13a1e94c1a7cd3bde927a8c18ee301fcf45ee87a6257c1633", + "惠州": "26d125d3f04748e748eccafa0c07d09212dd738ca540fb728b8202c8419f13b9", + "茂名": "9b90d5d8c988589e091c5474b51d6363ef597bc93470d5d49ae37006e02e38ed", + "阳江": "5ee66061902cf489abb7049df1ae30c1ebec5af64d62bf71f37af52173a0c1a6", + "江门": "516e664c20bbc2ac4cbfe29994de2adb4085b955a09f3cbddb7d2affab892237", + "中山": "0cc0187bc0a343ecd70b45296210ae75fbcf2de169435d1ebb8162ac7e43a1ff" + }, + "河南": { + "驻马店": "3a420ecc73a3708c0b29d9234a2fe6bf826ffc772cb24fda610be3fb0d47b2f7", + "郑州": "d04d3272b31a08c0d5b4e4cf67e44ab13278779cedb36a9d76a7a7c496607921", + "许昌": "145bb2cb4d3e08b546e50b7e91cb3e200d57e183ab450b57dfb73a67603b4a52", + "濮阳": "873d0b32df02e4df984dda751ad22bcb62b1943031ce2a8ce48de7d98af8ba88", + "济源": "1a6f7e765a34e824ac4792602ce9737a2d99535db6f4f86dd9f310de9af4e8d8", + "平顶山": "b0032649138648dee28b02be9983795bffa29bab863e9ca485fe80961ee8abc4", + "焦作": "0459d890ed89549bcf4853acfb1e34ecd3da4ac33f85f106b50a6b06c8ce68c1", + "新乡": "cef3d46ea594a50a5ce6bd7398b9d24670bf9c4b6d3557bc0826ae0665559f18", + "洛阳": "572215ea307cbfefa5bf1e9a374c5d6a71345c1a51d381c301e5bef55968e29e", + "三门峡": "795c7a18d6e77107a5e921b9ba51d47e4cdbb0133638b6e1b9b9af88afa75baf", + "信阳": "d62ee5e45302c68e20bc470bba296ce5ae6aa8bc1a09b0839a47e4109a953b96", + "鹤壁": "6ac368de2bea769ede9cf8faa7d08b3075b785addcdc1c07b8fc6ffd61e5c38d", + "南阳": "2e46620b685d1cc887ca216bbe03713ebe2ba2baa9d73a824219b89f88a6cd88", + "漯河": "c7d8597a8473e8f4824dc8ac00ee406ed2d678e1db6dc3e4b2521b48886acfb1", + "商丘": "1ce44841858aa9ffefe65156a6e4bb74975a5abe6c2ffb2e9d8034fc6da3dd6b", + "安阳": "360d58a276ee7c82071075d5926a494886eb9e05637519db1350c8ddb32aa217", + "开封": "2435505ac5365e5913948eae254d46edb5b4f464b246499cb8688bde1089bfb8", + "周口": "46845e2a41db7e8bf0e6f1d1f42ad76652d25956e81329cb0a8e9d7df3ccc51b" + }, + "福建": { + "漳州": "e0167e025b5a699e50b3fb4ec4c43d27bedad6e177cf394b51ac7717a05d9f96", + "福州": "7d8b79d62c74038751de9895bbd0b22fdaebd3a4e1f58ca8e7c6ce06f769f15e", + "三明": "9ed66af07e9f169860686e2cb7f2e15aca4b7bb1691de1d298e7193b41d9b155", + "莆田": "c0256c28f8293c6b4e5f78f8541326a58f8e623fd0062f294291c8680ced10a9", + "厦门": "99b4026bb98da7fde0add4234c9965c9334de7b7ecf01581639526a665dd0091", + "宁德": "320d9f5366a0c5021cc0cf849c91998f17c231fdb94e3bfb8cebcacd671a8437", + "龙岩": "14fc7fa4ca25513cc50460f17ac2a42f932f55fcd95690f10788ace672d8bf7e", + "泉州": "6f6ef82fc0b29fb8f7e228cb02c8985cd5c88f1ea9b75107821896d98a3db24a", + "南平": "5d2add4042142bb373d83a09e38ddc9f216cb18b7425685c9ec86e21040d54b8" + }, + "吉林": { + "辽源": "6efe00a6073c78d6f77d318434bf06d2df6c1add418c14a2768aa3bd72711410", + "长春": "87b94e06fddb475f893643a6888240f77ff4c9446d153a65ac565505714c533b", + "延边朝鲜族自治州": "86f823309a4e5336839280d878821040db3d107f73de91d9d2bc5ceac5af762a", + "松原": "a4002c19888160b7f7875e7d5727ad8a0c7323af8070f39dcf60895112ac1283", + "白山": "0cecee7c061cd8037717d5481aadd35c68ec0f4f1a8ee88138aecb19d8f33276", + "通化": "e0ce2af43685ba15e22660b8d487d712673545f61bc34283b203fef5f620fe8c", + "四平": "6f3fba4383e19094a8bdb06ef3007da4ff05b17faa77309baadc9b6b90363395", + "吉林市": "94fdf6d0a0701120800c12ddf2cc5a09f47d5f228e2089987c074df79187dd99", + "白城": "bc41d34110c2989b29f7521133d605e7a8aa6e9edb488217c5c0d087603a753c" + } + } +} diff --git a/docs/device.json b/docs/device.json new file mode 100644 index 0000000..d5735d4 --- /dev/null +++ b/docs/device.json @@ -0,0 +1,39 @@ +{ + "code": 0, + "meta": "success", + "data": { + "count": 5, + "edges": [ + { + "macaddr": "DCD87C13AC99", + "public": "113.110.228.134", + "isp": "电信", + "single": 0 + }, + { + "macaddr": "DCD87C21B5D7", + "public": "120.232.63.156", + "isp": "移动", + "single": -1 + }, + { + "macaddr": "DCD87C0B941D", + "public": "120.231.246.244", + "isp": "移动", + "single": 0 + }, + { + "macaddr": "DCD87C0D3FC9", + "public": "120.229.75.80", + "isp": "移动", + "single": -1 + }, + { + "macaddr": "DCD87C463F1C", + "public": "27.38.68.239", + "isp": "联通", + "single": -1 + } + ] + } + } \ No newline at end of file diff --git a/docs/gateway_config_get.json b/docs/gateway_config_get.json new file mode 100644 index 0000000..f829e4e --- /dev/null +++ b/docs/gateway_config_get.json @@ -0,0 +1,5 @@ +{ + "code": 0, + "meta": "success", + "data": "eyJpZCI6MTksInJ1bGVzIjpbeyJ0YWJsZSI6MSwiZW5hYmxlIjp0cnVlLCJlZGdlIjpbIkRDRDg3QzQ1QjdCRiIsIiIsIiIsIiJdLCJuZXR3b3JrIjpbIjE3Mi4zMC4xNjguMiJdLCJyb3V0ZSI6bnVsbCwiY2l0eWhhc2giOiJmYzViOTFlOTI5MTlmYTcwNWQ3MWRkZTIyMmIzZmI1ZTdkYTI2YmZhMDQ4OWM5ZGM2MGMwYTAxMTdmNjkyNDgxIn0seyJ0YWJsZSI6MiwiZW5hYmxlIjp0cnVlLCJlZGdlIjpbIkRDRDg3QzRBMzFDNCIsIiIsIiIsIiJdLCJuZXR3b3JrIjpbIjE3Mi4zMC4xNjguMyJdLCJyb3V0ZSI6bnVsbCwiY2l0eWhhc2giOiJmOGE1ZTliMDQxNzg0OTBjZjhlNzFmNWIyNzM1MzhhYTc1ZWYyYzk3OGVjYWM5NzRhMTc2ZDkzYWY5NjZlZjUzIn0seyJ0YWJsZSI6MywiZW5hYmxlIjp0cnVlLCJlZGdlIjpbIkRDRDg3QzJBOEVDMCIsIiIsIiIsIiJdLCJuZXR3b3JrIjpbIjE3Mi4zMC4xNjguNCJdLCJyb3V0ZSI6bnVsbCwiY2l0eWhhc2giOiJlZjI2Y2RmMTU0NTRlMmFhYmExMjU1MTJkY2I2YjUwOWYwYTljMDJlMDgwN2FjMTNkNGI3N2NiZmY1MmZlMDVkIn0seyJ0YWJsZSI6NCwiZW5hYmxlIjp0cnVlLCJlZGdlIjpbIkRDRDg3QzQ4OTY5NCIsIiIsIiIsIiJdLCJuZXR3b3JrIjpbIjE3Mi4zMC4xNjguNSJdLCJyb3V0ZSI6bnVsbCwiY2l0eWhhc2giOiI2OWNiNDY2OGJhOWJjNWQ3MGI4MGVhMmI0OGVmZjU0OTIxNTEyNmNlNDEyYTIyODc3NTViNGY0OTRjNDU5YWUxIn0seyJ0YWJsZSI6NSwiZW5hYmxlIjp0cnVlLCJlZGdlIjpbIkRDRDg3QzBCOUNBNiIsIiIsIiIsIiJdLCJuZXR3b3JrIjpbIjE3Mi4zMC4xNjguNiJdLCJyb3V0ZSI6bnVsbCwiY2l0eWhhc2giOiIwOGE0Yjg5NzAzY2I0N2Y3MThjYzljMjUwNWI3ZTVjYjc4M2E0OWU3NWRiODBhNDA1MmY2MGFlYmQ4ZTQwNDk1In1dfQ==" +} \ No newline at end of file diff --git a/docs/gateway_config_get_info.json b/docs/gateway_config_get_info.json new file mode 100644 index 0000000..608ff72 --- /dev/null +++ b/docs/gateway_config_get_info.json @@ -0,0 +1,61 @@ +{ + "id": 18, + "rules": [ + { + "table": 1, + "enable": true, + "edge": [ + "DCD87C45B7BF" + ], + "network": [ + "172.30.168.2" + ], + "cityhash": "fc5b91e92919fa705d71dde222b3fb5e7da26bfa0489c9dc60c0a0117f692481" + }, + { + "table": 2, + "enable": true, + "edge": [ + "DCD87C4A31C4" + ], + "network": [ + "172.30.168.3" + ], + "cityhash": "f8a5e9b04178490cf8e71f5b273538aa75ef2c978ecac974a176d93af966ef53" + }, + { + "table": 3, + "enable": true, + "edge": [ + "DCD87C2A8EC0" + ], + "network": [ + "172.30.168.4" + ], + "cityhash": "ef26cdf15454e2aaba125512dcb6b509f0a9c02e0807ac13d4b77cbff52fe05d" + }, + { + "table": 4, + "enable": true, + "edge": [ + "DCD87C489694" + ], + "network": [ + "172.30.168.5" + ], + "route": [], + "cityhash": "69cb4668ba9bc5d70b80ea2b48eff549215126ce412a2287755b4f494c459ae1" + }, + { + "table": 5, + "enable": true, + "edge": [ + "DCD87C0B9CA6" + ], + "network": [ + "172.30.168.6" + ], + "cityhash": "08a4b89703cb47f718cc9c2505b7e5cb783a49e75db80a4052f60aebd8e40495" + } + ] +} \ No newline at end of file diff --git a/docs/gateway_config_set - 副本.json b/docs/gateway_config_set - 副本.json new file mode 100644 index 0000000..2e1f461 --- /dev/null +++ b/docs/gateway_config_set - 副本.json @@ -0,0 +1,62 @@ +{ + "macaddr": "001122334455", + "config": { + "id": 19, + "rules": [ + { + "table": 1, + "enable": true, + "edge": [ + "DCD87C45B7BF" + ], + "network": [ + "172.30.168.2" + ], + "cityhash": "fc5b91e92919fa705d71dde222b3fb5e7da26bfa0489c9dc60c0a0117f692481" + }, + { + "table": 2, + "enable": true, + "edge": [ + "DCD87C4A31C4" + ], + "network": [ + "172.30.168.3" + ], + "cityhash": "f8a5e9b04178490cf8e71f5b273538aa75ef2c978ecac974a176d93af966ef53" + }, + { + "table": 3, + "enable": true, + "edge": [ + "DCD87C2A8EC0" + ], + "network": [ + "172.30.168.4" + ], + "cityhash": "ef26cdf15454e2aaba125512dcb6b509f0a9c02e0807ac13d4b77cbff52fe05d" + }, + { + "table": 4, + "enable": true, + "edge": [ + "DCD87C489694" + ], + "network": [ + "172.30.168.5" + ], + "cityhash": "69cb4668ba9bc5d70b80ea2b48eff549215126ce412a2287755b4f494c459ae1" + }, + { + "table": 5, + "enable": true, + "edge": [ + "DCD87C0B9CA6" + ], + "network": [ + "172.30.168.6" + ], + "cityhash": "08a4b89703cb47f718cc9c2505b7e5cb783a49e75db80a4052f60aebd8e40495" + } + ] +}} diff --git a/docs/gateway_config_set.json b/docs/gateway_config_set.json new file mode 100644 index 0000000..effaeb8 --- /dev/null +++ b/docs/gateway_config_set.json @@ -0,0 +1,63 @@ +{ + "macaddr": "001122334455", + "config": { + "id": 19, + "rules": [ + { + "table": 1, + "enable": true, + "edge": [ + "DCD87C45B7BF" + ], + "network": [ + "172.30.168.2" + ], + "cityhash": "fc5b91e92919fa705d71dde222b3fb5e7da26bfa0489c9dc60c0a0117f692481" + }, + { + "table": 2, + "enable": true, + "edge": [ + "DCD87C4A31C4" + ], + "network": [ + "172.30.168.3" + ], + "cityhash": "f8a5e9b04178490cf8e71f5b273538aa75ef2c978ecac974a176d93af966ef53" + }, + { + "table": 3, + "enable": true, + "edge": [ + "DCD87C2A8EC0" + ], + "network": [ + "172.30.168.4" + ], + "cityhash": "ef26cdf15454e2aaba125512dcb6b509f0a9c02e0807ac13d4b77cbff52fe05d" + }, + { + "table": 4, + "enable": true, + "edge": [ + "DCD87C489694" + ], + "network": [ + "172.30.168.5" + ], + "cityhash": "69cb4668ba9bc5d70b80ea2b48eff549215126ce412a2287755b4f494c459ae1" + }, + { + "table": 5, + "enable": true, + "edge": [ + "DCD87C0B9CA6" + ], + "network": [ + "172.30.168.6" + ], + "cityhash": "08a4b89703cb47f718cc9c2505b7e5cb783a49e75db80a4052f60aebd8e40495" + } + ] + } +} \ No newline at end of file diff --git a/docs/gateway_config_set_route_中文注解.json b/docs/gateway_config_set_route_中文注解.json new file mode 100644 index 0000000..51febb3 --- /dev/null +++ b/docs/gateway_config_set_route_中文注解.json @@ -0,0 +1,65 @@ +{ + "macaddr": "001122334455", "//": "要配置代理链路网关的Mac地址,也为网关的eth0 Mac,也为授权时的Mac地址", + "config": { + "id": 19, "//": "配置文件id信息", + "rules": [ + { + "table": 1, "//": "代理链路规则id,可选项配置;rules数组中每个对象为一条代理链路", + "enable": true, "//": "控制当前链路生效的开关,true为生效,false为失效", + "edge": [ + "DCD87C45B7BF" "//": "代理链路edge节点Mac地址", + ], + "network": [ + "172.30.168.2" "//": "socks5代理和http代理钧使用172.30.168.2-251固定地址段,网关模式下配置为业务主机实际的ip地址,当前配置为172.30.168.2对应的socks5代理端口为44001、http代理端口为45001", + ], + "route": [ + "182.207.100.4/24:10.10.1.200" "//": 格式为:"目的IP地址或者IP地址段:指定出口的网关地址", + ], + "cityhash": "fc5b91e92919fa705d71dde222b3fb5e7da26bfa0489c9dc60c0a0117f692481" "//": "当前链路配置edge节点城市的cityhash值", + }, + { + "table": 2, + "enable": true, + "edge": [ + "DCD87C4A31C4" "//": "代理链路edge节点Mac地址", + ], + "network": [ + "172.30.168.3" "//": "当前配置为172.30.168.2对应的socks5代理端口为44002、http代理端口为45002", + ], + "cityhash": "f8a5e9b04178490cf8e71f5b273538aa75ef2c978ecac974a176d93af966ef53" + }, + { + "table": 3, + "enable": true, + "edge": [ + "DCD87C2A8EC0" "//": "代理链路edge节点Mac地址", + ], + "network": [ + "172.30.168.4" "//": "当前配置为172.30.168.2对应的socks5代理端口为44003、http代理端口为45003", + ], + "cityhash": "ef26cdf15454e2aaba125512dcb6b509f0a9c02e0807ac13d4b77cbff52fe05d" + }, + { + "table": 4, + "enable": true, + "edge": [ + "DCD87C489694" + ], + "network": [ + "172.30.168.5" + ], + "cityhash": "69cb4668ba9bc5d70b80ea2b48eff549215126ce412a2287755b4f494c459ae1" + }, + { + "table": 5, + "enable": true, + "edge": [ + "DCD87C0B9CA6" + ], + "network": [ + "172.30.168.6" + ], + "cityhash": "08a4b89703cb47f718cc9c2505b7e5cb783a49e75db80a4052f60aebd8e40495" + } + ] +}} diff --git a/docs/gateway_status.json b/docs/gateway_status.json new file mode 100644 index 0000000..f5968f9 --- /dev/null +++ b/docs/gateway_status.json @@ -0,0 +1,5 @@ +{ + "code": 0, + "meta": "success", + "data": "eyJpZCI6MTksInRpbWUiOjE2NzcyNDkwMTksIm1vZGUiOjEsIndhbiI6ImpkY2xpbmswIiwibWFjYWRkciI6IjAwMTEyMjMzNDQ1NSIsIm5ldHdvcmsiOiIxMC4xNjguNC4wLzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJzdXBlcm5vZGUiOiIxMTQuNjcuMTAwLjIyMyIsInN1cGVybm9kZXBvcnQiOiI1NDMyMSIsInVybCI6IjExNC42Ny4xMDAuMjIzOjU0MzIxIiwicHVibGljIjoiMTE0LjY3LjEwMC4yMjMiLCJlZGdlcyI6eyJEQ0Q4N0M0NUI3QkYiOnsidXJsIjoiMTE0LjY3LjEwMC4yMjM6NTQzMjEiLCJuZXR3b3JrIjoiMTAuMTY4LjQuMC8yMiIsInBlZXIiOiIxMC4xNjguNC4yLzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJyb3V0ZSI6IiJ9LCJEQ0Q4N0M0QTMxQzQiOnsidXJsIjoiMTE0LjY3LjEwMC4yMjM6NTQzMjEiLCJuZXR3b3JrIjoiMTAuMTY4LjQuMC8yMiIsInBlZXIiOiIxMC4xNjguNC4zLzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJyb3V0ZSI6IiJ9LCJEQ0Q4N0MyQThFQzAiOnsidXJsIjoiMTE0LjY3LjEwMC4yMjM6NTQzMjEiLCJuZXR3b3JrIjoiMTAuMTY4LjQuMC8yMiIsInBlZXIiOiIxMC4xNjguNC40LzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJyb3V0ZSI6IiJ9LCJEQ0Q4N0M0ODk2OTQiOnsidXJsIjoiMTE0LjY3LjEwMC4yMjM6NTQzMjEiLCJuZXR3b3JrIjoiMTAuMTY4LjQuMC8yMiIsInBlZXIiOiIxMC4xNjguNC41LzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJyb3V0ZSI6IiJ9LCJEQ0Q4N0MwQjlDQTYiOnsidXJsIjoiMTE0LjY3LjEwMC4yMjM6NTQzMjEiLCJuZXR3b3JrIjoiMTAuMTY4LjQuMC8yMiIsInBlZXIiOiIxMC4xNjguNC42LzIyIiwiZ2F0ZXdheSI6IjEwLjE2OC40LjEiLCJyb3V0ZSI6IiJ9fSwicGVlcnMiOnsiRENEODdDNEEzMUM0Ijp7ImlwYWRkciI6IjEwLjE2OC40LjMiLCJ0YWJsZSI6MiwiZ2F0ZXdheSI6dHJ1ZSwiaGVhbHRoIjo3LCJwdWJsaWMiOiIxMDEuODAuMTguMTE1Iiwic2luZ2xlIjowLCJ0aW1lIjoxNjc3MjQ5MDE4fSwiRENEODdDMEI5Q0E2Ijp7ImlwYWRkciI6IjEwLjE2OC40LjYiLCJ0YWJsZSI6NSwiZ2F0ZXdheSI6dHJ1ZSwiaGVhbHRoIjo4MywicHVibGljIjoiMTEyLjQzLjk2LjIyMSIsInNpbmdsZSI6MCwidGltZSI6MTY3NzI0OTAxMH0sIkRDRDg3QzQ1QjdCRiI6eyJpcGFkZHIiOiIxMC4xNjguNC4yIiwidGFibGUiOjEsImdhdGV3YXkiOnRydWUsImhlYWx0aCI6MTUsInB1YmxpYyI6IjExMi4yMi43NS4xMjYiLCJzaW5nbGUiOjAsInRpbWUiOjE2NzcyNDkwMTN9LCJEQ0Q4N0M0ODk2OTQiOnsiaXBhZGRyIjoiMTAuMTY4LjQuNSIsInRhYmxlIjo0LCJnYXRld2F5IjpmYWxzZSwiaGVhbHRoIjo0NiwicHVibGljIjoiMTEyLjQ0LjEwNC4xOSIsInNpbmdsZSI6MCwidGltZSI6MTY3NzI0OTAxOX19LCJzdGF0dXMiOlt7InRhYmxlIjoxLCJlZGdlIjoiRENEODdDNDVCN0JGIiwicHVibGljIjoiMTEyLjIyLjc1LjEyNiIsInNpbmdsZSI6MCwiaXBhZGRyIjoiMTAuMTY4LjQuMiIsImhlYWx0aCI6MTV9LHsidGFibGUiOjIsImVkZ2UiOiJEQ0Q4N0M0QTMxQzQiLCJwdWJsaWMiOiIxMDEuODAuMTguMTE1Iiwic2luZ2xlIjowLCJpcGFkZHIiOiIxMC4xNjguNC4zIiwiaGVhbHRoIjo3fSx7InRhYmxlIjozLCJlZGdlIjoiIiwicHVibGljIjoiIiwic2luZ2xlIjotMSwiaXBhZGRyIjoiIiwiaGVhbHRoIjotMX0seyJ0YWJsZSI6NCwiZWRnZSI6IkRDRDg3QzQ4OTY5NCIsInB1YmxpYyI6IjExMi40NC4xMDQuMTkiLCJzaW5nbGUiOjAsImlwYWRkciI6IjEwLjE2OC40LjUiLCJoZWFsdGgiOjQ2fSx7InRhYmxlIjo1LCJlZGdlIjoiRENEODdDMEI5Q0E2IiwicHVibGljIjoiMTEyLjQzLjk2LjIyMSIsInNpbmdsZSI6MCwiaXBhZGRyIjoiMTAuMTY4LjQuNiIsImhlYWx0aCI6ODN9XX0=" +} diff --git a/docs/gateway_status_info.json b/docs/gateway_status_info.json new file mode 100644 index 0000000..1fa0165 --- /dev/null +++ b/docs/gateway_status_info.json @@ -0,0 +1,130 @@ +{ + "id": 19, + "time": 1677249019, + "mode": 1, + "wan": "jdclink0", + "macaddr": "001122334455", + "network": "10.168.4.0/22", + "gateway": "10.168.4.1", + "supernode": "114.67.100.223", + "supernodeport": "54321", + "url": "114.67.100.223:54321", + "public": "114.67.100.223", + "edges": { + "DCD87C45B7BF": { + "url": "114.67.100.223:54321", + "network": "10.168.4.0/22", + "peer": "10.168.4.2/22", + "gateway": "10.168.4.1", + "route": "" + }, + "DCD87C4A31C4": { + "url": "114.67.100.223:54321", + "network": "10.168.4.0/22", + "peer": "10.168.4.3/22", + "gateway": "10.168.4.1", + "route": "" + }, + "DCD87C2A8EC0": { + "url": "114.67.100.223:54321", + "network": "10.168.4.0/22", + "peer": "10.168.4.4/22", + "gateway": "10.168.4.1", + "route": "" + }, + "DCD87C489694": { + "url": "114.67.100.223:54321", + "network": "10.168.4.0/22", + "peer": "10.168.4.5/22", + "gateway": "10.168.4.1", + "route": "" + }, + "DCD87C0B9CA6": { + "url": "114.67.100.223:54321", + "network": "10.168.4.0/22", + "peer": "10.168.4.6/22", + "gateway": "10.168.4.1", + "route": "" + } + }, + "peers": { + "DCD87C4A31C4": { + "ipaddr": "10.168.4.3", + "table": 2, + "gateway": true, + "health": 7, + "public": "101.80.18.115", + "single": 0, + "time": 1677249018 + }, + "DCD87C0B9CA6": { + "ipaddr": "10.168.4.6", + "table": 5, + "gateway": true, + "health": 83, + "public": "112.43.96.221", + "single": 0, + "time": 1677249010 + }, + "DCD87C45B7BF": { + "ipaddr": "10.168.4.2", + "table": 1, + "gateway": true, + "health": 15, + "public": "112.22.75.126", + "single": 0, + "time": 1677249013 + }, + "DCD87C489694": { + "ipaddr": "10.168.4.5", + "table": 4, + "gateway": false, + "health": 46, + "public": "112.44.104.19", + "single": 0, + "time": 1677249019 + } + }, + "status": [ + { + "table": 1, + "edge": "DCD87C45B7BF", + "public": "112.22.75.126", + "single": 0, + "ipaddr": "10.168.4.2", + "health": 15 + }, + { + "table": 2, + "edge": "DCD87C4A31C4", + "public": "101.80.18.115", + "single": 0, + "ipaddr": "10.168.4.3", + "health": 7 + }, + { + "table": 3, + "edge": "", + "public": "", + "single": -1, + "ipaddr": "", + "health": -1 + }, + { + "table": 4, + "edge": "DCD87C489694", + "public": "112.44.104.19", + "single": 0, + "ipaddr": "10.168.4.5", + "health": 46 + }, + { + "table": 5, + "edge": "DCD87C0B9CA6", + "public": "112.43.96.221", + "single": 0, + "ipaddr": "10.168.4.6", + "health": 83 + } + ] +} \ No newline at end of file diff --git a/docs/京东EIP网关标准版API对接文档V2.3.pdf b/docs/京东EIP网关标准版API对接文档V2.3.pdf new file mode 100644 index 0000000..cd8a683 Binary files /dev/null and b/docs/京东EIP网关标准版API对接文档V2.3.pdf differ diff --git a/docs/京东EIP网关标准版部署与配置V2.4.pdf b/docs/京东EIP网关标准版部署与配置V2.4.pdf new file mode 100644 index 0000000..8a460a9 Binary files /dev/null and b/docs/京东EIP网关标准版部署与配置V2.4.pdf differ diff --git a/docs/网关清空配置.json b/docs/网关清空配置.json new file mode 100644 index 0000000..7e0fb3b --- /dev/null +++ b/docs/网关清空配置.json @@ -0,0 +1,18 @@ +{ + "macaddr": "001122334455", + "config": { + "id": 1, + "rules": [ + { + "table": 1, + "enable": false, + "edge": [ + "", + "", + "", + "" + ], + "network": [], + "cityhash": "" + } ] +}} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8a523de --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module zzman + +go 1.24.0 + +require ( + github.com/joho/godotenv v1.5.1 + github.com/redis/go-redis/v9 v9.11.0 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.30.1 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/text v0.27.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6fcb52e --- /dev/null +++ b/go.sum @@ -0,0 +1,26 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= +github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.30.1 h1:lSHg33jJTBxs2mgJRfRZeLDG+WZaHYCk3Wtfl6Ngzo4= +gorm.io/gorm v1.30.1/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d88a963 --- /dev/null +++ b/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "log/slog" + "os" + "slices" + "zzman/actions" + "zzman/clients" + "zzman/model" + + "github.com/joho/godotenv" +) + +func main() { + + // 初始化环境 + slog.Debug("初始化环境变量") + err := godotenv.Load() + if err != nil { + slog.Error(fmt.Errorf("初始化变量失败:%w", err).Error()) + } + + model.Init() + clients.InitRedis() + + // 执行命令 + if len(os.Args) < 2 { + println("缺少命令参数") + return + } + switch { + case os.Args[1] == "sync": + err := actions.Sync() + if err != nil { + slog.Error(fmt.Sprintf("同步城市节点数据失败:%s", err.Error())) + } else { + slog.Info("同步城市节点数据成功") + } + return + + case os.Args[1] == "update": + + var args actions.UpdateArgs + if len(os.Args) >= 3 { + slices.Contains(os.Args, "--mock") + args.Mock = true + } + + err := actions.Update(model.DB, args) + if err != nil { + slog.Error(fmt.Sprintf("更新节点失败:%s", err.Error())) + } else { + slog.Info("更新节点成功") + } + } + + println("请输入正确的命令参数") +} diff --git a/model/city.go b/model/city.go new file mode 100644 index 0000000..093e4c6 --- /dev/null +++ b/model/city.go @@ -0,0 +1,20 @@ +package model + +type City struct { + Id int `gorm:"column:id;primaryKey"` + Macaddr string `gorm:"column:macaddr"` + Name string `gorm:"column:city"` + Num int `gorm:"column:num"` + Hash string `gorm:"column:hash"` + Label string `gorm:"column:label"` + Count int `gorm:"column:count"` + Offset int `gorm:"column:offset"` + CreateTime string `gorm:"column:createtime"` + UpdateTime string `gorm:"column:updatetime"` + + EdgesCount int // 用于查询时统计边缘节点数量 +} + +func (City) TableName() string { + return "cityhash" +} diff --git a/model/common.go b/model/common.go new file mode 100644 index 0000000..81b4b2d --- /dev/null +++ b/model/common.go @@ -0,0 +1,55 @@ +package model + +import ( + "fmt" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "os" + "strconv" +) + +var DB *gorm.DB + +func Init() { + var err error + + host := os.Getenv("MYSQL_HOST") + if host == "" { + host = "localhost" + } + + portStr := os.Getenv("MYSQL_PORT") + var port int + if portStr == "" { + port = 3306 + } else { + port, err = strconv.Atoi(portStr) + if err != nil { + panic(fmt.Sprintf("Invalid MYSQL_PORT environment variable: %s", portStr)) + } + } + + username := os.Getenv("MYSQL_USERNAME") + if username == "" { + panic("MYSQL_USERNAME environment variable is not set") + } + + password := os.Getenv("MYSQL_PASSWORD") + if password == "" { + panic("MYSQL_PASSWORD environment variable is not set") + } + + database := os.Getenv("MYSQL_DATABASE") + if database == "" { + panic("MYSQL_DATABASE environment variable is not set") + } + + dsn := fmt.Sprintf( + "%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", + username, password, host, port, database, + ) + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic(err) + } +} diff --git a/model/config.go b/model/config.go new file mode 100644 index 0000000..315af58 --- /dev/null +++ b/model/config.go @@ -0,0 +1,41 @@ +package model + +type Config struct { + Id int `gorm:"column:id;primaryKey"` + GatewayMac string `gorm:"column:macaddr"` + Table string `gorm:"column:table"` + Macaddr string `gorm:"column:edge"` + Network string `gorm:"column:network"` + Cityhash string `gorm:"column:cityhash"` + CityLabel string `gorm:"column:label"` + User string `gorm:"column:user"` + InnerIp string `gorm:"column:inner_ip"` + IsChange int `gorm:"column:ischange"` + IsOnline int `gorm:"column:isonline"` + OnlineNum int `gorm:"column:onlinenum"` + CreateTime string `gorm:"column:createtime"` + UpdateTime string `gorm:"column:updatetime"` +} + +func (Config) TableName() string { + return "gateway" +} + +type ConfigUpdate struct { + Id int `gorm:"column:id;primaryKey"` + GatewayMac *string `gorm:"column:macaddr"` + Table *string `gorm:"column:table"` + Macaddr *string `gorm:"column:edge"` + Network *string `gorm:"column:network"` + Cityhash *string `gorm:"column:cityhash"` + CityLabel *string `gorm:"column:label"` + User *string `gorm:"column:user"` + InnerIp *string `gorm:"column:inner_ip"` + IsChange *int `gorm:"column:ischange"` + IsOnline *int `gorm:"column:isonline"` + OnlineNum *int `gorm:"column:onlinenum"` +} + +func (ConfigUpdate) TableName() string { + return "gateway" +} diff --git a/model/edge.go b/model/edge.go new file mode 100644 index 0000000..0434c19 --- /dev/null +++ b/model/edge.go @@ -0,0 +1,19 @@ +package model + +type Edge struct { + Id int `gorm:"column:id;primaryKey"` + CityId int `gorm:"column:city_id"` + + Macaddr string `gorm:"column:macaddr"` + Public string `gorm:"column:public"` + Isp string `gorm:"column:isp"` + Single int `gorm:"column:single"` + Sole bool `gorm:"column:sole"` + Arch int `gorm:"column:arch"` + Online int `gorm:"column:online"` + Active bool `gorm:"column:active"` +} + +func (Edge) TableName() string { + return "edge" +} diff --git a/model/gateway.go b/model/gateway.go new file mode 100644 index 0000000..5916a95 --- /dev/null +++ b/model/gateway.go @@ -0,0 +1,19 @@ +package model + +type Gateway struct { + Id int `gorm:"column:id;primaryKey"` + ConfigVersion int `gorm:"column:setid"` + ChangeCount int `gorm:"column:change_count"` + LimitCount int `gorm:"column:limit_count"` + Token string `gorm:"column:token"` + Macaddr string `gorm:"column:macaddr"` + TokenTime string `gorm:"column:token_time"` + PrivateIp string `gorm:"column:inner_ip"` + ProxyIp string `gorm:"column:l2ip"` + CreateTime string `gorm:"column:createtime"` + UpdateTime string `gorm:"column:updatetime"` +} + +func (e *Gateway) TableName() string { + return "token" +} diff --git a/util/util.go b/util/util.go new file mode 100644 index 0000000..9e9a222 --- /dev/null +++ b/util/util.go @@ -0,0 +1,5 @@ +package util + +func P[T any](v T) *T { + return &v +}