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 |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"fmt" |
|||
"log" |
|||
"net" |
|||
"net/http" |
|||
"strconv" |
|||
"runtime" |
|||
"sync" |
|||
"time" |
|||
|
|||
"godo/libs" |
|||
) |
|||
|
|||
func HandleAddr(w http.ResponseWriter, r *http.Request) { |
|||
addr := r.URL.Query().Get("addr") |
|||
if addr == "" { |
|||
libs.ErrorMsg(w, "addr is empty") |
|||
return |
|||
} |
|||
type UserStatus struct { |
|||
Hostname string `json:"hostname"` |
|||
IP string `json:"ip"` |
|||
Time time.Time `json:"time"` |
|||
} |
|||
|
|||
udpAddr := libs.GetUdpAddr() |
|||
if addr == udpAddr { |
|||
libs.ErrorMsg(w, "addr is same as current addr") |
|||
return |
|||
} |
|||
var OnlineUsers = make(map[string]UserStatus) |
|||
|
|||
// 检查是否为多播地址
|
|||
if !IsValidMulticastAddr(addr) { |
|||
libs.ErrorMsg(w, "addr is not a valid multicast address") |
|||
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") |
|||
} |
|||
type UDPPayload struct { |
|||
Action string `json:"action"` |
|||
Data string `json:"data"` |
|||
} |
|||
|
|||
// 检查是否为多播地址
|
|||
func IsValidMulticastAddr(addr string) bool { |
|||
host, port, err := net.SplitHostPort(addr) |
|||
func getHostname(ip string) (string, error) { |
|||
hostname, err := net.LookupAddr(ip) |
|||
if err != nil { |
|||
return false |
|||
return "", fmt.Errorf("error getting hostname: %v", err) |
|||
} |
|||
|
|||
ip := net.ParseIP(host) |
|||
if ip == nil || !isMulticastIP(ip) { |
|||
return false |
|||
if len(hostname) > 0 { |
|||
return hostname[0], nil |
|||
} |
|||
|
|||
_, err = strconv.Atoi(port) |
|||
return err == nil |
|||
return "", fmt.Errorf("no hostname found for IP: %s", ip) |
|||
} |
|||
|
|||
// 检查 IP 是否为多播地址
|
|||
func isMulticastIP(ip net.IP) bool { |
|||
if ip.To4() != nil { |
|||
return ip[0]&0xF0 == 0xE0 // 检查 IPv4 多播地址范围 224.0.0.0 - 239.255.255.255
|
|||
// 发送 UDP 包并忽略响应
|
|||
func sendUDPPacket(ip string) error { |
|||
payload := UDPPayload{ |
|||
Action: "check", |
|||
Data: "", |
|||
} |
|||
return ip[0]&0xF0 == 0xE0 // 检查 IPv6 多播地址范围 FF00::/8
|
|||
} |
|||
|
|||
// 验证多播地址的可访问性
|
|||
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)) |
|||
log.Printf("sending ip: %+v", ip) |
|||
payloadBytes, err := json.Marshal(payload) |
|||
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 { |
|||
return false |
|||
log.Printf("error dialing UDP: %v", err) |
|||
return fmt.Errorf("error dialing UDP: %v", err) |
|||
} |
|||
defer conn.Close() |
|||
|
|||
// 发送一条测试消息
|
|||
testMsg := []byte("Test message") |
|||
_, err = conn.WriteToUDP(testMsg, udpAddr) |
|||
_, err = conn.Write(payloadBytes) |
|||
if err != nil { |
|||
return false |
|||
log.Printf("error writing UDP payload: %v", err) |
|||
return fmt.Errorf("error writing UDP payload: %v", err) |
|||
} |
|||
|
|||
// 接收一条测试消息
|
|||
buffer := make([]byte, 1024) |
|||
n, _, err := conn.ReadFromUDP(buffer) |
|||
return nil |
|||
} |
|||
|
|||
func concurrentGetIpInfo(ips []string) { |
|||
// 获取本地 IP 地址
|
|||
hostips, err := libs.GetValidIPAddresses() |
|||
if err != nil { |
|||
return false |
|||
log.Printf("failed to get local IP addresses: %v", err) |
|||
return |
|||
} |
|||
|
|||
if n > 0 && string(buffer[:n]) == "Test message" { |
|||
return true |
|||
var wg sync.WaitGroup |
|||
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 |
|||
} |
|||
|
|||
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