```
feat(rpc): 设置默认RPC地址为本地回环 修复RPC客户端连接问题,将默认服务器地址设置为127.0.0.1以确保本地连接正常 refactor(qqwry): 优化IP地址查询功能 移除不必要的正则表达式依赖,重构IP地址查询逻辑,提高代码性能和可维护性 fix(server): 保存确定的端口到配置中 确保服务器端口在确定后正确保存到配置中,避免端口配置丢失
This commit is contained in:
@@ -86,7 +86,7 @@ func StartClient(id, port uint16, callback any) *struct {
|
||||
} {
|
||||
|
||||
var rpcaddr, _ = service.NewBaseSysParamService().DataByKey(context.Background(), "server_ip")
|
||||
//rpcaddr = "127.0.0.1"
|
||||
rpcaddr = "127.0.0.1"
|
||||
closer1, err := jsonrpc.NewMergeClient(context.Background(),
|
||||
"ws://"+rpcaddr+":"+rpcport, "", []interface{}{
|
||||
&RPCClient,
|
||||
|
||||
@@ -12,12 +12,9 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/ipipdotnet/ipdb-go"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
@@ -88,143 +85,6 @@ func QueryIP(ip string) (location *Location, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetIpAddress 获取 IP 归属地和运营商
|
||||
func GetIpAddress(ip string) (string, error) {
|
||||
html, err := doGet("https://www.ipshudi.com/" + ip + "/")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
div := getAddress(html, `<td>\n<span>.*</span>\n`)
|
||||
div1 := getAddress(html, `<td class="th">运营商</td><td><span>.*</span>`)
|
||||
|
||||
location := "未知归属地"
|
||||
if div != "" {
|
||||
location = strings.Split(div, "<span>")[1]
|
||||
location = strings.Split(location, "</span>")[0]
|
||||
}
|
||||
|
||||
isp := ""
|
||||
if div1 != "" {
|
||||
isp = strings.Split(div1, "<span>")[1]
|
||||
isp = strings.Split(isp, "</span>")[0]
|
||||
}
|
||||
|
||||
return location + " " + isp, nil
|
||||
}
|
||||
|
||||
// 定义响应数据结构(与 API 返回字段对应)
|
||||
type IPLocationResponse struct {
|
||||
IP string `json:"ip"`
|
||||
IPNumber string `json:"ip_number"`
|
||||
IPVersion int `json:"ip_version"`
|
||||
CountryName string `json:"country_name"`
|
||||
CountryCode2 string `json:"country_code2"`
|
||||
ISP string `json:"isp"`
|
||||
ResponseCode string `json:"response_code"`
|
||||
ResponseMessage string `json:"response_message"`
|
||||
}
|
||||
|
||||
// 调用 IP 定位 API
|
||||
func LookupIP(ip string, format string) (*IPLocationResponse, error) {
|
||||
// 构建请求 URL
|
||||
baseURL := "https://api.iplocation.net/"
|
||||
params := url.Values{}
|
||||
params.Add("ip", ip)
|
||||
if format != "" {
|
||||
params.Add("format", format)
|
||||
}
|
||||
|
||||
fullURL := baseURL + "?" + params.Encode()
|
||||
|
||||
// 发送 GET 请求
|
||||
resp, err := http.Get(fullURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
// 解析 JSON 响应(默认格式为 json)
|
||||
var result IPLocationResponse
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v (响应内容: %s)", err, string(body))
|
||||
}
|
||||
|
||||
// 检查 API 响应状态
|
||||
if result.ResponseCode != "200" {
|
||||
return nil, fmt.Errorf("API 调用失败: %s (%s)", result.ResponseMessage, result.ResponseCode)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// doGet 发送 HTTP GET 请求,返回响应内容
|
||||
func doGet(url string) ([]byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// getAddress 使用正则表达式从 HTML 中提取内容
|
||||
func getAddress(html []byte, pattern string) string {
|
||||
re := regexp.MustCompile(pattern)
|
||||
return re.FindString(string(html))
|
||||
}
|
||||
|
||||
// 判断IP是否为私有地址(包括IPv4和IPv6)
|
||||
func isPrivateIP(ipStr string) (bool, error) {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
return false, fmt.Errorf("无效的IP地址: %s", ipStr)
|
||||
}
|
||||
|
||||
// 定义私有网段
|
||||
privateNets := []string{
|
||||
// IPv4私有网段
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
// IPv6私有网段(ULA和链路本地)
|
||||
"fc00::/7",
|
||||
"fe80::/10",
|
||||
}
|
||||
|
||||
// 检查IP是否属于任一私有网段
|
||||
for _, cidr := range privateNets {
|
||||
_, netIP, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if netIP.Contains(ip) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 判断IP是否为环回地址
|
||||
func isLoopbackIP(ipStr string) (bool, error) {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
return false, fmt.Errorf("无效的IP地址: %s", ipStr)
|
||||
}
|
||||
return ip.IsLoopback(), nil
|
||||
}
|
||||
|
||||
// QueryIPDat 从dat查询IP,仅加载dat格式数据库时使用
|
||||
func QueryIPDat(ipv4 string) (location *Location, err error) {
|
||||
ip := net.ParseIP(ipv4).To4()
|
||||
@@ -232,11 +92,24 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
|
||||
return nil, errors.New("ip is not ipv4")
|
||||
}
|
||||
|
||||
if isLoopback, err := isLoopbackIP(ipv4); isLoopback || err != nil {
|
||||
if ip.IsLoopback() {
|
||||
return &Location{ISP: "局域网", IP: ipv4}, nil
|
||||
}
|
||||
if isPrivateIP, err := isPrivateIP(ipv4); isPrivateIP || err != nil {
|
||||
return &Location{ISP: "私有地址", IP: ipv4}, nil
|
||||
|
||||
privateNets := []string{
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
}
|
||||
|
||||
for _, cidr := range privateNets {
|
||||
_, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ipnet.Contains(ip) {
|
||||
return &Location{ISP: "私有地址", IP: ipv4}, nil
|
||||
}
|
||||
}
|
||||
ip32 := binary.BigEndian.Uint32(ip)
|
||||
posA := binary.LittleEndian.Uint32(data[:4])
|
||||
@@ -245,16 +118,19 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
|
||||
for {
|
||||
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
|
||||
if int(mid+indexLen) > len(data) {
|
||||
// 当数据中找不到IP时,尝试使用网络查询
|
||||
r, _ := LookupIP(ipv4, "json")
|
||||
if r != nil {
|
||||
location := &Location{ISP: r.ISP, IP: r.IP, Country: r.CountryName, District: r.CountryCode2}
|
||||
|
||||
location := &Location{
|
||||
IP: r.IP,
|
||||
Country: r.CountryName,
|
||||
ISP: r.ISP,
|
||||
}
|
||||
locationCache.Store(ipv4, location)
|
||||
return location, nil
|
||||
} else {
|
||||
return nil, errors.New("ip not found")
|
||||
}
|
||||
|
||||
}
|
||||
buf := data[mid : mid+indexLen]
|
||||
_ip := binary.LittleEndian.Uint32(buf[:4])
|
||||
@@ -360,6 +236,56 @@ func QueryIPIpdb(ip string) (location *Location, err error) {
|
||||
locationCache.Store(ip, location)
|
||||
return location, nil
|
||||
}
|
||||
// IPLocationResponse 定义IP定位API的响应结构
|
||||
type IPLocationResponse struct {
|
||||
IP string `json:"ip"`
|
||||
IPNumber string `json:"ip_number"`
|
||||
IPVersion int `json:"ip_version"`
|
||||
CountryName string `json:"country_name"`
|
||||
CountryCode2 string `json:"country_code2"`
|
||||
ISP string `json:"isp"`
|
||||
ResponseCode string `json:"response_code"`
|
||||
ResponseMessage string `json:"response_message"`
|
||||
}
|
||||
|
||||
// LookupIP 调用外部API查询IP地理位置
|
||||
func LookupIP(ip string, format string) (*IPLocationResponse, error) {
|
||||
// 构建请求 URL
|
||||
baseURL := "https://api.iplocation.net/"
|
||||
params := url.Values{}
|
||||
params.Add("ip", ip)
|
||||
if format != "" {
|
||||
params.Add("format", format)
|
||||
}
|
||||
|
||||
fullURL := baseURL + "?" + params.Encode()
|
||||
|
||||
// 发送 GET 请求
|
||||
resp, err := http.Get(fullURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
// 解析 JSON 响应
|
||||
var result IPLocationResponse
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v (响应内容: %s)", err, string(body))
|
||||
}
|
||||
|
||||
// 检查 API 响应状态
|
||||
if result.ResponseCode != "200" {
|
||||
return nil, fmt.Errorf("API 调用失败: %s (%s)", result.ResponseMessage, result.ResponseCode)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// LoadData 从内存加载IP数据库
|
||||
func LoadData(database []byte) {
|
||||
@@ -407,3 +333,4 @@ func SplitResult(addr string, isp string, ipv4 string) (location *Location) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ func Start() {
|
||||
}
|
||||
|
||||
port, err := determinePort(cool.Config.ServerInfo.CanPort)
|
||||
cool.Config.ServerInfo.Port = uint16(port)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to determine port: %v", err)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"blazing/cool"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"blazing/modules/base/model"
|
||||
@@ -33,22 +34,38 @@ func NewBaseSysLogService() *BaseSysLogService {
|
||||
},
|
||||
},
|
||||
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
||||
// baseSysLog.IPAddr = fmt.Sprintf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n",
|
||||
// location.Country,
|
||||
// location.Province,
|
||||
// location.City,
|
||||
// location.District,
|
||||
// location.ISP,
|
||||
// )
|
||||
|
||||
var rr []g.MapStrAny
|
||||
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
||||
for _, v := range r {
|
||||
ipaddr, err := qqwry.QueryIP(v.Map()["ip"].(string))
|
||||
for i := 0; i < len(r); i++ {
|
||||
subm := r[i].GMap()
|
||||
ipaddr, err := qqwry.QueryIP(r[i].Map()["ip"].(string))
|
||||
if err == nil {
|
||||
v.GMap().Set("ipAddr", ipaddr)
|
||||
// baseSysLog.IPAddr = fmt.Sprintf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n",
|
||||
// location.Country,
|
||||
// location.Province,
|
||||
// location.City,
|
||||
// location.District,
|
||||
// location.ISP,
|
||||
// )
|
||||
|
||||
subm.Set("ipAddr", fmt.Sprintf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n",
|
||||
ipaddr.Country,
|
||||
ipaddr.Province,
|
||||
ipaddr.City,
|
||||
ipaddr.District,
|
||||
ipaddr.ISP,
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
rr = append(rr, subm.MapStrAny())
|
||||
}
|
||||
|
||||
data.(map[string]interface{})["list"] = rr
|
||||
|
||||
return data
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ func (s *ItemService) UPDATE(id uint32, count int) {
|
||||
"item_id": id,
|
||||
"item_cnt": count,
|
||||
}
|
||||
data = cool.SetTest(data)
|
||||
//data = cool.SetTest(data)
|
||||
|
||||
m.Data(data).Insert()
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ const TableNameServerList = "server_list"
|
||||
type ServerList struct {
|
||||
*cool.Model
|
||||
coolconfig.ServerList
|
||||
//isonline
|
||||
IsOnline uint8 `gorm:"column:isonline;default:0;comment:'是否在线'" json:"isonline"`
|
||||
}
|
||||
|
||||
// TableName ServerList's table name
|
||||
|
||||
@@ -29,24 +29,29 @@ func NewServerService() *ServerService {
|
||||
Model: model.NewServerList(),
|
||||
PageQueryOp: &cool.QueryOp{
|
||||
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
||||
|
||||
var rr []g.MapStrAny
|
||||
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
||||
for _, v := range r {
|
||||
t, ok := cool.GetClient(gconv.Uint16(v.Map()["port"]))
|
||||
for i := 0; i < len(r); i++ {
|
||||
t, ok := cool.GetClient(gconv.Uint16(r[i].Map()["port"]))
|
||||
// tt.Friends = v.Friends
|
||||
subm := r[i].GMap()
|
||||
|
||||
if ok {
|
||||
cool.Logger.Info(context.TODO(), "服务器假踢人")
|
||||
err := t.KickPerson(0) //实现指定服务器踢人
|
||||
|
||||
if err == nil {
|
||||
// tt.Friends = v.Friends
|
||||
v.GMap().Set("isonline", 1)
|
||||
|
||||
subm.Set("isonline", 1)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rr = append(rr, subm.MapStrAny())
|
||||
}
|
||||
|
||||
data.(map[string]interface{})["list"] = rr
|
||||
|
||||
return data
|
||||
},
|
||||
},
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user