Browse Source

change check online

master
godo 9 months ago
parent
commit
4c1fc5351d
  1. 4
      godo/cmd/main.go
  2. 71
      godo/libs/chatip.go
  3. 16
      godo/libs/dir.go
  4. 190
      godo/localchat/addr.go
  5. 27
      godo/localchat/check.go
  6. 4
      godo/localchat/file.go
  7. 2
      godo/localchat/send.go
  8. 126
      godo/localchat/server.go
  9. 141
      godo/localchat/udp.go

4
godo/cmd/main.go

@ -80,9 +80,9 @@ func OsStart() {
localchatRouter := router.PathPrefix("/localchat").Subrouter()
localchatRouter.HandleFunc("/message", localchat.HandleMessage).Methods(http.MethodPost)
localchatRouter.HandleFunc("/file", localchat.HandlerFile).Methods(http.MethodPost)
//localchatRouter.HandleFunc("/file", localchat.HandlerFile).Methods(http.MethodPost)
localchatRouter.HandleFunc("/udpaddr", localchat.HandleAddr).Methods(http.MethodGet)
localchatRouter.HandleFunc("/check", localchat.HandleCheck).Methods(http.MethodGet)
// 注册 WebDAV 路由
webdavRouter := router.PathPrefix("/webdav").Subrouter()
webdavRouter.HandleFunc("/read", webdav.HandleReadDir).Methods(http.MethodGet)

71
godo/libs/chatip.go

@ -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)
}

16
godo/libs/dir.go

@ -29,11 +29,11 @@ func InitServer() error {
Value: info,
}
SetConfig(osInfo)
udpAddr := ReqBody{
Name: "udpAddr",
Value: "224.0.0.251:20249",
ipSetting := ReqBody{
Name: "chatIpSetting",
Value: GetDefaultChatIpSetting(),
}
SetConfig(udpAddr)
SetConfig(ipSetting)
}
return nil
@ -56,13 +56,7 @@ func GetOsDir() (string, error) {
}
return osDir.(string), nil
}
func GetUdpAddr() string {
udp, ok := GetConfig("udpAddr")
if !ok {
return "224.0.0.251:20249"
}
return udp.(string)
}
func GetAppDir() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {

190
godo/localchat/addr.go

@ -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]
}

27
godo/localchat/check.go

@ -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")
}

4
godo/localchat/file.go

@ -132,7 +132,9 @@ func SendFile(file *os.File, numChunks int, toIp string, message UdpMessage) {
}
// 发送文件块
addr, err := net.ResolveUDPAddr("udp4", toIp)
//addr, err := net.ResolveUDPAddr("udp4", toIp+":56780")
port := "56780"
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port))
if err != nil {
log.Fatalf("Failed to resolve UDP address: %v", err)
}

2
godo/localchat/send.go

@ -37,7 +37,7 @@ func HandleMessage(w http.ResponseWriter, r *http.Request) {
// SendToIP 向指定的 IP 地址发送 UDP 消息
func SendToIP(message UdpMessage) error {
toIp := message.IP
port := GetBroadcastPort()
port := "56780"
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%s", toIp, port))
if err != nil {
log.Printf("Failed to resolve UDP address %s:%s: %v", toIp, port, err)

126
godo/localchat/server.go

@ -4,68 +4,96 @@ import (
"encoding/json"
"log"
"net"
"os"
"time"
)
func InitBroadcast() {
ticker := time.NewTicker(5 * time.Second) // 每 5 秒发送一次广播消息
defer ticker.Stop()
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 Messages struct {
Messages []UdpMessage `json:"messages"`
}
type UserMessage struct {
Messages map[string]*Messages `json:"messages"`
Onlines map[string]UserStatus `json:"onlines"`
}
var UserMessages = make(map[string]*Messages)
func init() {
go UdpServer()
go CheckOnlines()
}
func CheckOnlines() {
CheckOnline()
ticker := time.NewTicker(60 * time.Second)
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)
}
// 检查客户端是否已断开连接
CheckOnline()
}
}
func SendBroadcast(broadcastAddr string, message UdpMessage) error {
addr, err := net.ResolveUDPAddr("udp4", broadcastAddr)
// UDP 服务器端逻辑
func UdpServer() {
// 监听 UDP 端口
listener, err := net.ListenPacket("udp", ":56780")
if err != nil {
log.Printf("Failed to resolve UDP address %s: %v", broadcastAddr, err)
return err
log.Fatalf("error setting up listener: %v", err)
}
defer listener.Close()
// 使用本地地址进行连接
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
}
log.Println("UDP server started on :56780")
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()
// 无限循环,监听 UDP 请求
for {
buffer := make([]byte, 1024)
data, err := json.Marshal(message)
if err != nil {
log.Printf("Failed to marshal JSON for %s: %v", broadcastAddr, err)
return err
}
n, remoteAddr, err := listener.ReadFrom(buffer)
if err != nil {
log.Printf("error reading from UDP: %v", err)
continue
}
_, err = conn.WriteToUDP(data, addr)
if err != nil {
log.Printf("Failed to write to UDP address %s: %v", broadcastAddr, err)
return err
log.Printf("Received UDP packet from %v: %s", remoteAddr, buffer[:n])
// 解析 UDP 数据
var udpMsg UdpMessage
err = json.Unmarshal(buffer[:n], &udpMsg)
if err != nil {
log.Printf("error unmarshalling UDP message: %v", err)
continue
}
if udpMsg.Type == "heartbeat" {
UpdateUserStatus(udpMsg.IP, udpMsg.Hostname)
continue
}
if udpMsg.Type == "file" {
RecieveFile(udpMsg)
continue
}
// 添加消息到 UserMessages
AddMessage(udpMsg)
}
log.Printf("发送消息到 %s 成功", broadcastAddr)
return nil
}
func ClearAllUserMessages() {
for ip, msg := range UserMessages {
msg.Messages = []UdpMessage{} // 清空切片
UserMessages[ip] = msg // 更新映射中的值
}
}
func GetMessages() UserMessage {
return UserMessage{
Messages: UserMessages,
Onlines: OnlineUsers,
}
}
func AddMessage(msg UdpMessage) {
if _, ok := UserMessages[msg.IP]; !ok {
UserMessages[msg.IP] = &Messages{}
}
UserMessages[msg.IP].Messages = append(UserMessages[msg.IP].Messages, msg)
}

141
godo/localchat/udp.go

@ -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…
Cancel
Save