From 9796c5aad7950b66c5a3861d8a225c91257a8379 Mon Sep 17 00:00:00 2001 From: link Date: Wed, 16 Mar 2022 15:41:14 +0800 Subject: [PATCH] prepare for test --- conf/conf.ini.sample | 4 + main.go | 12 +- model/person.go | 1 - model/sys_common.go | 6 + pkg/config/init.go | 3 + pkg/utils/file/block.go | 4 +- route/init.go | 17 ++- route/route.go | 9 +- route/v1/persion.go | 179 +++++++++++++++----------- service/download.go | 52 ++++++++ service/friend.go | 14 +++ service/model/o_download.go | 20 ++- service/model/o_friend.go | 4 +- service/person.go | 243 +++++++++++++----------------------- service/service.go | 6 + service/socket.go | 7 +- service/udpconn.go | 100 +++++++++++++-- 17 files changed, 412 insertions(+), 269 deletions(-) create mode 100644 service/download.go diff --git a/conf/conf.ini.sample b/conf/conf.ini.sample index fc99ddb..cb481e7 100644 --- a/conf/conf.ini.sample +++ b/conf/conf.ini.sample @@ -9,6 +9,7 @@ DateTimeFormat = 2006-01-02 15:04:05 TimeFormat = 15:04:05 DateFormat = 2006-01-02 ProjectPath = /casaOS/server +RootPath = /casaOS [server] @@ -44,3 +45,6 @@ ConfigStr = WidgetList = Analyse = +[file] +ShareDir = +DownloadDir = /DATA \ No newline at end of file diff --git a/main.go b/main.go index 1f0b53d..991922d 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "net/http" "time" + "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/sqlite" @@ -32,9 +33,14 @@ func init() { //gredis.GetRedisConn(config.RedisInfo), service.MyService = service.NewService(sqliteDB, loger2.NewOLoger()) service.Cache = cache.Init() - //go service.UDPConnect([]string{}) - go service.SocketConnect() - //go service.UDPService() + + go service.UDPService() + + go service.UDPConnect([]string{}) + service.Summary = make(map[string]model.FileSummaryModel) + service.UDPAddressMap = make(map[string]string) + //go service.SocketConnect() + route.InitFunction() } diff --git a/model/person.go b/model/person.go index cf39af1..2cc20d2 100644 --- a/model/person.go +++ b/model/person.go @@ -40,7 +40,6 @@ type FileDetailModel struct { type FileSummaryModel struct { Hash string `json:"hash"` //Verify file Name string `json:"name"` - Path string `json:"path"` BlockSize int `json:"block_size"` Length int `json:"length"` Size int64 `json:"size"` diff --git a/model/sys_common.go b/model/sys_common.go index 9301133..b02fa23 100644 --- a/model/sys_common.go +++ b/model/sys_common.go @@ -39,6 +39,7 @@ type APPModel struct { TimeFormat string DateFormat string ProjectPath string + RootPath string } //公共返回模型 @@ -76,3 +77,8 @@ type SystemConfig struct { type CasaOSGlobalVariables struct { AppChange bool } + +type FileSetting struct { + ShareDir []string `json:"share_dir" delim:"|"` + DownloadDir string `json:"download_dir"` +} diff --git a/pkg/config/init.go b/pkg/config/init.go index 9eb5052..5cb0df4 100644 --- a/pkg/config/init.go +++ b/pkg/config/init.go @@ -35,6 +35,8 @@ var SystemConfigInfo = &model.SystemConfig{} var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{} +var FileSettingInfo = &model.FileSetting{} + var Cfg *ini.File //初始化设置,获取系统的部分信息。 @@ -58,6 +60,7 @@ func InitSetup(config string) { mapTo("redis", RedisInfo) mapTo("server", ServerInfo) mapTo("system", SystemConfigInfo) + mapTo("file", FileSettingInfo) SystemConfigInfo.ConfigPath = configDir // AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd() diff --git a/pkg/utils/file/block.go b/pkg/utils/file/block.go index bbe568c..c02950e 100644 --- a/pkg/utils/file/block.go +++ b/pkg/utils/file/block.go @@ -60,9 +60,9 @@ func ComparisonHash(data []byte, hash string) bool { //get prefix byte length func PrefixLength(byteLength int) []byte { - lengthByte := []byte{'0', '0', '0', '0'} + lengthByte := []byte{'0', '0', '0', '0', '0', '0'} bSize := strconv.Itoa(byteLength) - cha := 4 - len(bSize) + cha := 6 - len(bSize) for i := len(bSize); i > 0; i-- { lengthByte[cha+i-1] = bSize[i-1] } diff --git a/route/init.go b/route/init.go index e18c0f6..d8b1f0e 100644 --- a/route/init.go +++ b/route/init.go @@ -25,7 +25,7 @@ func InitFunction() { Update2_3() CheckSerialDiskMount() - CheckToken2_9() + CheckToken2_11() } @@ -236,11 +236,24 @@ func CheckSerialDiskMount() { func Update2_3() { command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh") } -func CheckToken2_9() { +func CheckToken2_11() { if len(config.ServerInfo.Token) == 0 { token := uuid.NewV4().String config.ServerInfo.Token = token() config.Cfg.Section("server").Key("Token").SetValue(token()) config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) } + if len(config.AppInfo.RootPath) == 0 { + config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS") + config.AppInfo.RootPath = "/casaOS" + config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) + } + // str := []string{} + // str = append(str, "ddd") + // str = append(str, "aaa") + // ddd := strings.Join(str, "|") + // config.Cfg.Section("file").Key("ShareDir").SetValue(ddd) + + // config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) + } diff --git a/route/route.go b/route/route.go index 0bdb20f..b7380a3 100644 --- a/route/route.go +++ b/route/route.go @@ -290,13 +290,14 @@ func InitRouter() *gin.Engine { v1PersonGroup := v1Group.Group("/persion") v1PersonGroup.Use() { - // v1PersonGroup.GET("/test", v1.PersonTest) + v1PersonGroup.GET("/test", v1.PersonTest) v1PersonGroup.GET("/users", v1.GetPersionFriend) //用户列表 v1PersonGroup.POST("/user", v1.PostAddPersionFriend) //添加用户 v1PersonGroup.GET("/directory", v1.GetPersionDirectory) //文件列表 - //v1PersonGroup.GET("/download", v1.GetPersionFile) //下载文件 - v1PersonGroup.PUT("/edit/:token", v1.PutPersionNick) //修改好友 - v1PersonGroup.GET("/list", v1.GetPersionDownloadList) //下载列表(需要考虑试试下载速度) + v1PersonGroup.GET("/file", v1.GetPersionFile) //下载文件 + v1PersonGroup.PUT("/edit/:token", v1.PutPersionNick) //修改好友 + v1PersonGroup.GET("/list", v1.GetPersionDownloadList) //下载列表(需要考虑试试下载速度) + v1PersonGroup.DELETE("/file/id", v1.DeletePersionDownloadFile) // v1PersonGroup.PUT("/state/:id", v1.PutPersionCancelDownload) //修改下载状态(开始暂停删除) } diff --git a/route/v1/persion.go b/route/v1/persion.go index d44f556..018cd46 100644 --- a/route/v1/persion.go +++ b/route/v1/persion.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "time" "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/config" @@ -13,75 +12,26 @@ import ( model2 "github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/types" "github.com/gin-gonic/gin" - "github.com/gorilla/websocket" uuid "github.com/satori/go.uuid" ) func PersonTest(c *gin.Context) { + token := c.Query("token") //service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9") - m := model.ConnectState{} - m.CreatedAt = time.Now() - m.From = config.ServerInfo.Token - m.To = "fb2333a1-72b2-4cb4-9e31-61ccaffa55b9" - m.Type = "" - m.UUId = uuid.NewV4().String() - - //service.MyService.Person().Handshake(m) msg := model.MessageModel{} - msg.Type = "connection" - msg.Data = "fb2333a1-72b2-4cb4-9e31-61ccaffa55b9" + msg.Type = "hello" + msg.Data = "" msg.From = config.ServerInfo.Token - msg.UUId = "1234567890" - b, _ := json.Marshal(msg) - err := service.WebSocketConn.WriteMessage(websocket.TextMessage, b) + msg.To = token + msg.UUId = uuid.NewV4().String() + + dd, err := service.Dial("", msg) if err == nil { - return + fmt.Println(err) } -} - -//get other persion file -func GetPersionFile(c *gin.Context) { - path := c.Query("path") - persion := c.Query("persion") - if len(path) == 0 && len(persion) == 0 { - c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) - return - } - //任务标识 - uuid := uuid.NewV4().String() - - //1.通知对方需要下载 - service.MyService.Person().GetFileDetail(uuid, path, persion) - - //2.添加数据库 - - task := model2.PersionDownloadDBModel{} - task.UUID = uuid - task.Name = "" - task.Length = 0 - task.Size = 0 - task.State = types.DOWNLOADAWAIT - task.TempPath = "" - task.Type = 0 - service.MyService.Person().AddDownloadTask(task) - - c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) -} -func GetPersionDownloadList(c *gin.Context) { - path := c.Query("path") - persion := c.Query("persion") - if len(path) == 0 && len(persion) == 0 { - c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) - return - } - //任务标识 - uuid := uuid.NewV4().String() - - //1.通知对方需要下载 - service.MyService.Person().GetFileDetail(uuid, path, persion) - + fmt.Println(dd) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) } @@ -92,7 +42,87 @@ func GetPersionDownloadList(c *gin.Context) { // @Param token formData int true "Opponent token" // @Security ApiKeyAuth // @Success 200 {string} string "ok" -// @Router /persion/edit [put] +// @Router /persion/file/{id} [delete] +func GetPersionFile(c *gin.Context) { + + path := c.Query("path") + token := c.Query("token") + if len(path) == 0 && len(token) == 0 { + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) + return + } + //任务标识 + uuid := uuid.NewV4().String() + + //2.添加数据库 + + task := model2.PersionDownloadDBModel{} + task.UUID = uuid + task.Name = "" + task.Length = 0 + task.Size = 0 + task.State = types.DOWNLOADAWAIT + task.Type = 0 + service.MyService.Download().AddDownloadTask(task) + + m := model.MessageModel{} + m.Data = path + m.From = config.ServerInfo.Token + m.To = token + m.Type = "file_data" + m.UUId = uuid + _, err := service.Dial("192.168.2.224:9902", m) + if err != nil { + fmt.Println(err) + } + + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) +} + +// @Summary delete download file records +// @Produce application/json +// @Accept application/json +// @Tags persion +// @Param token formData int true "Opponent token" +// @Security ApiKeyAuth +// @Success 200 {string} string "ok" +// @Router /persion/file/{id} [delete] +func DeletePersionDownloadFile(c *gin.Context) { + + id := c.Param("id") + if len(id) == 0 { + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) + return + } + + service.MyService.Download().DelDownload(id) + + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) +} + +// @Summary get file download list +// @Produce application/json +// @Accept application/json +// @Tags persion +// @Param state query int true "wait:1,loading:1,pause:2,finish:3,error:4" Enums(0,1,2,4) +// @Security ApiKeyAuth +// @Success 200 {string} string "ok" +// @Router /persion/list [get] +func GetPersionDownloadList(c *gin.Context) { + state := c.DefaultQuery("state", "") + list := service.MyService.Download().GetDownloadListByState(state) + + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list}) +} + +// @Summary add friend +// @Produce application/json +// @Accept application/json +// @Tags persion +// @Param token formData int true "Opponent token" +// @Security ApiKeyAuth +// @Success 200 {string} string "ok" +// @Router /persion/edit/{token} [put] func PutPersionNick(c *gin.Context) { token := c.Param("token") nick := c.PostForm("nick") @@ -107,7 +137,7 @@ func PutPersionNick(c *gin.Context) { c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) } -// @Summary add friend +// @Summary get friends list // @Produce application/json // @Accept application/json // @Tags persion @@ -134,15 +164,16 @@ func PostAddPersionFriend(c *gin.Context) { c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) return } - //step:远程验证token是否存在 + msg := model.MessageModel{} - msg.Type = types.PERSONADDFRIEND - msg.To = token + msg.Type = "connection" msg.Data = token msg.From = config.ServerInfo.Token + msg.To = token msg.UUId = uuid.NewV4().String() - b, _ := json.Marshal(msg) - err := service.WebSocketConn.WriteMessage(websocket.TextMessage, b) + + _, err := service.Dial("", msg) + fmt.Println(err) friend := model2.FriendModel{} @@ -151,10 +182,18 @@ func PostAddPersionFriend(c *gin.Context) { c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) } +// @Summary get directory list +// @Produce application/json +// @Accept application/json +// @Tags persion +// @Param token query int true "Opponent token" +// @Security ApiKeyAuth +// @Success 200 {string} string "ok" +// @Router /persion/directory [get] func GetPersionDirectory(c *gin.Context) { path := c.Query("path") - persion := c.Query("persion") - if len(path) == 0 && len(persion) == 0 { + token := c.Query("token") + if len(path) == 0 && len(token) == 0 { c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) return } @@ -163,10 +202,10 @@ func GetPersionDirectory(c *gin.Context) { m := model.MessageModel{} m.Data = path m.From = config.ServerInfo.Token - m.To = persion + m.To = token m.Type = "directory" m.UUId = uuid - result, err := service.Dial("192.168.2.225:9902", m) + result, err := service.Dial(service.UDPAddressMap[token], m) if err != nil { fmt.Println(err) } diff --git a/service/download.go b/service/download.go new file mode 100644 index 0000000..1b24ff6 --- /dev/null +++ b/service/download.go @@ -0,0 +1,52 @@ +package service + +import ( + model2 "github.com/IceWhaleTech/CasaOS/service/model" + "gorm.io/gorm" +) + +type DownloadService interface { + AddDownloadTask(m model2.PersionDownloadDBModel) //添加下载任务 + EditDownloadState(m model2.PersionDownloadDBModel) //只修改状态 + SaveDownload(m model2.PersionDownloadDBModel) + DelDownload(uuid string) + GetDownloadById(uuid string) model2.PersionDownloadDBModel + GetDownloadListByState(state string) []model2.PersionDownloadDBModel +} +type downloadService struct { + db *gorm.DB +} + +func (d *downloadService) AddDownloadTask(m model2.PersionDownloadDBModel) { + d.db.Create(&m) +} +func (d *downloadService) EditDownloadState(m model2.PersionDownloadDBModel) { + d.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State) +} + +func (d *downloadService) DelDownload(uuid string) { + var m model2.PersionDownloadDBModel + d.db.Where("uuid = ?", uuid).Delete(&m) +} +func (d *downloadService) GetDownloadById(uuid string) model2.PersionDownloadDBModel { + var m model2.PersionDownloadDBModel + d.db.Model(m).Where("uuid = ?", uuid).First(&m) + return m +} +func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersionDownloadDBModel) { + if len(state) == 0 { + d.db.Find(&list) + + } else { + d.db.Where("state = ?", state).Find(&list) + } + + return +} + +func (d *downloadService) SaveDownload(m model2.PersionDownloadDBModel) { + d.db.Save(&m) +} +func NewDownloadService(db *gorm.DB) DownloadService { + return &downloadService{db: db} +} diff --git a/service/friend.go b/service/friend.go index 16a23b4..7a19ff0 100644 --- a/service/friend.go +++ b/service/friend.go @@ -1,6 +1,8 @@ package service import ( + "reflect" + model2 "github.com/IceWhaleTech/CasaOS/service/model" "gorm.io/gorm" ) @@ -12,6 +14,7 @@ type FriendService interface { GetFriendById(m model2.FriendModel) model2.FriendModel GetFriendList() (list []model2.FriendModel) UpdateAddFriendType(m model2.FriendModel) + UpdateOrCreate(m model2.FriendModel) } type friendService struct { @@ -38,6 +41,17 @@ func (p *friendService) GetFriendList() (list []model2.FriendModel) { return list } +func (p *friendService) UpdateOrCreate(m model2.FriendModel) { + friend := model2.FriendModel{} + p.db.Where("token = ?", m.Token).First(&friend) + if reflect.DeepEqual(friend, model2.FriendModel{}) { + p.db.Create(&m) + } else { + p.db.Model(&m).Updates(m) + } + +} + func (p *friendService) UpdateAddFriendType(m model2.FriendModel) { p.db.Model(&m).Updates(m) } diff --git a/service/model/o_download.go b/service/model/o_download.go index d88d103..fa60bce 100644 --- a/service/model/o_download.go +++ b/service/model/o_download.go @@ -2,23 +2,17 @@ package model type PersionDownloadDBModel struct { UUID string `gorm:"column:uuid;primary_key" json:"uuid"` - State int `json:"state"` // - Type int `json:"type"` //defult 1 - Name string `json:"name"` //file name - TempPath string `json:"temp_path"` //temp path - Size int64 `json:"size"` //file size - Section string `json:"section"` + State int `json:"state"` // + Type int `json:"type"` //defult 1 + Name string `json:"name"` //file name + Size int64 `json:"size"` //file size + BlockSize int `json:"block_size"` Length int `json:"length"` //slice length Hash string `json:"hash"` - CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"` - UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"` + UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"` } func (p *PersionDownloadDBModel) TableName() string { return "o_persion_download" } - -type PersionFileSectionModel struct { - Index int `json:"index"` - Hash string `json:"hash"` -} diff --git a/service/model/o_friend.go b/service/model/o_friend.go index ff36e9d..c48c92e 100644 --- a/service/model/o_friend.go +++ b/service/model/o_friend.go @@ -2,8 +2,8 @@ package model type FriendModel struct { State int `json:"state"` //备用 - CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"` - UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"` + CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"` + UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"` NickName string `json:"nick_name"` //custom name Avatar string `json:"avatar"` //头像 Name string `json:"name"` diff --git a/service/person.go b/service/person.go index 352ae5d..8829d22 100644 --- a/service/person.go +++ b/service/person.go @@ -40,14 +40,6 @@ type PersonService interface { 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 { @@ -81,7 +73,7 @@ func (p *personService) Handshake(m model.ConnectState) { //1先进行udp打通成功 srcAddr := &net.UDPAddr{ - IP: net.IPv4zero, Port: 9901} //注意端口必须固定 + IP: net.IPv4zero, Port: 9904} //注意端口必须固定 dstAddr := &net.UDPAddr{ IP: net.ParseIP(config.ServerInfo.Handshake), Port: 9527} //DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。 @@ -101,7 +93,6 @@ func (p *personService) Handshake(m model.ConnectState) { if err != nil { fmt.Printf("error during read: %s", err) } - conn.Close() toPersion := model.PersionModel{} err = json.Unmarshal(data[:n], &toPersion) if err != nil { @@ -116,33 +107,6 @@ func (p *personService) Handshake(m model.ConnectState) { } -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 type sysConn struct { @@ -152,104 +116,11 @@ type sysConn struct { } 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) - 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) - } + //m := model.ConnectState{} - if err != nil { - fmt.Println("监听错误", err.Error()) - } - for _, v := range ips { - dstAddr := &net.UDPAddr{ - IP: net.ParseIP(v), Port: 9901} + //MyService.Person().Handshake(m) - fmt.Println(v, "开始监听") - - //quic.Dial() - - go AsyncUDPConnect(dstAddr) - } - - for { - data := make([]byte, 1024) - n, add, err := UDPconn.ReadFromUDP(data) - fmt.Println(add) - 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) - 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("未知事件") - } - - } - } } // Setup a bare-bones TLS config for the server @@ -327,7 +198,6 @@ func (p *personService) Download(m model.MessageModel) { } 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{} @@ -349,7 +219,8 @@ func (p *personService) Download(m model.MessageModel) { //receive file data func (p *personService) ReceiveFileData(m model.MessageModel) { - task := p.GetDownloadById(m.UUId) + //task := p.GetDownloadById(m.UUId) + task := model2.PersionDownloadDBModel{} //需要重置参数 tempPath := "/oasis/download/" + task.UUID @@ -391,7 +262,7 @@ func (p *personService) ReceiveFileData(m model.MessageModel) { if h := file.GetHashByPath(filePath); h == task.Hash { //最终文件比对成功 task.State = types.DOWNLOADFINISH - p.EditDownloadState(task) + //p.EditDownloadState(task) //remove temp path file.RMDir(tempPath) } @@ -417,7 +288,6 @@ func (p *personService) ReplyGetFileDetail(m model.MessageModel) { 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{} @@ -477,24 +347,24 @@ func (p *personService) SendFileData(m model.MessageModel, blockSize int, length // 文件摘要返回 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 + // 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) + // 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 { + if _, err := UDPConn.WriteToUDP([]byte(dst.IP.String()+" is ok"), dst); err != nil { log.Println("send msg fail", err) return } else { @@ -518,9 +388,13 @@ func UDPService() { KeepAlive: true, } srcAddr := &net.UDPAddr{ - IP: net.IPv4zero, Port: 9902} //注意端口必须固定 - fmt.Println(srcAddr.String()) - listener, err := quic.ListenAddr(srcAddr.String(), generateTLSConfig(), quicConfig) + IP: net.IPv4zero, Port: 9904} //注意端口必须固定 + var err error + UDPConn, err = net.ListenUDP("udp", srcAddr) + if err != nil { + fmt.Println(err) + } + listener, err := quic.Listen(UDPConn, generateTLSConfig(), quicConfig) if err != nil { fmt.Println(err) } @@ -531,6 +405,7 @@ func UDPService() { if err != nil { panic(err) } + for { select { case <-ctx.Done(): @@ -590,10 +465,8 @@ func UDPService() { //处理内容 func ProcessingContent(stream quic.Stream) { - //需要处理关闭问题 - for { - prefixByte := make([]byte, 4) + prefixByte := make([]byte, 6) c1, err := io.ReadFull(stream, prefixByte) fmt.Println(c1) if err != nil { @@ -619,13 +492,22 @@ func ProcessingContent(stream quic.Stream) { //什么也不做 continue } else if m.Type == "directory" { - list := MyService.ZiMa().GetDirPath(m.Data.(string)) + var list []model.Path + if m.Data.(string) == "" || m.Data.(string) == "/" { + for _, v := range config.FileSettingInfo.ShareDir { + tempList := MyService.ZiMa().GetDirPath(v) + list = append(list, tempList...) + } + } else { + list = MyService.ZiMa().GetDirPath(m.Data.(string)) + } m.To = m.From m.Data = list m.From = config.ServerInfo.Token SendData(stream, m) break } else if m.Type == "file_data" { + SendFileData(stream, m.Data.(string), m.From, m.UUId) break } else if m.Type == types.PERSONADDFRIEND { @@ -636,7 +518,7 @@ func ProcessingContent(stream quic.Stream) { fmt.Println(err) continue } - go MyService.Friend().UpdateAddFriendType(friend) + go MyService.Friend().UpdateOrCreate(friend) mi := model2.FriendModel{} mi.Avatar = config.UserInfo.Avatar mi.Profile = config.UserInfo.Description @@ -647,6 +529,23 @@ func ProcessingContent(stream quic.Stream) { m.From = config.ServerInfo.Token SendData(stream, m) + break + } else if m.Type == "connection" { + UDPAddressMap[m.From] = m.Data.(string) + fmt.Println("persion", m) + mi := model2.FriendModel{} + mi.Avatar = config.UserInfo.Avatar + mi.Profile = config.UserInfo.Description + mi.Name = config.UserInfo.UserName + 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 + Dial(m.Data.(string), msg) + break } else { //不应有不做返回的数据 @@ -673,20 +572,43 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error { fmt.Println("读取失败", err) return err } + + //先发送文件摘要 + + summary := model.FileSummaryModel{} + summary.BlockSize = blockSize + summary.Hash = file.GetHashByPath(filePath) + summary.Length = length + summary.Name = fStat.Name() + summary.Size = fStat.Size() + + msg := model.MessageModel{} + msg.Type = "summary" + msg.Data = summary + msg.From = config.ServerInfo.Token + msg.To = to + msg.UUId = uuid + + summaryByte, _ := json.Marshal(msg) + summaryPrefixLength := file.PrefixLength(len(summaryByte)) + summaryData := append(summaryPrefixLength, summaryByte...) + stream.Write(summaryData) + bufferedReader := bufio.NewReader(f) buf := make([]byte, blockSize) for i := 0; i < length; i++ { tran := model.TranFileModel{} - _, err = bufferedReader.Read(buf) + n, err := bufferedReader.Read(buf) if err == io.EOF { fmt.Println("读取完毕", err) } - tran.Hash = file.GetHashByContent(buf) + tran.Hash = file.GetHashByContent(buf[:n]) tran.Index = i + tran.Length = length msg := model.MessageModel{} msg.Type = "file_data" @@ -695,7 +617,10 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error { msg.To = to msg.UUId = uuid b, _ := json.Marshal(msg) - stream.Write(b) + prefixLength := file.PrefixLength(len(b)) + dataLength := file.DataLength(len(buf[:n])) + data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...) + stream.Write(data) } defer stream.Close() return nil diff --git a/service/service.go b/service/service.go index c40da69..c72a91c 100644 --- a/service/service.go +++ b/service/service.go @@ -34,6 +34,7 @@ type Repository interface { Search() SearchService Person() PersonService Friend() FriendService + Download() DownloadService } func NewService(db *gorm.DB, log loger2.OLog) Repository { @@ -57,6 +58,7 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository { search: NewSearchService(), person: NewPersonService(db), friend: NewFriendService(db), + download: NewDownloadService(db), } } @@ -79,8 +81,12 @@ type store struct { search SearchService person PersonService friend FriendService + download DownloadService } +func (c *store) Download() DownloadService { + return c.download +} func (c *store) Friend() FriendService { return c.friend } diff --git a/service/socket.go b/service/socket.go index ff44464..3863792 100644 --- a/service/socket.go +++ b/service/socket.go @@ -5,7 +5,6 @@ import ( "fmt" "net/url" "reflect" - "strings" "time" "github.com/IceWhaleTech/CasaOS/model" @@ -53,7 +52,7 @@ func SocketConnect() { m.To = msa.From m.Type = types.PERSONADDFRIEND m.UUId = uuid - result, err := Dial("192.168.2.225:9902", m) + result, err := Dial("192.168.2.224:9902", m) friend := model2.FriendModel{} if err != nil && !reflect.DeepEqual(result, friend) { dataModelByte, _ := json.Marshal(result.Data) @@ -91,14 +90,14 @@ func SocketConnect() { } func Connect() { - host := strings.Split(config.ServerInfo.Handshake, "://") - u := url.URL{Scheme: "ws", Host: host[1], Path: "/v1/ws"} + u := url.URL{Scheme: "ws", Host: config.ServerInfo.Handshake + ":8088", Path: "/v1/ws"} for { d, _, e := websocket.DefaultDialer.Dial(u.String(), nil) if e == nil { WebSocketConn = d return } + fmt.Println(e) time.Sleep(time.Second * 5) } } diff --git a/service/udpconn.go b/service/udpconn.go index dca32e2..c7c4395 100644 --- a/service/udpconn.go +++ b/service/udpconn.go @@ -10,19 +10,23 @@ import ( "io" "io/ioutil" "net" + "os" "strconv" "time" "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/config" "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 UDPConn *net.UDPConn var PeopleMap map[string]quic.Stream var Message chan model.MessageModel +var UDPAddressMap map[string]string func Dial(addr string, msg model.MessageModel) (m model.MessageModel, err error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -37,8 +41,18 @@ func Dial(addr string, msg model.MessageModel) (m model.MessageModel, err error) NextProtos: []string{"bench"}, SessionTicketsDisabled: true, } + srcAddr := &net.UDPAddr{ + IP: net.IPv4zero, Port: 9904} //注意端口必须固定 + //addr + if len(addr) == 0 { + addr = config.ServerInfo.Handshake + ":9527" + } + dstAddr, err := net.ResolveUDPAddr("udp", addr) - session, err := quic.DialAddrContext(ctx, addr, tlsConf, quicConfig) + //DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。 + //(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口 + + session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), tlsConf, quicConfig) if err != nil { return m, err } @@ -79,11 +93,12 @@ func SendData(stream quic.Stream, m model.MessageModel) { stream.Write(data) } +var Summary map[string]model.FileSummaryModel + //读取数据 func ReadContent(stream quic.Stream) { - path := "" for { - prefixByte := make([]byte, 4) + prefixByte := make([]byte, 6) c1, err := io.ReadFull(stream, prefixByte) fmt.Println(c1, err, string(prefixByte)) prefixLength, err := strconv.Atoi(string(prefixByte)) @@ -96,7 +111,7 @@ func ReadContent(stream quic.Stream) { if err != nil { fmt.Println(err) } - + fmt.Println(m) //传输数据需要继续读取 if m.Type == "file_data" { dataModelByte, _ := json.Marshal(m.Data) @@ -121,13 +136,80 @@ func ReadContent(stream quic.Stream) { fmt.Println("hash不匹配", hash, dataModel.Hash) } - filepath := path + strconv.Itoa(dataModel.Index) + 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) + } else { + if file.GetHashByPath(filepath) != dataModel.Hash { + os.Remove(filepath) + err = ioutil.WriteFile(filepath, dataByte, 0644) + } + } + + files, err := ioutil.ReadDir(tempPath) + + 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) + } else { + os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name) + task := model2.PersionDownloadDBModel{} + task.UUID = m.UUId + task.State = types.DOWNLOADERROR + MyService.Download().EditDownloadState(task) + } - err = ioutil.WriteFile(filepath, dataByte, 0644) - if dataModel.Index >= (dataModel.Length - 1) { - //file.SpliceFiles("", path, dataModel.Length) break } + } else if m.Type == "summary" { + + dataModel := model.FileSummaryModel{} + if m.UUId == m.UUId { + 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 + MyService.Download().SaveDownload(task) + + Summary[m.UUId] = dataModel + + } else if m.Type == "connection" { + UDPAddressMap[m.From] = m.Data.(string) + fmt.Println("udpconn", m) + mi := model2.FriendModel{} + mi.Avatar = config.UserInfo.Avatar + mi.Profile = config.UserInfo.Description + mi.Name = config.UserInfo.UserName + 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 + Dial(m.Data.(string), msg) + Message <- m + break } else { Message <- m }