mirror of https://gitee.com/godoos/godoos.git
9 changed files with 309 additions and 272 deletions
@ -0,0 +1,71 @@ |
|||||
|
package libs |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"strconv" |
||||
|
) |
||||
|
|
||||
|
type UserChatIpSetting struct { |
||||
|
First string `json:"First"` |
||||
|
Second string `json:"Second"` |
||||
|
ThirdStart string `json:"ThirdStart"` |
||||
|
ThirdEnd string `json:"ThirdEnd"` |
||||
|
FourthStart string `json:"FourthStart"` |
||||
|
FourthEnd string `json:"FourthEnd"` |
||||
|
} |
||||
|
|
||||
|
func GetDefaultChatIpSetting() UserChatIpSetting { |
||||
|
return UserChatIpSetting{ |
||||
|
First: "192", |
||||
|
Second: "168", |
||||
|
ThirdStart: "1", |
||||
|
ThirdEnd: "1", |
||||
|
FourthStart: "2", |
||||
|
FourthEnd: "99", |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func GetChatIpSetting() UserChatIpSetting { |
||||
|
ips, ok := GetConfig("chatIpSetting") |
||||
|
if !ok { |
||||
|
return GetDefaultChatIpSetting() |
||||
|
} |
||||
|
return ips.(UserChatIpSetting) |
||||
|
} |
||||
|
|
||||
|
// GenerateIPs 生成 IP 地址列表
|
||||
|
func GenerateIPs(setting UserChatIpSetting) []string { |
||||
|
var IPs []string |
||||
|
|
||||
|
thirdStart, _ := strconv.Atoi(setting.ThirdStart) |
||||
|
thirdEnd, _ := strconv.Atoi(setting.ThirdEnd) |
||||
|
fourthStart, _ := strconv.Atoi(setting.FourthStart) |
||||
|
fourthEnd, _ := strconv.Atoi(setting.FourthEnd) |
||||
|
|
||||
|
if thirdStart == thirdEnd { |
||||
|
if fourthStart == fourthEnd { |
||||
|
// 第三位和第四位都相等,只生成一个 IP 地址
|
||||
|
IPs = append(IPs, fmt.Sprintf("%s.%s.%d.%d", setting.First, setting.Second, thirdStart, fourthStart)) |
||||
|
} else { |
||||
|
// 第三位相等,第四位不相等,生成第四位的所有 IP 地址
|
||||
|
for j := fourthStart; j <= fourthEnd; j++ { |
||||
|
IPs = append(IPs, fmt.Sprintf("%s.%s.%d.%d", setting.First, setting.Second, thirdStart, j)) |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
// 第三位不相等,生成第三位和第四位的所有组合
|
||||
|
for i := thirdStart; i <= thirdEnd; i++ { |
||||
|
for j := fourthStart; j <= fourthEnd; j++ { |
||||
|
IPs = append(IPs, fmt.Sprintf("%s.%s.%d.%d", setting.First, setting.Second, i, j)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return IPs |
||||
|
} |
||||
|
|
||||
|
// 示例函数
|
||||
|
func GetChatIPs() []string { |
||||
|
setting := GetChatIpSetting() |
||||
|
return GenerateIPs(setting) |
||||
|
} |
@ -1,103 +1,159 @@ |
|||||
package localchat |
package localchat |
||||
|
|
||||
import ( |
import ( |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
"log" |
||||
"net" |
"net" |
||||
"net/http" |
"net/http" |
||||
"strconv" |
"runtime" |
||||
|
"sync" |
||||
|
"time" |
||||
|
|
||||
"godo/libs" |
"godo/libs" |
||||
) |
) |
||||
|
|
||||
func HandleAddr(w http.ResponseWriter, r *http.Request) { |
type UserStatus struct { |
||||
addr := r.URL.Query().Get("addr") |
Hostname string `json:"hostname"` |
||||
if addr == "" { |
IP string `json:"ip"` |
||||
libs.ErrorMsg(w, "addr is empty") |
Time time.Time `json:"time"` |
||||
return |
} |
||||
} |
|
||||
|
|
||||
udpAddr := libs.GetUdpAddr() |
var OnlineUsers = make(map[string]UserStatus) |
||||
if addr == udpAddr { |
|
||||
libs.ErrorMsg(w, "addr is same as current addr") |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
// 检查是否为多播地址
|
type UDPPayload struct { |
||||
if !IsValidMulticastAddr(addr) { |
Action string `json:"action"` |
||||
libs.ErrorMsg(w, "addr is not a valid multicast address") |
Data string `json:"data"` |
||||
return |
|
||||
} |
|
||||
// 验证可访问性
|
|
||||
if IsMulticastAddrAccessible(addr) { |
|
||||
save := libs.ReqBody{ |
|
||||
Value: addr, |
|
||||
Name: "udpAddr", |
|
||||
} |
|
||||
libs.SetConfig(save) |
|
||||
libs.SuccessMsg(w, nil, "addr is a valid multicast address and accessible") |
|
||||
} else { |
|
||||
libs.ErrorMsg(w, "addr is a valid multicast address but not accessible") |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
// 检查是否为多播地址
|
func getHostname(ip string) (string, error) { |
||||
func IsValidMulticastAddr(addr string) bool { |
hostname, err := net.LookupAddr(ip) |
||||
host, port, err := net.SplitHostPort(addr) |
|
||||
if err != nil { |
if err != nil { |
||||
return false |
return "", fmt.Errorf("error getting hostname: %v", err) |
||||
} |
} |
||||
|
if len(hostname) > 0 { |
||||
ip := net.ParseIP(host) |
return hostname[0], nil |
||||
if ip == nil || !isMulticastIP(ip) { |
|
||||
return false |
|
||||
} |
} |
||||
|
return "", fmt.Errorf("no hostname found for IP: %s", ip) |
||||
_, err = strconv.Atoi(port) |
|
||||
return err == nil |
|
||||
} |
} |
||||
|
|
||||
// 检查 IP 是否为多播地址
|
// 发送 UDP 包并忽略响应
|
||||
func isMulticastIP(ip net.IP) bool { |
func sendUDPPacket(ip string) error { |
||||
if ip.To4() != nil { |
payload := UDPPayload{ |
||||
return ip[0]&0xF0 == 0xE0 // 检查 IPv4 多播地址范围 224.0.0.0 - 239.255.255.255
|
Action: "check", |
||||
|
Data: "", |
||||
} |
} |
||||
return ip[0]&0xF0 == 0xE0 // 检查 IPv6 多播地址范围 FF00::/8
|
log.Printf("sending ip: %+v", ip) |
||||
} |
payloadBytes, err := json.Marshal(payload) |
||||
|
|
||||
// 验证多播地址的可访问性
|
|
||||
func IsMulticastAddrAccessible(addr string) bool { |
|
||||
host, port, err := net.SplitHostPort(addr) |
|
||||
if err != nil { |
|
||||
return false |
|
||||
} |
|
||||
|
|
||||
udpAddr, err := net.ResolveUDPAddr("udp4", net.JoinHostPort(host, port)) |
|
||||
if err != nil { |
if err != nil { |
||||
return false |
log.Printf("error marshalling payload: %v", err) |
||||
|
return fmt.Errorf("error marshalling payload: %v", err) |
||||
} |
} |
||||
|
|
||||
conn, err := net.ListenMulticastUDP("udp4", nil, udpAddr) |
conn, err := net.Dial("udp", fmt.Sprintf("%s:56780", ip)) |
||||
if err != nil { |
if err != nil { |
||||
return false |
log.Printf("error dialing UDP: %v", err) |
||||
|
return fmt.Errorf("error dialing UDP: %v", err) |
||||
} |
} |
||||
defer conn.Close() |
defer conn.Close() |
||||
|
|
||||
// 发送一条测试消息
|
_, err = conn.Write(payloadBytes) |
||||
testMsg := []byte("Test message") |
|
||||
_, err = conn.WriteToUDP(testMsg, udpAddr) |
|
||||
if err != nil { |
if err != nil { |
||||
return false |
log.Printf("error writing UDP payload: %v", err) |
||||
|
return fmt.Errorf("error writing UDP payload: %v", err) |
||||
} |
} |
||||
|
|
||||
// 接收一条测试消息
|
return nil |
||||
buffer := make([]byte, 1024) |
} |
||||
n, _, err := conn.ReadFromUDP(buffer) |
|
||||
|
func concurrentGetIpInfo(ips []string) { |
||||
|
// 获取本地 IP 地址
|
||||
|
hostips, err := libs.GetValidIPAddresses() |
||||
if err != nil { |
if err != nil { |
||||
return false |
log.Printf("failed to get local IP addresses: %v", err) |
||||
|
return |
||||
} |
} |
||||
|
|
||||
if n > 0 && string(buffer[:n]) == "Test message" { |
var wg sync.WaitGroup |
||||
return true |
maxConcurrency := runtime.NumCPU() |
||||
|
|
||||
|
semaphore := make(chan struct{}, maxConcurrency) |
||||
|
|
||||
|
failedIPs := make(map[string]bool) |
||||
|
|
||||
|
for _, ip := range ips { |
||||
|
if containArr(hostips, ip) || failedIPs[ip] { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
wg.Add(1) |
||||
|
semaphore <- struct{}{} |
||||
|
|
||||
|
go func(ip string) { |
||||
|
defer wg.Done() |
||||
|
defer func() { <-semaphore }() |
||||
|
err := sendUDPPacket(ip) |
||||
|
if err != nil { |
||||
|
log.Printf("Failed to send packet to IP %s: %v", ip, err) |
||||
|
failedIPs[ip] = true // 标记失败的 IP
|
||||
|
} else { |
||||
|
hostname, err := getHostname(ip) |
||||
|
if err != nil { |
||||
|
log.Printf("Failed to get hostname for IP %s: %v", ip, err) |
||||
|
} else { |
||||
|
OnlineUsers[ip] = UserStatus{ |
||||
|
Hostname: hostname, |
||||
|
IP: ip, |
||||
|
Time: time.Now(), |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}(ip) |
||||
} |
} |
||||
|
|
||||
|
wg.Wait() |
||||
|
} |
||||
|
|
||||
|
func CheckOnline() { |
||||
|
// 清除 OnlineUsers 映射表
|
||||
|
CleanOnlineUsers() |
||||
|
|
||||
|
ips := libs.GetChatIPs() |
||||
|
// 启动并发处理
|
||||
|
concurrentGetIpInfo(ips) |
||||
|
|
||||
|
log.Printf("online users: %v", OnlineUsers) |
||||
|
} |
||||
|
|
||||
|
func CleanOnlineUsers() { |
||||
|
OnlineUsers = make(map[string]UserStatus) |
||||
|
} |
||||
|
|
||||
|
func containArr(s []string, str string) bool { |
||||
|
for _, v := range s { |
||||
|
if v == str { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
return false |
return false |
||||
} |
} |
||||
|
|
||||
|
func HandleHeartbeat(w http.ResponseWriter, r *http.Request) { |
||||
|
ip := r.RemoteAddr // 可以根据实际情况获取 IP
|
||||
|
hostname, err := getHostname(ip) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusInternalServerError, "Failed to get hostname") |
||||
|
return |
||||
|
} |
||||
|
userStatus := UpdateUserStatus(ip, hostname) |
||||
|
libs.SuccessMsg(w, userStatus, "Heartbeat received") |
||||
|
} |
||||
|
|
||||
|
func UpdateUserStatus(ip string, hostname string) UserStatus { |
||||
|
OnlineUsers[ip] = UserStatus{ |
||||
|
Hostname: hostname, |
||||
|
IP: ip, |
||||
|
Time: time.Now(), |
||||
|
} |
||||
|
return OnlineUsers[ip] |
||||
|
} |
||||
|
@ -0,0 +1,27 @@ |
|||||
|
package localchat |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"godo/libs" |
||||
|
"net/http" |
||||
|
"os" |
||||
|
) |
||||
|
|
||||
|
func HandleCheck(w http.ResponseWriter, r *http.Request) { |
||||
|
hostname, err := os.Hostname() |
||||
|
if err != nil { |
||||
|
libs.ErrorMsg(w, "HandleMessage error") |
||||
|
return |
||||
|
} |
||||
|
libs.SuccessMsg(w, hostname, "") |
||||
|
} |
||||
|
func HandleAddr(w http.ResponseWriter, r *http.Request) { |
||||
|
var ipStr libs.UserChatIpSetting |
||||
|
err := json.NewDecoder(r.Body).Decode(&ipStr) |
||||
|
if err != nil { |
||||
|
libs.HTTPError(w, http.StatusBadRequest, "Failed to parse request body") |
||||
|
return |
||||
|
} |
||||
|
libs.SetConfigByName("ChatIpSetting", ipStr) |
||||
|
libs.SuccessMsg(w, nil, "success") |
||||
|
} |
@ -1,141 +0,0 @@ |
|||||
package localchat |
|
||||
|
|
||||
import ( |
|
||||
"encoding/json" |
|
||||
"godo/libs" |
|
||||
"log" |
|
||||
"net" |
|
||||
"strings" |
|
||||
"time" |
|
||||
) |
|
||||
|
|
||||
type UdpMessage struct { |
|
||||
Hostname string `json:"hostname"` |
|
||||
Type string `json:"type"` |
|
||||
Time time.Time `json:"time"` |
|
||||
IP string `json:"ip"` |
|
||||
Message any `json:"message"` |
|
||||
} |
|
||||
type UdpAddress struct { |
|
||||
Hostname string `json:"hostname"` |
|
||||
IP string `json:"ip"` |
|
||||
Time time.Time `json:"time"` |
|
||||
} |
|
||||
type Messages struct { |
|
||||
Messages []UdpMessage `json:"messages"` |
|
||||
} |
|
||||
type UserMessage struct { |
|
||||
Messages map[string]*Messages `json:"messages"` |
|
||||
Onlines []UdpAddress `json:"onlines"` |
|
||||
} |
|
||||
|
|
||||
var OnlineUsers []UdpAddress |
|
||||
var UserMessages = make(map[string]*Messages) // 使用指针类型
|
|
||||
|
|
||||
func init() { |
|
||||
go InitBroadcast() |
|
||||
go ListenForBroadcast() |
|
||||
} |
|
||||
|
|
||||
// ListenForBroadcast 监听多播消息
|
|
||||
func ListenForBroadcast() { |
|
||||
broadcastAddr := GetBroadcastAddr() |
|
||||
addr, err := net.ResolveUDPAddr("udp4", broadcastAddr) |
|
||||
if err != nil { |
|
||||
log.Fatalf("Failed to resolve UDP address: %v", err) |
|
||||
} |
|
||||
// 使用 ListenMulticastUDP 创建多播连接
|
|
||||
conn, err := net.ListenMulticastUDP("udp4", nil, addr) |
|
||||
if err != nil { |
|
||||
log.Fatalf("Failed to listen on UDP address: %v", err) |
|
||||
} |
|
||||
defer conn.Close() |
|
||||
|
|
||||
// 获取本地 IP 地址
|
|
||||
ips, err := libs.GetValidIPAddresses() |
|
||||
if err != nil { |
|
||||
log.Fatalf("Failed to get local IP addresses: %v", err) |
|
||||
} |
|
||||
|
|
||||
// 开始监听多播消息
|
|
||||
buffer := make([]byte, 1024) |
|
||||
for { |
|
||||
n, remoteAddr, err := conn.ReadFromUDP(buffer) |
|
||||
if err != nil { |
|
||||
log.Printf("Error reading from UDP: %v", err) |
|
||||
continue |
|
||||
} |
|
||||
|
|
||||
var udpMsg UdpMessage |
|
||||
err = json.Unmarshal(buffer[:n], &udpMsg) |
|
||||
if err != nil { |
|
||||
log.Printf("Error unmarshalling JSON: %v", err) |
|
||||
continue |
|
||||
} |
|
||||
// 从 remoteAddr 获取 IP 地址
|
|
||||
ip := remoteAddr.IP.String() |
|
||||
if containArr(ips, ip) { |
|
||||
continue |
|
||||
} |
|
||||
if udpMsg.Type == "online" { |
|
||||
if !containIp(OnlineUsers, ip) { |
|
||||
OnlineUsers = append(OnlineUsers, UdpAddress{Hostname: udpMsg.Hostname, IP: ip, Time: time.Now()}) |
|
||||
log.Printf("在线用户: %v", OnlineUsers) |
|
||||
} |
|
||||
} |
|
||||
udpMsg.IP = ip |
|
||||
if udpMsg.Type == "text" { |
|
||||
addMessageToUserMessages(ip, udpMsg) |
|
||||
} |
|
||||
if udpMsg.Type == "file" { |
|
||||
addMessageToUserMessages(ip, udpMsg) |
|
||||
RecieveFile(udpMsg) |
|
||||
} |
|
||||
log.Printf("Received message from %s: %s", remoteAddr, udpMsg.Hostname) |
|
||||
} |
|
||||
} |
|
||||
func containArr(s []string, str string) bool { |
|
||||
for _, v := range s { |
|
||||
if v == str { |
|
||||
return true |
|
||||
} |
|
||||
} |
|
||||
return false |
|
||||
} |
|
||||
func containIp(slice []UdpAddress, element string) bool { |
|
||||
for _, v := range slice { |
|
||||
if v.IP == element { |
|
||||
return true |
|
||||
} |
|
||||
} |
|
||||
return false |
|
||||
} |
|
||||
|
|
||||
// 添加消息到 UserMessages
|
|
||||
func addMessageToUserMessages(ip string, msg UdpMessage) { |
|
||||
if _, ok := UserMessages[ip]; !ok { |
|
||||
UserMessages[ip] = &Messages{} |
|
||||
} |
|
||||
UserMessages[ip].Messages = append(UserMessages[ip].Messages, msg) |
|
||||
} |
|
||||
|
|
||||
// 清空 UserMessages 中所有 IP 的消息列表
|
|
||||
func ClearAllUserMessages() { |
|
||||
for ip, msg := range UserMessages { |
|
||||
msg.Messages = []UdpMessage{} // 清空切片
|
|
||||
UserMessages[ip] = msg // 更新映射中的值
|
|
||||
} |
|
||||
} |
|
||||
func GetMessages() UserMessage { |
|
||||
return UserMessage{ |
|
||||
Messages: UserMessages, |
|
||||
Onlines: OnlineUsers, |
|
||||
} |
|
||||
} |
|
||||
func GetBroadcastAddr() string { |
|
||||
return libs.GetUdpAddr() |
|
||||
} |
|
||||
func GetBroadcastPort() string { |
|
||||
addr := GetBroadcastAddr() |
|
||||
return addr[strings.LastIndex(addr, ":")+1:] |
|
||||
} |
|
Loading…
Reference in new issue