1
0
mirror of https://github.com/IceWhaleTech/CasaOS.git synced 2025-07-09 23:45:31 +02:00
Files
CasaOS/service/person.go

513 lines
13 KiB
Go
Raw Normal View History

2022-02-17 18:43:25 +08:00
package service
import (
"context"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
2022-02-17 18:43:25 +08:00
"encoding/json"
"encoding/pem"
2022-02-17 18:43:25 +08:00
"fmt"
2022-02-28 14:14:39 +08:00
"io"
2022-02-17 18:43:25 +08:00
"log"
"math/big"
2022-02-17 18:43:25 +08:00
"net"
2022-02-28 14:14:39 +08:00
"os"
"path/filepath"
2022-02-17 18:43:25 +08:00
"reflect"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
2022-02-17 18:43:25 +08:00
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go"
"gorm.io/gorm"
2022-02-17 18:43:25 +08:00
)
type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error)
Handshake(m model.ConnectState)
Download(m model.MessageModel)
GetFileDetail(uuid, path, to string)
SendFileData(m model.MessageModel, blockSize int, length int)
ReplyGetFileDetail(m model.MessageModel)
ReceiveFileData(m model.MessageModel)
ReceiveGetFileDetail(m model.MessageModel)
//------------ database
AddDownloadTask(m model2.PersionDownloadDBModel) //添加下载任务
EditDownloadState(m model2.PersionDownloadDBModel) //只修改状态
EditDownloading(m model2.PersionDownloadDBModel, section model2.PersionFileSectionModel)
SaveDownloadState(m model2.PersionDownloadDBModel)
DelDownload(uuid string)
GetDownloadById(uuid string) model2.PersionDownloadDBModel
2022-02-17 18:43:25 +08:00
}
type personService struct {
db *gorm.DB
2022-02-17 18:43:25 +08:00
}
var IpInfo model.PersionModel
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 (p *personService) Handshake(m model.ConnectState) {
//1先进行udp打通成功
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: 9901} //注意端口必须固定
dstAddr := &net.UDPAddr{
IP: net.ParseIP(config.ServerInfo.Handshake), Port: 9527}
//DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。
//(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口
conn, err := net.DialUDP("udp", srcAddr, dstAddr)
if err != nil {
fmt.Println(err)
}
b, _ := json.Marshal(m)
if _, err = conn.Write(b); err != nil {
fmt.Println(err)
}
data := make([]byte, 1024)
//ReadFromUDP从c读取一个UDP数据包,将有效负载拷贝到b,返回拷贝字节数和数据包来源地址。
//ReadFromUDP方***在超过一个固定的时间点之后超时,并返回一个错误。
n, _, err := conn.ReadFromUDP(data)
if err != nil {
fmt.Printf("error during read: %s", err)
}
conn.Close()
toPersion := model.PersionModel{}
err = json.Unmarshal(data[:n], &toPersion)
if err != nil {
fmt.Println(err)
}
2022-02-18 19:06:03 +08:00
//websocket 连接
2022-02-17 18:43:25 +08:00
// bidirectionHole(srcAddr, &anotherPeer)
//2udp打洞成功向服务器汇报打洞结果
//3转udp打洞
}
func (p *personService) AddDownloadTask(m model2.PersionDownloadDBModel) {
p.db.Create(&m)
}
func (p *personService) EditDownloadState(m model2.PersionDownloadDBModel) {
p.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State)
}
func (p *personService) EditDownloading(m model2.PersionDownloadDBModel, section model2.PersionFileSectionModel) {
b, _ := json.Marshal(section)
m.Section = string(b)
p.db.Model(&m).Where("uuid = ?", m.UUID).Update("section", m.Section)
}
func (p *personService) DelDownload(uuid string) {
var m model2.PersionDownloadDBModel
p.db.Where("uuid = ?", uuid).Delete(&m)
}
func (p *personService) GetDownloadById(uuid string) model2.PersionDownloadDBModel {
var m model2.PersionDownloadDBModel
p.db.Model(m).Where("uuid = ?", uuid).First(&m)
return m
}
func (p *personService) SaveDownloadState(m model2.PersionDownloadDBModel) {
p.db.Save(&m)
}
2022-02-28 14:14:39 +08:00
var ipAddress chan string
2022-02-17 18:43:25 +08:00
type sysConn struct {
conn *net.UDPConn
header string
auth cipher.AEAD
}
2022-02-28 14:14:39 +08:00
func UDPConnect(ips []string) {
quicConfig := &quic.Config{
ConnectionIDLength: 12,
HandshakeIdleTimeout: time.Second * 8,
MaxIdleTimeout: time.Second * 45,
MaxIncomingStreams: 32,
MaxIncomingUniStreams: -1,
KeepAlive: true,
}
fmt.Println(quicConfig)
//PersonUDPMap = make(map[string]*net.UDPAddr)
2022-02-28 14:14:39 +08:00
ipAddress = make(chan string)
2022-02-28 14:14:39 +08:00
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: 9901}
fmt.Println(srcAddr)
//UDPconn, err := net.ListenUDP("udp", srcAddr)
// sysconn := &sysConn{
// conn: UDPconn,
// header: "",
// auth: nil,
// }
// if err != nil {
// fmt.Println(err)
// }
// liste, err := quic.Listen(UDPconn, generateTLSConfig(), nil)
// if err != nil {
// fmt.Println(err)
// }
// ssss, err := liste.Accept(context.Background())
// if err != nil {
// fmt.Println(err)
// }
// st, err := ssss.AcceptStream(context.Background())
// if err != nil {
// fmt.Println(err)
// }
// st.Write([]byte("ssss"))
qlister, err := quic.ListenAddr("0.0.0.0:9901", generateTLSConfig(), nil)
//qlister, err := quic.Listen(UDPconn, nil, nil)
if err != nil {
fmt.Println("quic错误", qlister)
}
//session, e := qlister.Accept()
sess, err := qlister.Accept(context.Background())
sess.SendMessage([]byte("aaaa"))
stream, err := sess.AcceptStream(context.Background())
stream.Write([]byte("bbb"))
//quic.Dial()
if err != nil {
fmt.Println("quic错误", qlister)
}
2022-02-28 14:14:39 +08:00
if err != nil {
fmt.Println("监听错误", err.Error())
}
for _, v := range ips {
dstAddr := &net.UDPAddr{
IP: net.ParseIP(v), Port: 9901}
fmt.Println(v, "开始监听")
//quic.Dial()
go AsyncUDPConnect(dstAddr)
2022-02-28 14:14:39 +08:00
}
for {
data := make([]byte, 1024)
n, add, err := UDPconn.ReadFromUDP(data)
fmt.Println(add)
2022-02-28 14:14:39 +08:00
if err != nil {
log.Printf("error during read:%s\n", err)
} else {
2022-02-28 14:14:39 +08:00
fmt.Println("收到数据:", string(data[:n]))
msg := model.MessageModel{}
err := json.Unmarshal(data[:n], &msg)
if err != nil {
log.Printf("转义错误:%s\n", err)
}
//todo:检查数据库是否为合法请求
if msg.Type == "hi" {
//add ip
//PersonUDPMap[msg.From] = add
} else if msg.Type == "browse" {
//获取目录结构
} else if msg.Type == "file_detail" {
MyService.Person().ReplyGetFileDetail(msg)
} else if msg.Type == "file_detail_reply" {
MyService.Person().ReceiveGetFileDetail(msg)
} else if msg.Type == "file_data_reply" {
MyService.Person().ReceiveFileData(msg)
} else {
fmt.Println("未知事件")
}
2022-02-28 14:14:39 +08:00
}
}
}
// Setup a bare-bones TLS config for the server
func generateTLSConfig() *tls.Config {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
2022-02-28 14:14:39 +08:00
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
panic(err)
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
2022-02-28 14:14:39 +08:00
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
2022-02-28 14:14:39 +08:00
if err != nil {
panic(err)
2022-02-28 14:14:39 +08:00
}
// return &tls.Config{
// ClientSessionCache: globalSessionCache,
// RootCAs: root,
// InsecureSkipVerify: false,
// NextProtos: nil,
// SessionTicketsDisabled: true,
// }
return &tls.Config{
Certificates: []tls.Certificate{tlsCert},
NextProtos: []string{"quic-echo-example"},
2022-02-28 14:14:39 +08:00
}
}
//首次获取文件信息
func (p *personService) GetFileList(uuid, path, to string) {
msg := model.MessageModel{}
msg.Type = "file_list"
msg.Data = path
msg.To = to
msg.From = config.ServerInfo.Token
msg.UUId = uuid
b, _ := json.Marshal(msg)
fmt.Println(b)
// if ip, ok := PersonUDPMap[msg.To]; ok {
// _, err := UDPconn.WriteToUDP(b, ip)
// if err != nil {
// fmt.Println("写入错误", err)
// }
// }
//接收
2022-02-28 14:14:39 +08:00
}
//首次获取文件信息
func (p *personService) GetFileDetail(uuid, path, to string) {
msg := model.MessageModel{}
msg.Type = "file_detail"
msg.Data = path
msg.To = to
msg.From = config.ServerInfo.Token
msg.UUId = uuid
b, _ := json.Marshal(msg)
fmt.Println(b)
// if ip, ok := PersonUDPMap[msg.To]; ok {
// _, err := UDPconn.WriteToUDP(b, ip)
// if err != nil {
// fmt.Println("写入错误", err)
// }
// }
//创建临时文件夹
file.MkDir("/oasis/download/" + uuid)
}
2022-02-28 14:14:39 +08:00
func (p *personService) Download(m model.MessageModel) {
fDetail, err := os.Stat("/Users/liangjianli/Documents/images")
//发送需要发送的数据摘要
if err != nil {
fmt.Println("未获取到文件信息")
2022-02-28 14:14:39 +08:00
}
summary := model.FileSummaryModel{}
summary.Hash = file.GetHashByPath(fDetail.Name())
summary.Path = m.Data.(string)
summary.BlockSize, summary.Length = file.GetBlockInfo(fDetail.Size())
msg := model.MessageModel{}
msg.Type = "download-reply"
msg.Data = summary
msg.From = config.ServerInfo.Token
msg.UUId = ""
b, _ := json.Marshal(msg)
fmt.Println(b)
// if ip, ok := PersonUDPMap[m.From]; ok {
// _, err := UDPconn.WriteToUDP(b, ip)
// if err != nil {
// fmt.Println("写入错误", err)
// }
// }
2022-02-28 14:14:39 +08:00
}
//receive file data
func (p *personService) ReceiveFileData(m model.MessageModel) {
task := p.GetDownloadById(m.UUId)
2022-02-28 14:14:39 +08:00
//需要重置参数
tempPath := "/oasis/download/" + task.UUID
tempFilePath := tempPath + "/" + task.Name
fmt.Println(tempFilePath)
filePath := "/oasis/download/" + task.Name
2022-02-28 14:14:39 +08:00
bss, _ := json.Marshal(m.Data)
tran := model.TranFileModel{}
err := json.Unmarshal(bss, &tran)
2022-02-28 14:14:39 +08:00
if err != nil {
fmt.Println(err)
}
// if file.ComparisonHash(tran.Hash) {
// f, err := os.Create(tempFilePath + strconv.Itoa(tran.Index))
// if err != nil {
// fmt.Println("创建文件错误", err)
// }
// defer f.Close()
// // _, err = f.Write(tran.Data)
// if err != nil {
// fmt.Println("写入错误", err, tran.Index)
// }
// }
var k int
err = filepath.Walk(tempPath, func(filename string, fi os.FileInfo, err error) error { //遍历目录
if fi.IsDir() { // 忽略目录
return nil
}
k++
return nil
})
2022-02-17 18:43:25 +08:00
if err != nil {
fmt.Println("获取文件错误", err)
2022-02-17 18:43:25 +08:00
}
if task.Length == k {
//err := file.SpliceFiles(tempPath, filePath)
if err == nil {
if h := file.GetHashByPath(filePath); h == task.Hash {
//最终文件比对成功
task.State = types.DOWNLOADFINISH
p.EditDownloadState(task)
//remove temp path
file.RMDir(tempPath)
2022-02-17 18:43:25 +08:00
}
}
}
2022-02-17 18:43:25 +08:00
}
2022-02-17 18:43:25 +08:00
//1:say hi
//2:发送文件名称
//3:发送数据
2022-02-17 18:43:25 +08:00
//========================================接收端============================================================================================
2022-02-17 18:43:25 +08:00
// reply file detail
func (p *personService) ReplyGetFileDetail(m model.MessageModel) {
path := m.Data.(string)
f, err := os.Stat(path)
if err != nil {
fmt.Println(err)
2022-02-17 18:43:25 +08:00
}
summary := model.FileSummaryModel{}
summary.Name = f.Name()
summary.Size = f.Size()
summary.Hash = file.GetHashByPath(path)
summary.Path = path
summary.BlockSize, summary.Length = file.GetBlockInfo(f.Size())
msg := model.MessageModel{}
msg.Type = "file_detail_reply"
msg.Data = summary
msg.From = config.ServerInfo.Token
msg.To = m.From
msg.UUId = m.UUId
b, _ := json.Marshal(msg)
// if ip, ok := PersonUDPMap[m.To]; ok {
// _, err := UDPconn.WriteToUDP(b, ip)
// if err != nil {
// fmt.Println("写入错误", err)
// }
// }
fmt.Println(b)
//开始发送数据
p.SendFileData(m, summary.BlockSize, summary.Length)
2022-02-17 18:43:25 +08:00
}
func (p *personService) SendFileData(m model.MessageModel, blockSize int, length int) {
path := m.Data.(string)
2022-02-28 14:14:39 +08:00
f, err := os.Open(path)
2022-02-28 14:14:39 +08:00
if err != nil {
//读取时移动了文件,需要保存数据到数据库
fmt.Println("读取失败", err)
2022-02-28 14:14:39 +08:00
}
buf := make([]byte, blockSize)
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
_, err := f.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
2022-02-28 14:14:39 +08:00
}
tran.Hash = file.GetHashByContent(buf)
tran.Index = i + 1
msg := model.MessageModel{}
msg.Type = "file_data_reply"
msg.Data = tran
msg.From = config.ServerInfo.Token
msg.To = m.From
msg.UUId = m.UUId
b, _ := json.Marshal(msg)
// if ip, ok := PersonUDPMap[m.To]; ok {
// _, err := UDPconn.WriteToUDP(b, ip)
// if err != nil {
// fmt.Println("写入错误", err)
// }
// }
fmt.Println(b)
2022-02-28 14:14:39 +08:00
}
}
// 文件摘要返回
func (p *personService) ReceiveGetFileDetail(m model.MessageModel) {
2022-02-28 14:14:39 +08:00
task := p.GetDownloadById("")
bss, _ := json.Marshal(m.Data)
summary := model.FileSummaryModel{}
err := json.Unmarshal(bss, &summary)
2022-02-28 14:14:39 +08:00
if err != nil {
fmt.Println(err)
}
task.Hash = summary.Hash
task.Length = summary.Length
task.Size = summary.Size
2022-02-28 14:14:39 +08:00
p.SaveDownloadState(task)
2022-02-28 14:14:39 +08:00
}
func AsyncUDPConnect(dst *net.UDPAddr) {
2022-02-28 14:14:39 +08:00
for {
time.Sleep(2 * time.Second)
if _, err := UDPconn.WriteToUDP([]byte(dst.IP.String()+" is ok"), dst); err != nil {
log.Println("send msg fail", err)
return
2022-02-28 14:14:39 +08:00
} else {
fmt.Println(dst.IP)
fmt.Println(dst.IP.To4())
2022-02-28 14:14:39 +08:00
}
}
}
func NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db}
2022-02-17 18:43:25 +08:00
}