|
@@ -1,28 +1,23 @@
|
|
package service
|
|
package service
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "bufio"
|
|
"context"
|
|
"context"
|
|
- "crypto/cipher"
|
|
|
|
- "crypto/rand"
|
|
|
|
- "crypto/rsa"
|
|
|
|
- "crypto/tls"
|
|
|
|
- "crypto/x509"
|
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
- "encoding/pem"
|
|
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
- "log"
|
|
|
|
- "math/big"
|
|
|
|
"net"
|
|
"net"
|
|
"os"
|
|
"os"
|
|
- "path/filepath"
|
|
|
|
"reflect"
|
|
"reflect"
|
|
|
|
+ "strconv"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
"github.com/IceWhaleTech/CasaOS/model"
|
|
"github.com/IceWhaleTech/CasaOS/model"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
|
|
|
+ "github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
|
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
|
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
|
|
|
+ port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
|
"github.com/IceWhaleTech/CasaOS/types"
|
|
"github.com/IceWhaleTech/CasaOS/types"
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/lucas-clemente/quic-go"
|
|
@@ -31,21 +26,6 @@ import (
|
|
|
|
|
|
type PersonService interface {
|
|
type PersonService interface {
|
|
GetPersionInfo(token string) (m model.PersionModel, err error)
|
|
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
|
|
|
|
}
|
|
}
|
|
|
|
|
|
type personService struct {
|
|
type personService struct {
|
|
@@ -53,6 +33,7 @@ type personService struct {
|
|
}
|
|
}
|
|
|
|
|
|
var IpInfo model.PersionModel
|
|
var IpInfo model.PersionModel
|
|
|
|
+var CancelList map[string]string
|
|
|
|
|
|
func PushIpInfo(token string) {
|
|
func PushIpInfo(token string) {
|
|
|
|
|
|
@@ -74,439 +55,306 @@ func (p *personService) GetPersionInfo(token string) (m model.PersionModel, err
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
-//尝试连接
|
|
|
|
-func (p *personService) Handshake(m model.ConnectState) {
|
|
|
|
- //1先进行udp打通成功
|
|
|
|
|
|
+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{
|
|
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)
|
|
|
|
|
|
+ IP: net.IPv4zero, Port: port}
|
|
|
|
+ var err error
|
|
|
|
+ UDPConn, err = net.ListenUDP("udp", srcAddr)
|
|
if err != nil {
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
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)
|
|
|
|
|
|
+ listener, err := quic.Listen(UDPConn, quic_helper.GetGenerateTLSConfig(config.ServerInfo.Token), quic_helper.GetQUICConfig())
|
|
if err != nil {
|
|
if err != nil {
|
|
- fmt.Printf("error during read: %s", err)
|
|
|
|
|
|
+ fmt.Println(err)
|
|
}
|
|
}
|
|
- conn.Close()
|
|
|
|
- toPersion := model.PersionModel{}
|
|
|
|
- err = json.Unmarshal(data[:n], &toPersion)
|
|
|
|
|
|
+ defer listener.Close()
|
|
|
|
+ ctx := context.Background()
|
|
|
|
+ acceptFailures := 0
|
|
|
|
+ const maxAcceptFailures = 10
|
|
if err != nil {
|
|
if err != nil {
|
|
- fmt.Println(err)
|
|
|
|
|
|
+ panic(err)
|
|
}
|
|
}
|
|
|
|
|
|
- //websocket 连接
|
|
|
|
- // 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)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-var ipAddress chan string
|
|
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-ctx.Done():
|
|
|
|
+ fmt.Println(ctx.Err())
|
|
|
|
+ return
|
|
|
|
+ default:
|
|
|
|
+ }
|
|
|
|
|
|
-type sysConn struct {
|
|
|
|
- conn *net.UDPConn
|
|
|
|
- header string
|
|
|
|
- auth cipher.AEAD
|
|
|
|
-}
|
|
|
|
|
|
+ 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
|
|
|
|
+ }
|
|
|
|
|
|
-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)
|
|
|
|
- ipAddress = make(chan string)
|
|
|
|
|
|
+ // Slightly increased delay for each failure.
|
|
|
|
+ time.Sleep(time.Duration(acceptFailures) * time.Second)
|
|
|
|
|
|
- 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)
|
|
|
|
- }
|
|
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
|
|
- if err != nil {
|
|
|
|
- fmt.Println("监听错误", err.Error())
|
|
|
|
- }
|
|
|
|
- for _, v := range ips {
|
|
|
|
- dstAddr := &net.UDPAddr{
|
|
|
|
- IP: net.ParseIP(v), Port: 9901}
|
|
|
|
|
|
+ acceptFailures = 0
|
|
|
|
|
|
- fmt.Println(v, "开始监听")
|
|
|
|
|
|
+ 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
|
|
|
|
+ }
|
|
|
|
|
|
- //quic.Dial()
|
|
|
|
|
|
+ // 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 AsyncUDPConnect(dstAddr)
|
|
|
|
|
|
+ go ProcessingContent(stream)
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
|
|
+//处理内容
|
|
|
|
+func ProcessingContent(stream quic.Stream) {
|
|
for {
|
|
for {
|
|
- data := make([]byte, 1024)
|
|
|
|
- n, add, err := UDPconn.ReadFromUDP(data)
|
|
|
|
- fmt.Println(add)
|
|
|
|
|
|
+ prefixByte := make([]byte, 6)
|
|
|
|
+ _, err := io.ReadFull(stream, prefixByte)
|
|
if err != nil {
|
|
if err != nil {
|
|
- log.Printf("error during read:%s\n", err)
|
|
|
|
- } else {
|
|
|
|
-
|
|
|
|
- fmt.Println("收到数据:", string(data[:n]))
|
|
|
|
- msg := model.MessageModel{}
|
|
|
|
- err := json.Unmarshal(data[:n], &msg)
|
|
|
|
|
|
+ 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 {
|
|
if err != nil {
|
|
- log.Printf("转义错误:%s\n", err)
|
|
|
|
|
|
+ fmt.Println(err)
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
- //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)
|
|
|
|
|
|
+ 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 {
|
|
} else {
|
|
- fmt.Println("未知事件")
|
|
|
|
|
|
+ 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()
|
|
|
|
|
|
-// 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)
|
|
|
|
- }
|
|
|
|
- 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})
|
|
|
|
-
|
|
|
|
- tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
|
|
|
- if err != nil {
|
|
|
|
- panic(err)
|
|
|
|
- }
|
|
|
|
- // 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"},
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-//首次获取文件信息
|
|
|
|
-func (p *personService) GetFileList(uuid, path, to string) {
|
|
|
|
|
|
+//文件分片发送
|
|
|
|
+func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
|
|
|
|
+ summary := model.FileSummaryModel{}
|
|
|
|
|
|
msg := model.MessageModel{}
|
|
msg := model.MessageModel{}
|
|
- msg.Type = "file_list"
|
|
|
|
- msg.Data = path
|
|
|
|
- msg.To = to
|
|
|
|
|
|
+ msg.Type = types.PERSONSUMMARY
|
|
msg.From = config.ServerInfo.Token
|
|
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)
|
|
|
|
- // }
|
|
|
|
- // }
|
|
|
|
- //接收
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-//首次获取文件信息
|
|
|
|
-func (p *personService) GetFileDetail(uuid, path, to string) {
|
|
|
|
-
|
|
|
|
- msg := model.MessageModel{}
|
|
|
|
- msg.Type = "file_detail"
|
|
|
|
- msg.Data = path
|
|
|
|
msg.To = to
|
|
msg.To = to
|
|
- msg.From = config.ServerInfo.Token
|
|
|
|
msg.UUId = uuid
|
|
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)
|
|
|
|
-}
|
|
|
|
|
|
|
|
-func (p *personService) Download(m model.MessageModel) {
|
|
|
|
- fDetail, err := os.Stat("/Users/liangjianli/Documents/images")
|
|
|
|
- //发送需要发送的数据摘要
|
|
|
|
|
|
+ fStat, err := os.Stat(filePath)
|
|
if err != nil {
|
|
if err != nil {
|
|
- fmt.Println("未获取到文件信息")
|
|
|
|
- }
|
|
|
|
- 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)
|
|
|
|
|
|
+ summary.Message = err.Error()
|
|
|
|
|
|
- fmt.Println(b)
|
|
|
|
-
|
|
|
|
- // if ip, ok := PersonUDPMap[m.From]; ok {
|
|
|
|
- // _, err := UDPconn.WriteToUDP(b, ip)
|
|
|
|
- // if err != nil {
|
|
|
|
- // fmt.Println("写入错误", err)
|
|
|
|
- // }
|
|
|
|
- // }
|
|
|
|
-}
|
|
|
|
|
|
+ msg.Data = summary
|
|
|
|
|
|
-//receive file data
|
|
|
|
-func (p *personService) ReceiveFileData(m model.MessageModel) {
|
|
|
|
- task := p.GetDownloadById(m.UUId)
|
|
|
|
-
|
|
|
|
- //需要重置参数
|
|
|
|
- tempPath := "/oasis/download/" + task.UUID
|
|
|
|
- tempFilePath := tempPath + "/" + task.Name
|
|
|
|
- fmt.Println(tempFilePath)
|
|
|
|
- filePath := "/oasis/download/" + task.Name
|
|
|
|
-
|
|
|
|
- bss, _ := json.Marshal(m.Data)
|
|
|
|
- tran := model.TranFileModel{}
|
|
|
|
- err := json.Unmarshal(bss, &tran)
|
|
|
|
- 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
|
|
|
|
- })
|
|
|
|
- if err != nil {
|
|
|
|
- fmt.Println("获取文件错误", err)
|
|
|
|
- }
|
|
|
|
- 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)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ summaryByte, _ := json.Marshal(msg)
|
|
|
|
+ summaryPrefixLength := file.PrefixLength(len(summaryByte))
|
|
|
|
+ summaryData := append(summaryPrefixLength, summaryByte...)
|
|
|
|
+ stream.Write(summaryData)
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
-}
|
|
|
|
|
|
+ blockSize, length := file.GetBlockInfo(fStat.Size())
|
|
|
|
|
|
-//1:say hi
|
|
|
|
-//2:发送文件名称
|
|
|
|
-//3:发送数据
|
|
|
|
|
|
+ f, err := os.Open(filePath)
|
|
|
|
+ if err != nil {
|
|
|
|
|
|
-//========================================接收端============================================================================================
|
|
|
|
|
|
+ summary.Message = err.Error()
|
|
|
|
+ msg.Data = summary
|
|
|
|
|
|
-// 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)
|
|
|
|
|
|
+ summaryByte, _ := json.Marshal(msg)
|
|
|
|
+ summaryPrefixLength := file.PrefixLength(len(summaryByte))
|
|
|
|
+ summaryData := append(summaryPrefixLength, summaryByte...)
|
|
|
|
+ stream.Write(summaryData)
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
- 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"
|
|
|
|
|
|
+ //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
|
|
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)
|
|
|
|
-}
|
|
|
|
|
|
|
|
-func (p *personService) SendFileData(m model.MessageModel, blockSize int, length int) {
|
|
|
|
- path := m.Data.(string)
|
|
|
|
|
|
+ summaryByte, _ := json.Marshal(msg)
|
|
|
|
+ summaryPrefixLength := file.PrefixLength(len(summaryByte))
|
|
|
|
+ summaryData := append(summaryPrefixLength, summaryByte...)
|
|
|
|
+ stream.Write(summaryData)
|
|
|
|
|
|
- f, err := os.Open(path)
|
|
|
|
- if err != nil {
|
|
|
|
- //读取时移动了文件,需要保存数据到数据库
|
|
|
|
- fmt.Println("读取失败", err)
|
|
|
|
- }
|
|
|
|
|
|
+ bufferedReader := bufio.NewReader(f)
|
|
buf := make([]byte, blockSize)
|
|
buf := make([]byte, blockSize)
|
|
|
|
+
|
|
|
|
+ defer stream.Close()
|
|
|
|
+
|
|
for i := 0; i < length; i++ {
|
|
for i := 0; i < length; i++ {
|
|
|
|
+
|
|
tran := model.TranFileModel{}
|
|
tran := model.TranFileModel{}
|
|
- _, err := f.Read(buf)
|
|
|
|
|
|
+
|
|
|
|
+ n, err := bufferedReader.Read(buf)
|
|
|
|
+
|
|
if err == io.EOF {
|
|
if err == io.EOF {
|
|
fmt.Println("读取完毕", err)
|
|
fmt.Println("读取完毕", err)
|
|
}
|
|
}
|
|
- 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)
|
|
|
|
- }
|
|
|
|
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// 文件摘要返回
|
|
|
|
-func (p *personService) ReceiveGetFileDetail(m model.MessageModel) {
|
|
|
|
-
|
|
|
|
- task := p.GetDownloadById("")
|
|
|
|
- bss, _ := json.Marshal(m.Data)
|
|
|
|
- summary := model.FileSummaryModel{}
|
|
|
|
- err := json.Unmarshal(bss, &summary)
|
|
|
|
- if err != nil {
|
|
|
|
- fmt.Println(err)
|
|
|
|
- }
|
|
|
|
- task.Hash = summary.Hash
|
|
|
|
- task.Length = summary.Length
|
|
|
|
- task.Size = summary.Size
|
|
|
|
-
|
|
|
|
- p.SaveDownloadState(task)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func AsyncUDPConnect(dst *net.UDPAddr) {
|
|
|
|
- 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
|
|
|
|
- } else {
|
|
|
|
- fmt.Println(dst.IP)
|
|
|
|
- fmt.Println(dst.IP.To4())
|
|
|
|
|
|
+ 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)
|
|
}
|
|
}
|
|
-}
|
|
|
|
-func NewPersonService(db *gorm.DB) PersonService {
|
|
|
|
- return &personService{db: db}
|
|
|
|
|
|
+ return nil
|
|
}
|
|
}
|