完成了分享下载全部流程
This commit is contained in:
+1
-1
@@ -24,7 +24,7 @@ var T = Config{
|
||||
Avatar: "./data/avatar",
|
||||
ZeroconfKey: "work_cations_service",
|
||||
ZeroconfPort: 16800,
|
||||
ServerAddr: ":16800",
|
||||
ServerAddr: ":16801",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"work_cation/assets"
|
||||
"work_cation/global"
|
||||
"work_cation/service"
|
||||
"work_cation/version"
|
||||
"work_cation/views"
|
||||
)
|
||||
@@ -33,6 +34,7 @@ func main() {
|
||||
|
||||
// 主界面
|
||||
func mainView(w fyne.Window) fyne.CanvasObject {
|
||||
service.Zeroconf.StartFindService()
|
||||
var (
|
||||
content = container.NewMax()
|
||||
a = fyne.CurrentApp()
|
||||
|
||||
+6
-4
@@ -5,37 +5,39 @@ import (
|
||||
"fmt"
|
||||
"github.com/grandcat/zeroconf"
|
||||
"net"
|
||||
"work_cation/cfg"
|
||||
)
|
||||
|
||||
// Online 在线数据
|
||||
type Online struct {
|
||||
AddrIPv4 []net.IP `json:"-"` // Host machine IPv4 address
|
||||
AddrIPv6 []net.IP `json:"-"`
|
||||
Port int `json:"port"`
|
||||
Port string `json:"port"`
|
||||
ID string `json:"id"`
|
||||
Ip string `json:"ip"`
|
||||
}
|
||||
|
||||
func (o *Online) Url(router string) string {
|
||||
return fmt.Sprintf("http://%s:%d%s", o.Ip, o.Port, router)
|
||||
return fmt.Sprintf("http://%s%s%s", o.Ip, o.Port, router)
|
||||
}
|
||||
|
||||
func UserTOnlineList(user *Users) []string {
|
||||
return []string{
|
||||
user.ID,
|
||||
user.Ip,
|
||||
cfg.T.ServerAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func NewOnline(entry *zeroconf.ServiceEntry) (*Online, error) {
|
||||
if len(entry.Text) != 2 {
|
||||
if len(entry.Text) != 3 {
|
||||
return nil, errors.New("invalid online entry")
|
||||
}
|
||||
|
||||
return &Online{
|
||||
AddrIPv4: entry.AddrIPv4,
|
||||
AddrIPv6: entry.AddrIPv6,
|
||||
Port: entry.Port,
|
||||
Port: entry.Text[2],
|
||||
ID: entry.Text[0],
|
||||
Ip: entry.Text[1],
|
||||
}, nil
|
||||
|
||||
+14
-1
@@ -15,6 +15,19 @@ func (*baseCardRepo) FindAll(db *gorm.DB) []models.BaseCard {
|
||||
return cards
|
||||
}
|
||||
|
||||
func (*baseCardRepo) Create(db *gorm.DB, baseCard *models.BaseCard) error {
|
||||
func (*baseCardRepo) Find(db *gorm.DB, uuid string) models.BaseCard {
|
||||
var card models.BaseCard
|
||||
db.Where("uuid = ?", uuid).Find(&card)
|
||||
return card
|
||||
}
|
||||
|
||||
func (*baseCardRepo) CreateOrSave(db *gorm.DB, baseCard *models.BaseCard) error {
|
||||
var card models.BaseCard
|
||||
if err := db.Where("uuid = ?", baseCard.UUID).Find(&card).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if card.UUID != "" {
|
||||
return db.Where("uuid = ?", baseCard.UUID).Save(baseCard).Error
|
||||
}
|
||||
return db.Create(baseCard).Error
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type BaseCardService struct{}
|
||||
var BaseCard = &BaseCardService{}
|
||||
|
||||
func (*BaseCardService) Create(db *gorm.DB, baseCard models.BaseCard) {
|
||||
repo.BaseCard.Create(db, &baseCard)
|
||||
repo.BaseCard.CreateOrSave(db, &baseCard)
|
||||
}
|
||||
|
||||
func (*BaseCardService) Update(db *gorm.DB, updateCard models.BaseCard) {
|
||||
|
||||
+145
-1
@@ -1,9 +1,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
"work_cation/cfg"
|
||||
"work_cation/models"
|
||||
)
|
||||
|
||||
@@ -14,7 +22,13 @@ var Client = &ClientService{}
|
||||
|
||||
func (c *ClientService) GetUser(online *models.Online) (*models.Users, error) {
|
||||
var user models.Users
|
||||
resp, err := http.Get(online.Url("/user"))
|
||||
ctx, carnal := context.WithTimeout(context.TODO(), time.Millisecond*500)
|
||||
defer carnal()
|
||||
res, err := http.NewRequestWithContext(ctx, "", online.Url("/user"), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -29,3 +43,133 @@ func (c *ClientService) GetUser(online *models.Online) (*models.Users, error) {
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (c *ClientService) GetCards(online *models.Online) ([]models.BaseCard, error) {
|
||||
var cards []models.BaseCard
|
||||
ctx, carnal := context.WithTimeout(context.TODO(), time.Millisecond*500)
|
||||
defer carnal()
|
||||
res, err := http.NewRequestWithContext(ctx, "", online.Url("/cards"), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(data, &cards)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cards, nil
|
||||
}
|
||||
|
||||
func (c *ClientService) Download(online *models.Online, uuid string, progress binding.Float) error {
|
||||
|
||||
resp, err := http.Get(online.Url("/download/card/" + uuid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
downloadFile := filepath.Join(cfg.T.CardDir, fmt.Sprintf("%s.zip", uuid))
|
||||
_, err = os.Stat(downloadFile)
|
||||
if err == nil {
|
||||
os.Remove(downloadFile)
|
||||
}
|
||||
|
||||
file, err := os.Create(downloadFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
r := Rr{
|
||||
file: file,
|
||||
tot: resp.ContentLength,
|
||||
progress: 0,
|
||||
oneUp: 0,
|
||||
progressBind: progress,
|
||||
}
|
||||
|
||||
_, err = io.Copy(&r, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 解压
|
||||
destDir := filepath.Join(cfg.T.CardDir, uuid)
|
||||
_ = os.RemoveAll(destDir)
|
||||
if err = unzipFile(downloadFile, destDir); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(downloadFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Rr struct {
|
||||
file *os.File
|
||||
tot int64
|
||||
progress int64
|
||||
|
||||
oneUp int
|
||||
progressBind binding.Float
|
||||
}
|
||||
|
||||
func (r *Rr) Write(p []byte) (n int, err error) {
|
||||
n, err = r.file.Write(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r.progress += int64(n)
|
||||
|
||||
nowUp := int(r.progress * 100 / r.tot)
|
||||
if nowUp != r.oneUp {
|
||||
r.progressBind.Set(float64(nowUp))
|
||||
r.oneUp = nowUp
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unzipFile(zipFile, destDir string) error {
|
||||
// 打开ZIP文件
|
||||
r, err := zip.OpenReader(zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
// 创建目标目录
|
||||
err = os.MkdirAll(destDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 遍历ZIP文件中的文件并解压缩到目标目录
|
||||
for _, f := range r.File {
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 创建文件
|
||||
path := filepath.Join(destDir, f.Name)
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(path, os.ModePerm)
|
||||
} else {
|
||||
// 创建文件
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(file, rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
rc.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (*erlangCardService) Create(erlangCard *models.ErlangCards) error {
|
||||
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||
var baseCard = erlangCard.BaseCard
|
||||
|
||||
err = repo.BaseCard.Create(global.DB, &baseCard)
|
||||
err = repo.BaseCard.CreateOrSave(global.DB, &baseCard)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,6 +49,6 @@ func (*ExecFileService) Create(info *models.ExecFiles, chooseDir string) error {
|
||||
}
|
||||
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||
var baseCard = info.BaseCard
|
||||
return repo.BaseCard.Create(tx, &baseCard)
|
||||
return repo.BaseCard.CreateOrSave(tx, &baseCard)
|
||||
})
|
||||
}
|
||||
|
||||
+80
-1
@@ -1,10 +1,15 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"work_cation/cfg"
|
||||
"work_cation/global"
|
||||
"work_cation/repo"
|
||||
@@ -52,11 +57,35 @@ func (s *serverService) StatusOffline() error {
|
||||
}
|
||||
|
||||
func (s *serverService) StartListenServer() error {
|
||||
router := gin.New()
|
||||
router := gin.Default()
|
||||
router.GET("/user", func(c *gin.Context) {
|
||||
user := repo.User.GetUserInfo(global.DB)
|
||||
c.JSON(200, user)
|
||||
})
|
||||
router.GET("/cards", func(c *gin.Context) {
|
||||
cards := repo.BaseCard.FindAll(global.DB)
|
||||
c.JSON(200, cards)
|
||||
})
|
||||
router.GET("/download/card/:uuid", func(c *gin.Context) {
|
||||
uuid := c.Param("uuid")
|
||||
card := repo.BaseCard.Find(global.DB, uuid)
|
||||
fmt.Println("card:", card)
|
||||
if card.UUID == "" {
|
||||
c.JSON(404, nil)
|
||||
return
|
||||
}
|
||||
cardPath := filepath.Join(cfg.T.CardDir, card.UUID)
|
||||
|
||||
// 设置响应头
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s.zip", uuid))
|
||||
c.Header("Content-Type", "application/zip")
|
||||
|
||||
err := zipFolder(cardPath, c.Writer)
|
||||
if err != nil {
|
||||
c.JSON(500, err)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.T.ServerAddr,
|
||||
@@ -71,3 +100,53 @@ func (s *serverService) StartListenServer() error {
|
||||
s.server = srv
|
||||
return nil
|
||||
}
|
||||
|
||||
func zipFolder(folderPath string, zipFile io.Writer) error {
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
defer zipWriter.Close()
|
||||
err := filepath.Walk(folderPath, func(filePath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.Name, err = filepath.Rel(folderPath, filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
}
|
||||
|
||||
writer, err := zipWriter.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(writer, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+16
-15
@@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/grandcat/zeroconf"
|
||||
"time"
|
||||
"slices"
|
||||
"work_cation/cfg"
|
||||
"work_cation/models"
|
||||
)
|
||||
|
||||
type zeroconfService struct {
|
||||
server *zeroconf.Server
|
||||
server *zeroconf.Server
|
||||
onlines []models.Online
|
||||
}
|
||||
|
||||
var Zeroconf = &zeroconfService{}
|
||||
@@ -37,31 +38,31 @@ func (s *zeroconfService) Close() {
|
||||
}
|
||||
|
||||
// FindService 查找被发现服务
|
||||
func (s *zeroconfService) FindService() (chan *models.Online, error) {
|
||||
func (s *zeroconfService) FindService() ([]models.Online, error) {
|
||||
return s.onlines, nil
|
||||
}
|
||||
|
||||
func (s *zeroconfService) StartFindService() error {
|
||||
resolver, err := zeroconf.NewResolver(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
allEntries := make(chan *zeroconf.ServiceEntry)
|
||||
useEntries := make(chan *models.Online)
|
||||
|
||||
go func(results <-chan *zeroconf.ServiceEntry) {
|
||||
for entry := range results {
|
||||
fmt.Println(entry.AddrIPv4, entry.ServiceInstanceName())
|
||||
if entry.ServiceInstanceName() == fmt.Sprintf("%s._http._tcp.local.", cfg.T.ZeroconfKey) {
|
||||
online, err := models.NewOnline(entry)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
useEntries <- online
|
||||
delOnlines := slices.DeleteFunc(s.onlines, func(item models.Online) bool {
|
||||
return item.ID == online.ID
|
||||
})
|
||||
s.onlines = append(delOnlines, *online)
|
||||
}
|
||||
}
|
||||
}(allEntries)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
err = resolver.Browse(ctx, "_http._tcp", "local.", allEntries)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, err
|
||||
}
|
||||
time.AfterFunc(10*time.Second, cancel)
|
||||
return useEntries, nil
|
||||
err = resolver.Browse(context.Background(), "_http._tcp", "local.", allEntries)
|
||||
return err
|
||||
}
|
||||
|
||||
+75
-4
@@ -1,10 +1,14 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"time"
|
||||
"work_cation/global"
|
||||
"work_cation/models"
|
||||
"work_cation/repo"
|
||||
@@ -18,11 +22,11 @@ func otherUser(w fyne.Window) fyne.CanvasObject {
|
||||
return widget.NewLabel("网络异常请稍后尝试")
|
||||
}
|
||||
go func() {
|
||||
for online := range findService {
|
||||
for _, online := range findService {
|
||||
var (
|
||||
onlineCopy = online
|
||||
)
|
||||
baseCardV, err := itemOnlineUserView(w, onlineCopy)
|
||||
baseCardV, err := itemOnlineUserView(w, &onlineCopy)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -69,9 +73,76 @@ func itemOnlineUserView(w fyne.Window, data *models.Online) (fyne.CanvasObject,
|
||||
})
|
||||
|
||||
showErrButton := widget.NewButton("查看主页", func() {
|
||||
dialog.ShowInformation("错误", "", w)
|
||||
otherUserIndexWin(user, data)
|
||||
})
|
||||
|
||||
card := widget.NewCard(user.Name, user.Ip, container.NewVBox(followLabel, showErrButton, followButton))
|
||||
return card, nil
|
||||
}
|
||||
|
||||
func otherUserIndexWin(user *models.Users, data *models.Online) {
|
||||
myApp := fyne.CurrentApp()
|
||||
myWindow := myApp.NewWindow(user.Name)
|
||||
myWindow.CenterOnScreen()
|
||||
myWindow.Resize(fyne.NewSize(620, 500))
|
||||
myWindow.SetContent(otherUserIndexView(myWindow, data))
|
||||
myWindow.Show()
|
||||
}
|
||||
|
||||
func otherUserIndexView(w fyne.Window, online *models.Online) fyne.CanvasObject {
|
||||
gridWrap := container.NewGridWrap(fyne.NewSize(200, 200))
|
||||
cards, _ := service.Client.GetCards(online)
|
||||
for _, baseCard := range cards {
|
||||
var baseCardCopy = baseCard
|
||||
baseCardV := baseOtherCardView(w, baseCardCopy, online)
|
||||
gridWrap.Add(baseCardV)
|
||||
}
|
||||
scroll := container.NewScroll(gridWrap)
|
||||
return container.NewBorder(nil, nil, nil, nil, scroll)
|
||||
}
|
||||
|
||||
func baseOtherCardView(w fyne.Window, baseCardCopy models.BaseCard, online *models.Online) *widget.Card {
|
||||
|
||||
saveCard := repo.BaseCard.Find(global.DB, baseCardCopy.UUID)
|
||||
|
||||
infoWid := container.NewVBox(
|
||||
widget.NewLabel(baseCardCopy.ToolType),
|
||||
widget.NewLabel(fmt.Sprintf("本地:%s", saveCard.UpdateTx.Format(time.DateTime))),
|
||||
widget.NewLabel(fmt.Sprintf("作者:%s", baseCardCopy.UpdateTx.Format(time.DateTime))),
|
||||
)
|
||||
|
||||
baseCardV := widget.NewCard(baseCardCopy.Title, baseCardCopy.Text, container.NewBorder(nil, widget.NewToolbar(
|
||||
widget.NewToolbarAction(theme.DownloadIcon(), func() {
|
||||
b := saveCard.UpdateTx.Unix() == baseCardCopy.UpdateTx.Unix()
|
||||
fmt.Println(saveCard.UpdateTx, baseCardCopy.UpdateTx)
|
||||
if b {
|
||||
dialog.ShowInformation("结果", "已下载本地", w)
|
||||
return
|
||||
}
|
||||
// 下载到本地 若没关注自动关注
|
||||
|
||||
progress := binding.NewFloat()
|
||||
progress.Set(0)
|
||||
progressBar := widget.NewProgressBarWithData(progress)
|
||||
progressBar.Max = 100
|
||||
smaillWin := dialog.NewCustom("下载中", "关闭", progressBar, w)
|
||||
smaillWin.Show()
|
||||
err := service.Client.Download(online, baseCardCopy.UUID, progress)
|
||||
if err != nil {
|
||||
smaillWin.SetDismissText("失败")
|
||||
return
|
||||
}
|
||||
// 修改数据
|
||||
progress.Set(99)
|
||||
saveCard.UpdateTx = baseCardCopy.UpdateTx
|
||||
err = repo.BaseCard.CreateOrSave(global.DB, &baseCardCopy)
|
||||
if err != nil {
|
||||
smaillWin.SetDismissText("失败")
|
||||
return
|
||||
}
|
||||
progress.Set(100)
|
||||
smaillWin.SetDismissText("完成 请去[我的]查看")
|
||||
|
||||
}),
|
||||
), nil, nil, infoWid))
|
||||
return baseCardV
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user