You've already forked CasaOS
mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-07-06 23:37:26 +02:00
298 lines
7.7 KiB
Go
298 lines
7.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/IceWhaleTech/CasaOS/model"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
|
"github.com/IceWhaleTech/CasaOS/types"
|
|
"github.com/lucas-clemente/quic-go"
|
|
uuid "github.com/satori/go.uuid"
|
|
)
|
|
|
|
var UDPConn *net.UDPConn
|
|
var PeopleMap map[string]quic.Stream
|
|
var Message chan model.MessageModel
|
|
var UDPAddressMap map[string]string
|
|
|
|
func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
Message = make(chan model.MessageModel)
|
|
|
|
srcAddr := &net.UDPAddr{
|
|
IP: net.IPv4zero, Port: 9904} //注意端口必须固定
|
|
addr := UDPAddressMap[msg.To]
|
|
ticker := msg.To
|
|
if server {
|
|
addr = config.ServerInfo.Handshake + ":9527"
|
|
ticker = "bench"
|
|
}
|
|
dstAddr, err := net.ResolveUDPAddr("udp", addr)
|
|
|
|
//DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。
|
|
//(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口
|
|
|
|
session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticker), quic_helper.GetQUICConfig())
|
|
if err != nil {
|
|
go MyService.Casa().PushConnectionStatus(m.UUId, err.Error(), m.From, m.To, m.Type)
|
|
return m, err
|
|
}
|
|
|
|
stream, err := session.OpenStreamSync(ctx)
|
|
if err != nil {
|
|
go MyService.Casa().PushConnectionStatus(m.UUId, err.Error(), m.From, m.To, m.Type)
|
|
session.CloseWithError(1, err.Error())
|
|
return m, err
|
|
}
|
|
|
|
SayHello(stream, msg.To)
|
|
|
|
SendData(stream, msg)
|
|
|
|
go ReadContent(stream)
|
|
result := <-Message
|
|
stream.Close()
|
|
go MyService.Casa().PushConnectionStatus(m.UUId, "OK", m.From, m.To, m.Type)
|
|
return result, nil
|
|
}
|
|
|
|
func SayHello(stream quic.Stream, to string) {
|
|
msg := model.MessageModel{}
|
|
msg.Type = types.PERSONHELLO
|
|
msg.Data = "hello"
|
|
msg.To = to
|
|
msg.From = config.ServerInfo.Token
|
|
msg.UUId = uuid.NewV4().String()
|
|
SendData(stream, msg)
|
|
}
|
|
|
|
//发送数据
|
|
func SendData(stream quic.Stream, m model.MessageModel) {
|
|
b, _ := json.Marshal(m)
|
|
prefixLength := file.PrefixLength(len(b))
|
|
data := append(prefixLength, b...)
|
|
stream.Write(data)
|
|
}
|
|
|
|
var Summary map[string]model.FileSummaryModel
|
|
|
|
//读取数据
|
|
func ReadContent(stream quic.Stream) {
|
|
for {
|
|
prefixByte := make([]byte, 6)
|
|
_, err := io.ReadFull(stream, prefixByte)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
break
|
|
}
|
|
prefixLength, err := strconv.Atoi(string(prefixByte))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
break
|
|
}
|
|
messageByte := make([]byte, prefixLength)
|
|
_, err = io.ReadFull(stream, messageByte)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
break
|
|
}
|
|
m := model.MessageModel{}
|
|
err = json.Unmarshal(messageByte, &m)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
break
|
|
}
|
|
|
|
if m.Type == types.PERSONDOWNLOAD {
|
|
dataModelByte, _ := json.Marshal(m.Data)
|
|
dataModel := model.TranFileModel{}
|
|
err := json.Unmarshal(dataModelByte, &dataModel)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
|
|
dataLengthByte := make([]byte, 8)
|
|
_, err = io.ReadFull(stream, dataLengthByte)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
dataLength, err := strconv.Atoi(string(dataLengthByte))
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
dataByte := make([]byte, dataLength)
|
|
_, err = io.ReadFull(stream, dataByte)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
sum := md5.Sum(dataByte)
|
|
hash := hex.EncodeToString(sum[:])
|
|
if dataModel.Hash != hash {
|
|
fmt.Println("hash不匹配", hash, dataModel.Hash)
|
|
continue
|
|
}
|
|
|
|
tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
|
|
file.IsNotExistMkDir(tempPath)
|
|
filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
|
|
tempFile, err := os.Stat(filepath)
|
|
|
|
if os.IsNotExist(err) || tempFile.Size() == 0 {
|
|
err = ioutil.WriteFile(filepath, dataByte, 0644)
|
|
task := model2.PersionDownloadDBModel{}
|
|
task.UUID = m.UUId
|
|
task.Error = err.Error()
|
|
task.State = types.DOWNLOADERROR
|
|
MyService.Download().SetDownloadError(task)
|
|
|
|
} else {
|
|
if file.GetHashByPath(filepath) != dataModel.Hash {
|
|
os.Remove(filepath)
|
|
err = ioutil.WriteFile(filepath, dataByte, 0644)
|
|
task := model2.PersionDownloadDBModel{}
|
|
task.UUID = m.UUId
|
|
task.Error = err.Error()
|
|
task.State = types.DOWNLOADERROR
|
|
MyService.Download().SetDownloadError(task)
|
|
}
|
|
}
|
|
|
|
files, err := ioutil.ReadDir(tempPath)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
if len(files) >= dataModel.Length {
|
|
summary := Summary[m.UUId]
|
|
file.SpliceFiles(tempPath, config.FileSettingInfo.DownloadDir+"/"+summary.Name, dataModel.Length, 0)
|
|
if file.GetHashByPath(config.FileSettingInfo.DownloadDir+"/"+summary.Name) == summary.Hash {
|
|
file.RMDir(tempPath)
|
|
task := model2.PersionDownloadDBModel{}
|
|
task.UUID = m.UUId
|
|
task.State = types.DOWNLOADFINISH
|
|
MyService.Download().EditDownloadState(task)
|
|
delete(Summary, m.UUId)
|
|
} else {
|
|
os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
|
|
task := model2.PersionDownloadDBModel{}
|
|
task.UUID = m.UUId
|
|
task.State = types.DOWNLOADERROR
|
|
MyService.Download().EditDownloadState(task)
|
|
}
|
|
|
|
break
|
|
}
|
|
} else if m.Type == types.PERSONSUMMARY {
|
|
|
|
dataModel := model.FileSummaryModel{}
|
|
dataModelByte, _ := json.Marshal(m.Data)
|
|
err := json.Unmarshal(dataModelByte, &dataModel)
|
|
fmt.Println(err)
|
|
|
|
task := model2.PersionDownloadDBModel{}
|
|
task.UUID = m.UUId
|
|
task.Name = dataModel.Name
|
|
task.Length = dataModel.Length
|
|
task.Size = dataModel.Size
|
|
task.State = types.DOWNLOADING
|
|
task.BlockSize = dataModel.BlockSize
|
|
task.Hash = dataModel.Hash
|
|
task.Type = 0
|
|
task.From = m.From
|
|
if len(dataModel.Message) > 0 {
|
|
task.State = types.DOWNLOADERROR
|
|
task.Error = dataModel.Message
|
|
}
|
|
|
|
MyService.Download().SaveDownload(task)
|
|
|
|
Summary[m.UUId] = dataModel
|
|
|
|
} else if m.Type == types.PERSONCONNECTION {
|
|
|
|
if len(m.Data.(string)) > 0 {
|
|
UDPAddressMap[m.From] = m.Data.(string)
|
|
} else {
|
|
delete(UDPAddressMap, m.From)
|
|
}
|
|
mi := model2.FriendModel{}
|
|
mi.Avatar = config.UserInfo.Avatar
|
|
mi.Profile = config.UserInfo.Description
|
|
mi.Name = config.UserInfo.NickName
|
|
mi.Token = config.ServerInfo.Token
|
|
msg := model.MessageModel{}
|
|
msg.Type = types.PERSONADDFRIEND
|
|
msg.Data = mi
|
|
msg.To = m.From
|
|
msg.From = config.ServerInfo.Token
|
|
msg.UUId = m.UUId
|
|
go Dial(msg, false)
|
|
Message <- m
|
|
break
|
|
} else if m.Type == "get_ip" {
|
|
if len(m.Data.(string)) == 0 {
|
|
delete(UDPAddressMap, m.From)
|
|
break
|
|
}
|
|
UDPAddressMap[m.From] = m.Data.(string)
|
|
Message <- m
|
|
break
|
|
} else {
|
|
Message <- m
|
|
}
|
|
}
|
|
Message <- model.MessageModel{}
|
|
}
|
|
|
|
func SendIPToServer() {
|
|
msg := model.MessageModel{}
|
|
msg.Type = "hello"
|
|
msg.Data = ""
|
|
msg.From = config.ServerInfo.Token
|
|
msg.To = config.ServerInfo.Token
|
|
msg.UUId = uuid.NewV4().String()
|
|
|
|
Dial(msg, true)
|
|
}
|
|
|
|
func LoopFriend() {
|
|
list := MyService.Friend().GetFriendList()
|
|
for i := 0; i < len(list); i++ {
|
|
msg := model.MessageModel{}
|
|
msg.Type = "get_ip"
|
|
msg.Data = ""
|
|
msg.From = config.ServerInfo.Token
|
|
msg.To = list[i].Token
|
|
msg.UUId = uuid.NewV4().String()
|
|
Dial(msg, true)
|
|
|
|
msg.Type = "hello"
|
|
msg.Data = ""
|
|
msg.From = config.ServerInfo.Token
|
|
msg.To = list[i].Token
|
|
msg.UUId = uuid.NewV4().String()
|
|
if _, ok := UDPAddressMap[list[i].Token]; ok {
|
|
go Dial(msg, false)
|
|
}
|
|
|
|
}
|
|
}
|