CasaOS/service/person.go
2022-04-06 12:10:51 +08:00

360 lines
8.7 KiB
Go

package service
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"net"
"os"
"reflect"
"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"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go"
"gorm.io/gorm"
)
type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error)
}
type personService struct {
db *gorm.DB
}
var IpInfo model.PersionModel
var CancelList map[string]string
func PushIpInfo(token string) {
m := model.PersionModel{}
m.Ips = GetDeviceAllIP()
m.Token = token
b, _ := json.Marshal(m)
if reflect.DeepEqual(IpInfo, m) {
return
}
head := make(map[string]string)
infoS := httper2.Post(config.ServerInfo.Handshake+"/v1/update", b, "application/json", head)
fmt.Println(infoS)
}
func (p *personService) GetPersionInfo(token string) (m model.PersionModel, err error) {
infoS := httper2.Get(config.ServerInfo.Handshake+"/v1/ips/"+token, nil)
err = json.Unmarshal([]byte(infoS), &m)
return
}
func NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db}
}
//=======================================================================================================================================================================
var StreamList map[string]quic.Stream
var ServiceMessage chan model.MessageModel
func UDPService() {
port := 0
if len(config.ServerInfo.UDPPort) > 0 {
port, _ = strconv.Atoi(config.ServerInfo.UDPPort)
if port != 0 && !port2.IsPortAvailable(port, "udp") {
port = 0
}
}
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: port}
var err error
UDPConn, err = net.ListenUDP("udp", srcAddr)
if err != nil {
fmt.Println(err)
}
listener, err := quic.Listen(UDPConn, quic_helper.GetGenerateTLSConfig(config.ServerInfo.Token), quic_helper.GetQUICConfig())
if err != nil {
fmt.Println(err)
}
defer listener.Close()
ctx := context.Background()
acceptFailures := 0
const maxAcceptFailures = 10
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
}
session, err := listener.Accept(ctx)
if err != nil {
fmt.Println("Listen (BEP/quic): Accepting connection:", err)
acceptFailures++
if acceptFailures > maxAcceptFailures {
// Return to restart the listener, because something
// seems permanently damaged.
fmt.Println(err)
return
}
// Slightly increased delay for each failure.
time.Sleep(time.Duration(acceptFailures) * time.Second)
continue
}
acceptFailures = 0
streamCtx, cancel := context.WithTimeout(ctx, time.Second*10)
stream, err := session.AcceptStream(streamCtx)
cancel()
if err != nil {
fmt.Println("failed to accept stream from %s: %v", session.RemoteAddr(), err)
_ = session.CloseWithError(1, err.Error())
continue
}
// prefixByte := make([]byte, 4)
// c1, err := io.ReadFull(stream, prefixByte)
// fmt.Println(c1, err)
// prefixLength, err := strconv.Atoi(string(prefixByte))
// if err != nil {
// fmt.Println(err)
// }
// messageByte := make([]byte, prefixLength)
// t, err := io.ReadFull(stream, messageByte)
// fmt.Println(t, err)
// m := model.MessageModel{}
// err = json.Unmarshal(messageByte, &m)
// if err != nil {
// fmt.Println(err)
// }
go ProcessingContent(stream)
}
}
//处理内容
func ProcessingContent(stream quic.Stream) {
for {
prefixByte := make([]byte, 6)
_, err := io.ReadFull(stream, prefixByte)
if err != nil {
fmt.Println(err)
return
}
prefixLength, err := strconv.Atoi(string(prefixByte))
if err != nil {
fmt.Println(err)
}
messageByte := make([]byte, prefixLength)
_, err = io.ReadFull(stream, messageByte)
if err != nil {
return
}
m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m)
if err != nil {
fmt.Println(err)
}
if m.Type == types.PERSONHELLO {
//nothing
continue
} else if m.Type == types.PERSONDIRECTORY {
friend := model2.FriendModel{}
friend.Token = m.From
var list []model.Path
rFriend := MyService.Friend().GetFriendById(friend)
if !reflect.DeepEqual(rFriend, model2.FriendModel{Token: m.From}) && !rFriend.Block {
if m.Data.(string) == "" || m.Data.(string) == "/" {
for _, v := range config.FileSettingInfo.ShareDir {
//tempList := MyService.ZiMa().GetDirPath(v)
temp := MyService.ZiMa().GetDirPathOne(v)
list = append(list, temp)
}
} else {
list = MyService.ZiMa().GetDirPath(m.Data.(string))
}
} else {
list = []model.Path{}
}
m.To = m.From
m.Data = list
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == types.PERSONDOWNLOAD {
SendFileData(stream, m.Data.(string), m.From, m.UUId)
break
} else if m.Type == types.PERSONADDFRIEND {
fmt.Println("有用户来请求加好友", m)
friend := model2.FriendModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &friend)
if err != nil {
fmt.Println(err)
continue
}
go MyService.Friend().UpdateOrCreate(friend)
mi := model2.FriendModel{}
mi.Avatar = config.UserInfo.Avatar
mi.Profile = config.UserInfo.Description
mi.NickName = config.UserInfo.NickName
m.To = m.From
m.Data = mi
m.Type = types.PERSONADDFRIEND
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} 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.NickName = config.UserInfo.NickName
// mi.Token = config.ServerInfo.Token
user := MyService.Casa().GetUserInfoByShareId(m.From)
friend := model2.FriendModel{}
friend.Token = m.From
friend.Avatar = user.Avatar
friend.Block = false
friend.NickName = user.NickName
friend.Profile = user.Avatar
friend.Version = user.Version
MyService.Friend().AddFriend(friend)
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
Dial(msg, false)
break
} else if m.Type == types.PERSONCANCEL {
CancelList[m.UUId] = "cancel"
break
} else {
//不应有不做返回的数据
//ServiceMessage <- m
break
}
}
stream.Close()
}
//文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
summary := model.FileSummaryModel{}
msg := model.MessageModel{}
msg.Type = types.PERSONSUMMARY
msg.From = config.ServerInfo.Token
msg.To = to
msg.UUId = uuid
fStat, err := os.Stat(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
blockSize, length := file.GetBlockInfo(fStat.Size())
f, err := os.Open(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
//send file summary first
summary.BlockSize = blockSize
summary.Hash = file.GetHashByPath(filePath)
summary.Length = length
summary.Name = fStat.Name()
summary.Size = fStat.Size()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
bufferedReader := bufio.NewReader(f)
buf := make([]byte, blockSize)
defer stream.Close()
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
n, err := bufferedReader.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
}
tran.Hash = file.GetHashByContent(buf[:n])
tran.Index = i
tran.Length = length
fileMsg := model.MessageModel{}
fileMsg.Type = types.PERSONDOWNLOAD
fileMsg.Data = tran
fileMsg.From = config.ServerInfo.Token
fileMsg.To = to
fileMsg.UUId = uuid
b, _ := json.Marshal(fileMsg)
prefixLength := file.PrefixLength(len(b))
dataLength := file.DataLength(len(buf[:n]))
data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...)
if _, ok := CancelList[uuid]; ok {
delete(CancelList, uuid)
return nil
}
stream.Write(data)
}
return nil
}