diff --git a/godo/cmd/main.go b/godo/cmd/main.go index 9ae64ec..b179e11 100644 --- a/godo/cmd/main.go +++ b/godo/cmd/main.go @@ -5,6 +5,7 @@ import ( "godo/deps" "godo/files" "godo/libs" + "godo/localchat" "godo/store" "godo/sys" "godo/webdav" @@ -77,11 +78,10 @@ func OsStart() { fileRouter.HandleFunc("/unzip", files.HandleUnZip).Methods(http.MethodGet) fileRouter.HandleFunc("/watch", files.WatchHandler).Methods(http.MethodGet) - //localchatRouter := router.PathPrefix("/localchat").Subrouter() - // localchatRouter.HandleFunc("/sse", localchat.SseHandler).Methods(http.MethodGet) - // localchatRouter.HandleFunc("/message", localchat.HandleMessage).Methods(http.MethodPost) - // localchatRouter.HandleFunc("/file", localchat.HandlerFile).Methods(http.MethodPost) - // localchatRouter.HandleFunc("/check", localchat.CheckUserHanlder).Methods(http.MethodGet) + localchatRouter := router.PathPrefix("/localchat").Subrouter() + localchatRouter.HandleFunc("/message", localchat.HandleMessage).Methods(http.MethodPost) + localchatRouter.HandleFunc("/file", localchat.HandlerFile).Methods(http.MethodPost) + localchatRouter.HandleFunc("/udpaddr", localchat.HandleAddr).Methods(http.MethodGet) // 注册 WebDAV 路由 webdavRouter := router.PathPrefix("/webdav").Subrouter() diff --git a/godo/libs/dir.go b/godo/libs/dir.go index ae00bc8..2dd2ed1 100644 --- a/godo/libs/dir.go +++ b/godo/libs/dir.go @@ -7,14 +7,6 @@ import ( "runtime" ) -var UdpMap = map[string]any{ - "port": "20249", - "ips": []string{ - "224.0.0.251", - "255.255.255.255", - }, -} - func InitServer() error { err := LoadConfig() if err != nil { @@ -39,7 +31,7 @@ func InitServer() error { SetConfig(osInfo) udpAddr := ReqBody{ Name: "udpAddr", - Value: UdpMap, + Value: "224.0.0.251:20249", } SetConfig(udpAddr) } @@ -64,12 +56,12 @@ func GetOsDir() (string, error) { } return osDir.(string), nil } -func GetUdpAddr() map[string]any { +func GetUdpAddr() string { udp, ok := GetConfig("udpAddr") if !ok { - return UdpMap + return "224.0.0.251:20249" } - return udp.(map[string]any) + return udp.(string) } func GetAppDir() (string, error) { homeDir, err := os.UserHomeDir() diff --git a/godo/localchat/addr.go b/godo/localchat/addr.go new file mode 100644 index 0000000..c8119b8 --- /dev/null +++ b/godo/localchat/addr.go @@ -0,0 +1,103 @@ +package localchat + +import ( + "net" + "net/http" + "strconv" + + "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 + } + + udpAddr := libs.GetUdpAddr() + if addr == udpAddr { + libs.ErrorMsg(w, "addr is same as current addr") + return + } + + // 检查是否为多播地址 + 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") + } +} + +// 检查是否为多播地址 +func IsValidMulticastAddr(addr string) bool { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return false + } + + ip := net.ParseIP(host) + if ip == nil || !isMulticastIP(ip) { + return false + } + + _, err = strconv.Atoi(port) + return err == nil +} + +// 检查 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 + } + 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)) + if err != nil { + return false + } + + conn, err := net.ListenMulticastUDP("udp4", nil, udpAddr) + if err != nil { + return false + } + defer conn.Close() + + // 发送一条测试消息 + testMsg := []byte("Test message") + _, err = conn.WriteToUDP(testMsg, udpAddr) + if err != nil { + return false + } + + // 接收一条测试消息 + buffer := make([]byte, 1024) + n, _, err := conn.ReadFromUDP(buffer) + if err != nil { + return false + } + + if n > 0 && string(buffer[:n]) == "Test message" { + return true + } + + return false +} diff --git a/godo/localchat/file.go b/godo/localchat/file.go index b7c3df3..ca5a5d3 100644 --- a/godo/localchat/file.go +++ b/godo/localchat/file.go @@ -25,24 +25,6 @@ type FileChunk struct { Filename string `json:"filename"` } -// HandleMessage 处理 HTTP 请求 -func HandleMessage(w http.ResponseWriter, r *http.Request) { - var msg UdpMessage - decoder := json.NewDecoder(r.Body) - if err := decoder.Decode(&msg); err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) - return - } - defer r.Body.Close() - err := SendToIP(msg) - if err != nil { - http.Error(w, "Failed to send message", http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - fmt.Fprintln(w, "Text message send successfully") -} - func HandlerFile(w http.ResponseWriter, r *http.Request) { // 初始化多播地址 var msg UdpMessage @@ -59,18 +41,29 @@ func HandlerFile(w http.ResponseWriter, r *http.Request) { libs.HTTPError(w, http.StatusInternalServerError, err.Error()) return } - filePath := filepath.Join(basePath, msg.Message.(string)) - // 处理单个文件或整个文件夹 - if fileInfo, err := os.Stat(filePath); err == nil { - if fileInfo.IsDir() { - handleDirectory(filePath, toIp, msg) + paths, ok := msg.Message.([]string) + if !ok { + libs.HTTPError(w, http.StatusInternalServerError, "Invalid request body") + return + } + for _, p := range paths { + filePath := filepath.Join(basePath, p) + // 处理单个文件或整个文件夹 + if fileInfo, err := os.Stat(filePath); err == nil { + if fileInfo.IsDir() { + handleDirectory(filePath, toIp, msg) + } else { + handleFile(filePath, toIp, msg) + } } else { - handleFile(filePath, toIp, msg) + continue } - } else { - http.Error(w, "Failed to stat path", http.StatusInternalServerError) - return } + msg.Type = "text" + msg.Message = "文件发送完成" + SendToIP(msg) + libs.SuccessMsg(w, nil, "文件发送成功") + } func handleFile(filePath string, toIp string, message UdpMessage) { diff --git a/godo/localchat/info.go b/godo/localchat/info.go deleted file mode 100644 index 87f61e4..0000000 --- a/godo/localchat/info.go +++ /dev/null @@ -1,62 +0,0 @@ -package localchat - -// // 获取自己的IP地址和主机名 -// func GetMyIPAndHostname() (string, string, error) { -// hostname, err := os.Hostname() -// if err != nil { -// return "", "", fmt.Errorf("failed to get hostname: %w", err) -// } -// preferredIP, err := GetLocalIP() -// if err != nil { -// return "", "", fmt.Errorf("failed to get IP address: %w", err) -// } - -// return preferredIP, hostname, nil -// } - -// func GetLocalIP() (string, error) { -// addrs, err := net.Interfaces() -// if err != nil { -// return "", fmt.Errorf("failed to get network interfaces: %w", err) -// } - -// var preferredIP net.IP -// for _, iface := range addrs { -// if iface.Flags&net.FlagUp == 0 { -// // Skip interfaces that are not up -// continue -// } -// ifAddrs, err := iface.Addrs() -// if err != nil { -// continue // Ignore this interface if we can't get its addresses -// } -// for _, addr := range ifAddrs { -// var ip net.IP -// switch v := addr.(type) { -// case *net.IPNet: -// ip = v.IP -// case *net.IPAddr: -// ip = v.IP -// default: -// continue -// } -// if ip.IsLoopback() { -// continue // Skip loopback addresses -// } -// if ip.To4() != nil && (ip.IsPrivate() || ip.IsGlobalUnicast()) { -// // Prefer global unicast or private addresses over link-local -// preferredIP = ip -// break -// } -// } -// if preferredIP != nil { -// // Found a preferred IP, break out of the loop -// break -// } -// } - -// if preferredIP == nil { -// return "", fmt.Errorf("no preferred non-loopback IPv4 address found") -// } -// return preferredIP.String(), nil -// } diff --git a/godo/localchat/linux.go b/godo/localchat/linux.go deleted file mode 100644 index b128009..0000000 --- a/godo/localchat/linux.go +++ /dev/null @@ -1,108 +0,0 @@ -//go:build !windows -// +build !windows - -package localchat - -// import ( -// "encoding/json" -// "log" -// "net" -// ) - -// func SendBroadcast(broadcastAddr string, message UdpMessage) error { - -// addr, err := net.ResolveUDPAddr("udp4", broadcastAddr) -// if err != nil { -// log.Printf("Failed to resolve UDP address %s: %v", broadcastAddr, err) -// return err -// } - -// // 使用本地地址进行连接 -// localAddr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") -// if err != nil { -// log.Printf("Failed to resolve local UDP address: %v", err) -// return err -// } - -// conn, err := net.ListenUDP("udp4", localAddr) -// if err != nil { -// log.Printf("Failed to listen on UDP address %s: %v", broadcastAddr, err) -// return err -// } -// defer conn.Close() - -// // 获取本地 IP 地址 -// localIP, err := GetLocalIP() -// log.Printf("本地 IP 地址: %s", localIP) -// if err != nil { -// log.Printf("Failed to get local IP address: %v", err) -// return err -// } -// message.IP = localIP - -// data, err := json.Marshal(message) -// if err != nil { -// log.Printf("Failed to marshal JSON for %s: %v", broadcastAddr, err) -// return err -// } - -// _, err = conn.WriteToUDP(data, addr) -// if err != nil { -// log.Printf("Failed to write to UDP address %s: %v", broadcastAddr, err) -// return err -// } - -// log.Printf("发送消息到 %s 成功", broadcastAddr) -// return nil -// } - -// // 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 地址 -// localIP, err := GetLocalIP() -// if err != nil { -// log.Printf("Failed to get local IP address: %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 -// } -// if udpMsg.IP == localIP { -// continue -// } -// OnlineUsers[udpMsg.IP] = udpMsg -// if udpMsg.Type == "file" { -// RecieveFile(udpMsg) -// } -// log.Printf("Received message from %s: %s", remoteAddr, udpMsg.Hostname) -// } -// } - -// func GetBroadcastAddr() string { -// //return libs.GetUdpAddr() -// return "224.0.0.251:20249" -// } diff --git a/godo/localchat/send.go b/godo/localchat/send.go index 4e3357e..906c83d 100644 --- a/godo/localchat/send.go +++ b/godo/localchat/send.go @@ -5,16 +5,26 @@ import ( "fmt" "log" "net" + "net/http" ) -// import ( -// "encoding/json" -// "fmt" -// "godo/libs" -// "log" -// "net" -// "strings" -// ) +// HandleMessage 处理 HTTP 请求 +func HandleMessage(w http.ResponseWriter, r *http.Request) { + var msg UdpMessage + decoder := json.NewDecoder(r.Body) + if err := decoder.Decode(&msg); err != nil { + http.Error(w, "Invalid request body", http.StatusBadRequest) + return + } + defer r.Body.Close() + err := SendToIP(msg) + if err != nil { + http.Error(w, "Failed to send message", http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, "Text message send successfully") +} // SendToIP 向指定的 IP 地址发送 UDP 消息 func SendToIP(message UdpMessage) error { @@ -55,13 +65,3 @@ func SendToIP(message UdpMessage) error { log.Printf("发送 UDP 消息到 %s 成功", toIp) return nil } - -// // 获取 OnlineUsers 的最新状态 -// -// func GetOnlineUsers() map[string]UdpMessage { -// return OnlineUsers -// } -// -// func GetLocalIP() (string, error) { -// return libs.GetIPAddress() -// } diff --git a/godo/localchat/server.go b/godo/localchat/server.go new file mode 100644 index 0000000..ed34430 --- /dev/null +++ b/godo/localchat/server.go @@ -0,0 +1,71 @@ +package localchat + +import ( + "encoding/json" + "log" + "net" + "os" + "time" +) + +func InitBroadcast() { + ticker := time.NewTicker(5 * time.Second) // 每 5 秒发送一次广播消息 + defer ticker.Stop() + + for range ticker.C { + hostname, err := os.Hostname() + if err != nil { + log.Printf("Failed to get hostname: %v", err) + continue + } + message := UdpMessage{ + Type: "online", + Hostname: hostname, + Message: "", + Time: time.Now(), + } + //发送多播消息 + broadcastAddr := GetBroadcastAddr() + err = SendBroadcast(broadcastAddr, message) + if err != nil { + log.Println("Failed to send broadcast message:", err) + } + } +} +func SendBroadcast(broadcastAddr string, message UdpMessage) error { + + addr, err := net.ResolveUDPAddr("udp4", broadcastAddr) + if err != nil { + log.Printf("Failed to resolve UDP address %s: %v", broadcastAddr, err) + return err + } + + // 使用本地地址进行连接 + localAddr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") + if err != nil { + log.Printf("Failed to resolve local UDP address: %v", err) + return err + } + + conn, err := net.ListenUDP("udp4", localAddr) + if err != nil { + log.Printf("Failed to listen on UDP address %s: %v", broadcastAddr, err) + return err + } + defer conn.Close() + + data, err := json.Marshal(message) + if err != nil { + log.Printf("Failed to marshal JSON for %s: %v", broadcastAddr, err) + return err + } + + _, err = conn.WriteToUDP(data, addr) + if err != nil { + log.Printf("Failed to write to UDP address %s: %v", broadcastAddr, err) + return err + } + + log.Printf("发送消息到 %s 成功", broadcastAddr) + return nil +} diff --git a/godo/localchat/udp.go b/godo/localchat/udp.go index 1c75c50..1abb754 100644 --- a/godo/localchat/udp.go +++ b/godo/localchat/udp.go @@ -5,7 +5,6 @@ import ( "godo/libs" "log" "net" - "os" "strings" "time" ) @@ -18,76 +17,21 @@ type UdpMessage struct { Message any `json:"message"` } type UdpAddress struct { - Hostname string `json:"hostname"` - IP string `json:"ip"` + Hostname string `json:"hostname"` + IP string `json:"ip"` + Time time.Time `json:"time"` +} +type Messages struct { + Messages []UdpMessage `json:"messages"` } var OnlineUsers []UdpAddress +var UserMessages = make(map[string]*Messages) // 使用指针类型 func init() { go InitBroadcast() go ListenForBroadcast() } -func InitBroadcast() { - ticker := time.NewTicker(5 * time.Second) // 每 5 秒发送一次广播消息 - defer ticker.Stop() - - for range ticker.C { - hostname, err := os.Hostname() - if err != nil { - log.Printf("Failed to get hostname: %v", err) - continue - } - message := UdpMessage{ - Type: "online", - Hostname: hostname, - Message: "", - } - //发送多播消息 - broadcastAddr := GetBroadcastAddr() - err = SendBroadcast(broadcastAddr, message) - if err != nil { - log.Println("Failed to send broadcast message:", err) - } - } -} -func SendBroadcast(broadcastAddr string, message UdpMessage) error { - - addr, err := net.ResolveUDPAddr("udp4", broadcastAddr) - if err != nil { - log.Printf("Failed to resolve UDP address %s: %v", broadcastAddr, err) - return err - } - - // 使用本地地址进行连接 - localAddr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") - if err != nil { - log.Printf("Failed to resolve local UDP address: %v", err) - return err - } - - conn, err := net.ListenUDP("udp4", localAddr) - if err != nil { - log.Printf("Failed to listen on UDP address %s: %v", broadcastAddr, err) - return err - } - defer conn.Close() - - data, err := json.Marshal(message) - if err != nil { - log.Printf("Failed to marshal JSON for %s: %v", broadcastAddr, err) - return err - } - - _, err = conn.WriteToUDP(data, addr) - if err != nil { - log.Printf("Failed to write to UDP address %s: %v", broadcastAddr, err) - return err - } - - log.Printf("发送消息到 %s 成功", broadcastAddr) - return nil -} // ListenForBroadcast 监听多播消息 func ListenForBroadcast() { @@ -129,9 +73,19 @@ func ListenForBroadcast() { if containArr(ips, ip) { continue } - if !containIp(OnlineUsers, ip) { - OnlineUsers = append(OnlineUsers, UdpAddress{Hostname: udpMsg.Hostname, IP: ip}) - log.Printf("在线用户: %v", OnlineUsers) + 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) } @@ -152,11 +106,30 @@ func containIp(slice []UdpAddress, element string) bool { } 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 GetUserMessages() map[string]*Messages { + return UserMessages +} func GetOnlineUsers() []UdpAddress { return OnlineUsers } func GetBroadcastAddr() string { - return "224.0.0.251:20249" + return libs.GetUdpAddr() } func GetBroadcastPort() string { addr := GetBroadcastAddr() diff --git a/godo/localchat/windows.go b/godo/localchat/windows.go deleted file mode 100644 index 1802cf6..0000000 --- a/godo/localchat/windows.go +++ /dev/null @@ -1,106 +0,0 @@ -// //go:build windows -// // +build windows - -package localchat - -// import ( -// "encoding/json" -// "log" -// "net" -// ) - -// func SendBroadcast(broadcastAddr string, message UdpMessage) error { - -// addr, err := net.ResolveUDPAddr("udp4", broadcastAddr) -// if err != nil { -// log.Printf("Failed to resolve UDP address %s: %v", broadcastAddr, err) -// return err -// } - -// // 使用本地地址进行连接 -// localAddr, err := net.ResolveUDPAddr("udp4", "0.0.0.0:0") -// if err != nil { -// log.Printf("Failed to resolve local UDP address: %v", err) -// return err -// } - -// conn, err := net.ListenUDP("udp4", localAddr) -// if err != nil { -// log.Printf("Failed to listen on UDP address %s: %v", broadcastAddr, err) -// return err -// } -// defer conn.Close() - -// // 获取本地 IP 地址 -// localIP, err := GetLocalIP() -// log.Printf("本地 IP 地址: %s", localIP) -// if err != nil { -// log.Printf("Failed to get local IP address: %v", err) -// return err -// } -// message.IP = localIP - -// data, err := json.Marshal(message) -// if err != nil { -// log.Printf("Failed to marshal JSON for %s: %v", broadcastAddr, err) -// return err -// } - -// _, err = conn.WriteToUDP(data, addr) -// if err != nil { -// log.Printf("Failed to write to UDP address %s: %v", broadcastAddr, err) -// return err -// } - -// log.Printf("发送消息到 %s 成功", broadcastAddr) -// return nil -// } - -// // ListenForBroadcast 监听广播消息 -// func ListenForBroadcast() { -// // 使用本地地址监听 -// localAddr, err := net.ResolveUDPAddr("udp4", ":20249") -// if err != nil { -// log.Fatalf("Failed to resolve local UDP address: %v", err) -// } - -// conn, err := net.ListenUDP("udp4", localAddr) -// if err != nil { -// log.Fatalf("Failed to listen on UDP address: %v", err) -// } -// defer conn.Close() -// // 获取本地 IP 地址 -// localIP, err := GetLocalIP() -// if err != nil { -// log.Printf("Failed to get local IP address: %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 -// } -// if udpMsg.IP == localIP { -// continue -// } -// OnlineUsers[udpMsg.IP] = udpMsg -// if udpMsg.Type == "file" { -// RecieveFile(udpMsg) -// } -// log.Printf("Received message from %s: %s", remoteAddr, udpMsg.Hostname) -// } -// } - -// func GetBroadcastAddr() string { -// //return libs.GetUdpAddr() -// return "255.255.255.255:20249" -// }