```
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")
|
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(),
|
closer1, err := jsonrpc.NewMergeClient(context.Background(),
|
||||||
"ws://"+rpcaddr+":"+rpcport, "", []interface{}{
|
"ws://"+rpcaddr+":"+rpcport, "", []interface{}{
|
||||||
&RPCClient,
|
&RPCClient,
|
||||||
|
|||||||
@@ -12,12 +12,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
_ "embed"
|
|
||||||
|
|
||||||
"github.com/ipipdotnet/ipdb-go"
|
"github.com/ipipdotnet/ipdb-go"
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
"golang.org/x/text/transform"
|
"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格式数据库时使用
|
// QueryIPDat 从dat查询IP,仅加载dat格式数据库时使用
|
||||||
func QueryIPDat(ipv4 string) (location *Location, err error) {
|
func QueryIPDat(ipv4 string) (location *Location, err error) {
|
||||||
ip := net.ParseIP(ipv4).To4()
|
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")
|
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
|
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)
|
ip32 := binary.BigEndian.Uint32(ip)
|
||||||
posA := binary.LittleEndian.Uint32(data[:4])
|
posA := binary.LittleEndian.Uint32(data[:4])
|
||||||
@@ -245,16 +118,19 @@ func QueryIPDat(ipv4 string) (location *Location, err error) {
|
|||||||
for {
|
for {
|
||||||
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
|
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
|
||||||
if int(mid+indexLen) > len(data) {
|
if int(mid+indexLen) > len(data) {
|
||||||
|
// 当数据中找不到IP时,尝试使用网络查询
|
||||||
r, _ := LookupIP(ipv4, "json")
|
r, _ := LookupIP(ipv4, "json")
|
||||||
if r != nil {
|
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)
|
locationCache.Store(ipv4, location)
|
||||||
return location, nil
|
return location, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("ip not found")
|
return nil, errors.New("ip not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
buf := data[mid : mid+indexLen]
|
buf := data[mid : mid+indexLen]
|
||||||
_ip := binary.LittleEndian.Uint32(buf[:4])
|
_ip := binary.LittleEndian.Uint32(buf[:4])
|
||||||
@@ -360,6 +236,56 @@ func QueryIPIpdb(ip string) (location *Location, err error) {
|
|||||||
locationCache.Store(ip, location)
|
locationCache.Store(ip, location)
|
||||||
return location, nil
|
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数据库
|
// LoadData 从内存加载IP数据库
|
||||||
func LoadData(database []byte) {
|
func LoadData(database []byte) {
|
||||||
@@ -407,3 +333,4 @@ func SplitResult(addr string, isp string, ipv4 string) (location *Location) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ func Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
port, err := determinePort(cool.Config.ServerInfo.CanPort)
|
port, err := determinePort(cool.Config.ServerInfo.CanPort)
|
||||||
|
cool.Config.ServerInfo.Port = uint16(port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to determine port: %v", err)
|
log.Fatalf("Failed to determine port: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"blazing/cool"
|
"blazing/cool"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"blazing/modules/base/model"
|
"blazing/modules/base/model"
|
||||||
@@ -33,22 +34,38 @@ func NewBaseSysLogService() *BaseSysLogService {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
||||||
// baseSysLog.IPAddr = fmt.Sprintf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n",
|
|
||||||
// location.Country,
|
var rr []g.MapStrAny
|
||||||
// location.Province,
|
|
||||||
// location.City,
|
|
||||||
// location.District,
|
|
||||||
// location.ISP,
|
|
||||||
// )
|
|
||||||
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
||||||
for _, v := range r {
|
for i := 0; i < len(r); i++ {
|
||||||
ipaddr, err := qqwry.QueryIP(v.Map()["ip"].(string))
|
subm := r[i].GMap()
|
||||||
|
ipaddr, err := qqwry.QueryIP(r[i].Map()["ip"].(string))
|
||||||
if err == nil {
|
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
|
return data
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (s *ItemService) UPDATE(id uint32, count int) {
|
|||||||
"item_id": id,
|
"item_id": id,
|
||||||
"item_cnt": count,
|
"item_cnt": count,
|
||||||
}
|
}
|
||||||
data = cool.SetTest(data)
|
//data = cool.SetTest(data)
|
||||||
|
|
||||||
m.Data(data).Insert()
|
m.Data(data).Insert()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const TableNameServerList = "server_list"
|
|||||||
type ServerList struct {
|
type ServerList struct {
|
||||||
*cool.Model
|
*cool.Model
|
||||||
coolconfig.ServerList
|
coolconfig.ServerList
|
||||||
|
//isonline
|
||||||
|
IsOnline uint8 `gorm:"column:isonline;default:0;comment:'是否在线'" json:"isonline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName ServerList's table name
|
// TableName ServerList's table name
|
||||||
|
|||||||
@@ -29,24 +29,29 @@ func NewServerService() *ServerService {
|
|||||||
Model: model.NewServerList(),
|
Model: model.NewServerList(),
|
||||||
PageQueryOp: &cool.QueryOp{
|
PageQueryOp: &cool.QueryOp{
|
||||||
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
ModifyResult: func(ctx g.Ctx, data interface{}) interface{} {
|
||||||
|
var rr []g.MapStrAny
|
||||||
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
r, _ := gconv.Map(data)["list"].(gdb.Result)
|
||||||
for _, v := range r {
|
for i := 0; i < len(r); i++ {
|
||||||
t, ok := cool.GetClient(gconv.Uint16(v.Map()["port"]))
|
t, ok := cool.GetClient(gconv.Uint16(r[i].Map()["port"]))
|
||||||
|
// tt.Friends = v.Friends
|
||||||
|
subm := r[i].GMap()
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
cool.Logger.Info(context.TODO(), "服务器假踢人")
|
cool.Logger.Info(context.TODO(), "服务器假踢人")
|
||||||
err := t.KickPerson(0) //实现指定服务器踢人
|
err := t.KickPerson(0) //实现指定服务器踢人
|
||||||
|
|
||||||
if err == nil {
|
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
|
return data
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user