Sfoglia il codice sorgente

Add CasaConnect function

link 3 anni fa
parent
commit
dd0645ee0f
61 ha cambiato i file con 1163 aggiunte e 1277 eliminazioni
  1. 1 1
      UI
  2. 5 8
      conf/conf.ini.sample
  3. 1 0
      go.mod
  4. 1 0
      go.sum
  5. 33 5
      main.go
  6. 13 15
      model/net.go
  7. 7 0
      model/person.go
  8. 8 13
      model/sys_common.go
  9. 9 0
      model/user.go
  10. 4 4
      model/zima.go
  11. 0 4
      pkg/config/init.go
  12. 19 2
      pkg/config/update.go
  13. 1 1
      pkg/sqlite/db.go
  14. 13 0
      pkg/utils/file/file.go
  15. 3 1
      pkg/utils/httper/httper.go
  16. 0 1
      pkg/utils/ini_helper.go
  17. 16 5
      pkg/utils/oasis_err/e.go
  18. 0 47
      pkg/zerotier/zerotier_api.go
  19. 24 9
      route/init.go
  20. 27 57
      route/route.go
  21. 1 1
      route/v1/app.go
  22. 49 4
      route/v1/file.go
  23. 293 81
      route/v1/persion.go
  24. 55 1
      route/v1/system.go
  25. 48 11
      route/v1/user.go
  26. 0 475
      route/v1/zerotier.go
  27. 1 1
      route/v1/zima_info.go
  28. 45 2
      service/casa.go
  29. 23 15
      service/download.go
  30. 8 5
      service/friend.go
  31. 18 15
      service/model/o_download.go
  32. 7 5
      service/model/o_friend.go
  33. 21 0
      service/notify.go
  34. 55 15
      service/person.go
  35. 0 6
      service/service.go
  36. 16 0
      service/system.go
  37. 126 53
      service/udpconn.go
  38. 0 353
      service/zerotier.go
  39. 69 2
      service/zima_info.go
  40. 5 10
      shell/assist.sh
  41. 18 1
      shell/helper.sh
  42. 5 2
      shell/usb-mount.sh
  43. 2 0
      types/notify.go
  44. 1 0
      types/person.go
  45. 1 0
      types/person_download.go
  46. 2 2
      types/system.go
  47. BIN
      web/img/1-small.1b74d2ba.png
  48. 55 0
      web/img/folder-publicshare.0219e0d4.svg
  49. BIN
      web/img/folder.c8ff81f3.png
  50. BIN
      web/img/xfile.402f9e59.png
  51. 1 1
      web/index.html
  52. 9 9
      web/js/0.js
  53. 0 8
      web/js/1.js
  54. 9 10
      web/js/2.js
  55. 0 8
      web/js/3.js
  56. 4 4
      web/js/4.js
  57. 4 4
      web/js/5.js
  58. 10 0
      web/js/6.js
  59. 10 0
      web/js/7.js
  60. 0 0
      web/js/app.js
  61. 7 0
      web/js/chunk-vendors.js

+ 1 - 1
UI

@@ -1 +1 @@
-Subproject commit 247c099bf14a2d9eb94bf7798e04d00dbc8f7efd
+Subproject commit 74fa1f8920aa23f40b04b87cc04ebef5c36b0890

+ 5 - 8
conf/conf.ini.sample

@@ -14,11 +14,12 @@ RootPath = /casaOS
 
 
 [server]
 [server]
 HttpPort = 8089
 HttpPort = 8089
+UDPPort = 
 RunMode = release
 RunMode = release
 ServerApi = https://api.casaos.zimaboard.com
 ServerApi = https://api.casaos.zimaboard.com
-Handshake = 
+Handshake = socket.casaos.io
 Token = 
 Token = 
-NickName = 
+USBAutoMount = true
 
 
 
 
 [user]
 [user]
@@ -28,11 +29,7 @@ Email = user@gmail.com
 Description = description
 Description = description
 Initialized = false
 Initialized = false
 Avatar = 
 Avatar = 
-
-[zerotier]
-UserName = user
-PWD = pwd
-Token = yBKYyavr2RdFAIVN7iTpzlsB1o6CqTgm
+NickName = 
 
 
 [redis]
 [redis]
 Host = 127.0.0.1:6379
 Host = 127.0.0.1:6379
@@ -48,4 +45,4 @@ Analyse =
 
 
 [file]
 [file]
 ShareDir =
 ShareDir =
-DownloadDir = /DATA
+DownloadDir =

+ 1 - 0
go.mod

@@ -50,6 +50,7 @@ require (
 	github.com/sirupsen/logrus v1.8.1
 	github.com/sirupsen/logrus v1.8.1
 	github.com/smartystreets/assertions v1.2.0 // indirect
 	github.com/smartystreets/assertions v1.2.0 // indirect
 	github.com/smartystreets/goconvey v1.6.4 // indirect
 	github.com/smartystreets/goconvey v1.6.4 // indirect
+	github.com/spf13/afero v1.2.2
 	github.com/swaggo/gin-swagger v1.3.0
 	github.com/swaggo/gin-swagger v1.3.0
 	github.com/swaggo/swag v1.7.3
 	github.com/swaggo/swag v1.7.3
 	github.com/tidwall/gjson v1.10.2
 	github.com/tidwall/gjson v1.10.2

+ 1 - 0
go.sum

@@ -794,6 +794,7 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=

+ 33 - 5
main.go

@@ -4,9 +4,9 @@ import (
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
+	"runtime"
 	"time"
 	"time"
 
 
-	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/cache"
 	"github.com/IceWhaleTech/CasaOS/pkg/cache"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
 	"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
@@ -29,6 +29,24 @@ func init() {
 	config.InitSetup(*configFlag)
 	config.InitSetup(*configFlag)
 	config.UpdateSetup()
 	config.UpdateSetup()
 	loger2.LogSetup()
 	loger2.LogSetup()
+	sysType := runtime.GOOS
+	if sysType == "windows" {
+		config.AppInfo.ProjectPath = "C:\\CasaOS\\service"
+		config.Cfg.Section("app").Key("ProjectPath").SetValue("C:\\CasaOS\\service")
+
+		config.AppInfo.RootPath = "C:\\CasaOS"
+		config.Cfg.Section("app").Key("RootPath").SetValue("C:\\CasaOS")
+		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	}
+	if sysType == "darwin" {
+		config.AppInfo.ProjectPath = "./CasaOS/service"
+		config.Cfg.Section("app").Key("ProjectPath").SetValue("./CasaOS/service")
+
+		config.AppInfo.RootPath = "./CasaOS"
+		config.Cfg.Section("app").Key("RootPath").SetValue("./CasaOS")
+		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	}
+
 	sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
 	sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
 	//gredis.GetRedisConn(config.RedisInfo),
 	//gredis.GetRedisConn(config.RedisInfo),
 	service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
 	service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
@@ -36,10 +54,10 @@ func init() {
 
 
 	go service.UDPService()
 	go service.UDPService()
 
 
-	service.Summary = make(map[string]model.FileSummaryModel)
+	fmt.Println("token", service.GetToken())
 	service.UDPAddressMap = make(map[string]string)
 	service.UDPAddressMap = make(map[string]string)
 	//go service.SocketConnect()
 	//go service.SocketConnect()
-
+	service.CancelList = make(map[string]string)
 	route.InitFunction()
 	route.InitFunction()
 
 
 	go service.SendIPToServer()
 	go service.SendIPToServer()
@@ -69,20 +87,30 @@ func main() {
 	//gredis.Setup()
 	//gredis.Setup()
 	r := route.InitRouter()
 	r := route.InitRouter()
 	//service.SyncTask(sqliteDB)
 	//service.SyncTask(sqliteDB)
-	cron2 := cron.New() //创建一个cron实例
+	cron2 := cron.New()
 	//every day execution
 	//every day execution
 	err := cron2.AddFunc("0 0/5 * * * *", func() {
 	err := cron2.AddFunc("0 0/5 * * * *", func() {
 		//service.PushIpInfo(*&config.ServerInfo.Token)
 		//service.PushIpInfo(*&config.ServerInfo.Token)
 		//service.UpdataDDNSList(mysqldb)
 		//service.UpdataDDNSList(mysqldb)
 		//service.SyncTask(sqliteDB)
 		//service.SyncTask(sqliteDB)
+
 		service.SendIPToServer()
 		service.SendIPToServer()
+
 		service.LoopFriend()
 		service.LoopFriend()
+
 	})
 	})
 	if err != nil {
 	if err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
+	// err = cron2.AddFunc("0/1 * * * * *", func() {
+
+	// 	//service.SendIPToServer()
+	// 	//service.LoopNet()
 
 
-	//启动/关闭
+	// })
+	// if err != nil {
+	// 	fmt.Println(err)
+	// }
 	cron2.Start()
 	cron2.Start()
 	defer cron2.Stop()
 	defer cron2.Stop()
 	s := &http.Server{
 	s := &http.Server{

+ 13 - 15
model/net.go

@@ -1,19 +1,17 @@
 package model
 package model
 
 
-import "time"
-
 type IOCountersStat struct {
 type IOCountersStat struct {
-	Name        string    `json:"name"`        // interface name
-	BytesSent   uint64    `json:"bytesSent"`   // number of bytes sent
-	BytesRecv   uint64    `json:"bytesRecv"`   // number of bytes received
-	PacketsSent uint64    `json:"packetsSent"` // number of packets sent
-	PacketsRecv uint64    `json:"packetsRecv"` // number of packets received
-	Errin       uint64    `json:"errin"`       // total number of errors while receiving
-	Errout      uint64    `json:"errout"`      // total number of errors while sending
-	Dropin      uint64    `json:"dropin"`      // total number of incoming packets which were dropped
-	Dropout     uint64    `json:"dropout"`     // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
-	Fifoin      uint64    `json:"fifoin"`      // total number of FIFO buffers errors while receiving
-	Fifoout     uint64    `json:"fifoout"`     // total number of FIFO buffers errors while sending
-	State       string    `json:"state"`
-	DateTime    time.Time `json:"date_time"`
+	Name        string `json:"name"`        // interface name
+	BytesSent   uint64 `json:"bytesSent"`   // number of bytes sent
+	BytesRecv   uint64 `json:"bytesRecv"`   // number of bytes received
+	PacketsSent uint64 `json:"packetsSent"` // number of packets sent
+	PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
+	Errin       uint64 `json:"errin"`       // total number of errors while receiving
+	Errout      uint64 `json:"errout"`      // total number of errors while sending
+	Dropin      uint64 `json:"dropin"`      // total number of incoming packets which were dropped
+	Dropout     uint64 `json:"dropout"`     // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
+	Fifoin      uint64 `json:"fifoin"`      // total number of FIFO buffers errors while receiving
+	Fifoout     uint64 `json:"fifoout"`     // total number of FIFO buffers errors while sending
+	State       string `json:"state"`
+	Time        int64  `json:"time"`
 }
 }

+ 7 - 0
model/person.go

@@ -45,3 +45,10 @@ type FileSummaryModel struct {
 	Size      int64  `json:"size"`
 	Size      int64  `json:"size"`
 	Message   string `json:"message"`
 	Message   string `json:"message"`
 }
 }
+
+type FriendsModel struct {
+	Id       uint   `gorm:"column:id;primary_key" json:"id"`
+	NickName string `json:"nick_name"`
+	Desc     string `json:"desc"`
+	ShareId  string `json:"share_id"`
+}

+ 8 - 13
model/sys_common.go

@@ -22,12 +22,14 @@ type UserModel struct {
 
 
 //服务配置
 //服务配置
 type ServerModel struct {
 type ServerModel struct {
-	HttpPort    string
-	RunMode     string
-	ServerApi   string
-	LockAccount bool
-	Handshake   string
-	Token       string
+	HttpPort     string
+	RunMode      string
+	ServerApi    string
+	LockAccount  bool
+	Handshake    string
+	Token        string
+	UDPPort      string
+	USBAutoMount string
 }
 }
 
 
 //服务配置
 //服务配置
@@ -50,13 +52,6 @@ type Result struct {
 	Data    interface{} `json:"data" example:"返回结果"`
 	Data    interface{} `json:"data" example:"返回结果"`
 }
 }
 
 
-//zeritier相关
-type ZeroTierModel struct {
-	UserName string
-	PWD      string
-	Token    string
-}
-
 //redis配置文件
 //redis配置文件
 type RedisModel struct {
 type RedisModel struct {
 	Host        string
 	Host        string

+ 9 - 0
model/user.go

@@ -0,0 +1,9 @@
+package model
+
+type UserInfo struct {
+	NickName string `json:"nick_name"`
+	Desc     string `json:"desc"`
+	ShareId  string `json:"share_id"`
+	Avatar   string `json:"avatar"`
+	Version  int    `json:"version,omitempty"`
+}

+ 4 - 4
model/zima.go

@@ -3,11 +3,11 @@ package model
 import "time"
 import "time"
 
 
 type Path struct {
 type Path struct {
-	Name  string    `json:"name"`
-	Path  string    `json:"path"`
-	IsDir bool      `json:"is_dir"`
+	Name  string    `json:"name"`   //File name or document name
+	Path  string    `json:"path"`   //Full path to file or folder
+	IsDir bool      `json:"is_dir"` //Is it a folder
 	Date  time.Time `json:"date"`
 	Date  time.Time `json:"date"`
-	Size  int64     `json:"size"`
+	Size  int64     `json:"size"` //File Size
 	Type  string    `json:"type,omitempty"`
 	Type  string    `json:"type,omitempty"`
 	Label string    `json:"label,omitempty"`
 	Label string    `json:"label,omitempty"`
 }
 }

+ 0 - 4
pkg/config/init.go

@@ -25,9 +25,6 @@ var AppInfo = &model.APPModel{}
 //redis相关配置
 //redis相关配置
 var RedisInfo = &model.RedisModel{}
 var RedisInfo = &model.RedisModel{}
 
 
-//zerotier相关
-var ZeroTierInfo = &model.ZeroTierModel{}
-
 //server相关
 //server相关
 var ServerInfo = &model.ServerModel{}
 var ServerInfo = &model.ServerModel{}
 
 
@@ -56,7 +53,6 @@ func InitSetup(config string) {
 
 
 	mapTo("user", UserInfo)
 	mapTo("user", UserInfo)
 	mapTo("app", AppInfo)
 	mapTo("app", AppInfo)
-	mapTo("zerotier", ZeroTierInfo)
 	mapTo("redis", RedisInfo)
 	mapTo("redis", RedisInfo)
 	mapTo("server", ServerInfo)
 	mapTo("server", ServerInfo)
 	mapTo("system", SystemConfigInfo)
 	mapTo("system", SystemConfigInfo)

+ 19 - 2
pkg/config/update.go

@@ -1,13 +1,30 @@
 package config
 package config
 
 
-import "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
+import (
+	"runtime"
+
+	"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
+)
 
 
 //检查目录是否存在
 //检查目录是否存在
 func mkdirDATAAll() {
 func mkdirDATAAll() {
-	dirArray := [7]string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
+	sysType := runtime.GOOS
+	var dirArray []string
+	if sysType == "linux" {
+		dirArray = []string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
+	}
+
+	if sysType == "windows" {
+		dirArray = []string{"C:\\CasaOS\\DATA\\AppData", "C:\\CasaOS\\DATA\\Documents", "C:\\CasaOS\\DATA\\Downloads", "C:\\CasaOS\\DATA\\Gallery", "C:\\CasaOS\\DATA\\Media/Movies", "C:\\CasaOS\\DATA\\Media\\TV Shows", "C:\\CasaOS\\DATA\\Media\\Music"}
+	}
+	if sysType == "darwin" {
+		dirArray = []string{"./CasaOS/DATA/AppData", "./CasaOS/DATA/Documents", "./CasaOS/DATA/Downloads", "./CasaOS/DATA/Gallery", "./CasaOS/DATA/Media/Movies", "./CasaOS/DATA/Media/TV Shows", "./CasaOS/DATA/Media/Music"}
+	}
+
 	for _, v := range dirArray {
 	for _, v := range dirArray {
 		file.IsNotExistMkDir(v)
 		file.IsNotExistMkDir(v)
 	}
 	}
+
 }
 }
 
 
 func UpdateSetup() {
 func UpdateSetup() {

+ 1 - 1
pkg/sqlite/db.go

@@ -31,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
 		return nil
 		return nil
 	}
 	}
 	gdb = db
 	gdb = db
-	err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersionDownloadDBModel{}, model2.FriendModel{})
+	err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{})
 	if err != nil {
 	if err != nil {
 		fmt.Println("检查和创建数据库出错", err)
 		fmt.Println("检查和创建数据库出错", err)
 	}
 	}

+ 13 - 0
pkg/utils/file/file.go

@@ -8,6 +8,8 @@ import (
 	"mime/multipart"
 	"mime/multipart"
 	"os"
 	"os"
 	"path"
 	"path"
+	path2 "path"
+	"path/filepath"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 )
 )
@@ -226,6 +228,17 @@ func CopyFile(src, dst string) error {
 	return os.Chmod(dst, srcinfo.Mode())
 	return os.Chmod(dst, srcinfo.Mode())
 }
 }
 
 
+//Check for duplicate file names
+func GetNoDuplicateFileName(fullPath string) string {
+	path, fileName := filepath.Split(fullPath)
+	fileSuffix := path2.Ext(fileName)
+	filenameOnly := strings.TrimSuffix(fileName, fileSuffix)
+	for i := 0; Exists(fullPath); i++ {
+		fullPath = path2.Join(path, filenameOnly+"("+strconv.Itoa(i+1)+")"+fileSuffix)
+	}
+	return fullPath
+}
+
 // Dir copies a whole directory recursively
 // Dir copies a whole directory recursively
 func CopyDir(src string, dst string) error {
 func CopyDir(src string, dst string) error {
 	var err error
 	var err error

+ 3 - 1
pkg/utils/httper/httper.go

@@ -3,6 +3,7 @@ package httper
 import (
 import (
 	"bytes"
 	"bytes"
 	"encoding/json"
 	"encoding/json"
+	"fmt"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
@@ -67,7 +68,8 @@ func Post(url string, data []byte, contentType string, head map[string]string) (
 	client := &http.Client{Timeout: 5 * time.Second}
 	client := &http.Client{Timeout: 5 * time.Second}
 	resp, error := client.Do(req)
 	resp, error := client.Do(req)
 	if error != nil {
 	if error != nil {
-		panic(error)
+		fmt.Println(error)
+		return
 	}
 	}
 	defer resp.Body.Close()
 	defer resp.Body.Close()
 
 

+ 0 - 1
pkg/utils/ini_helper.go

@@ -1 +0,0 @@
-package utils

+ 16 - 5
pkg/utils/oasis_err/e.go

@@ -37,13 +37,18 @@ const (
 	FILE_DOES_NOT_EXIST = 60001
 	FILE_DOES_NOT_EXIST = 60001
 	FILE_READ_ERROR     = 60002
 	FILE_READ_ERROR     = 60002
 	FILE_DELETE_ERROR   = 60003
 	FILE_DELETE_ERROR   = 60003
+	DIR_NOT_EXISTS      = 60004
 
 
 	//shortcuts
 	//shortcuts
 	SHORTCUTS_URL_ERROR = 70001
 	SHORTCUTS_URL_ERROR = 70001
 
 
-	//persion
-	PERSION_REMOTE_ERROR   = 80001
-	PERSION_DOWN_NOT_EXIST = 80002
+	//person
+	PERSON_REMOTE_ERROR   = 80001
+	PERSON_DOWN_NOT_EXIST = 80002
+	PERSON_EXIST_DOWNLOAD = 80003
+	PERSON_NOT_EXIST_USER = 80004
+	PERSON_EXIST_FRIEND   = 80005
+	PERSON_MYSELF         = 80006
 )
 )
 
 
 var MsgFlags = map[int]string{
 var MsgFlags = map[int]string{
@@ -82,12 +87,18 @@ var MsgFlags = map[int]string{
 	//
 	//
 	FILE_DOES_NOT_EXIST: "File does not exist",
 	FILE_DOES_NOT_EXIST: "File does not exist",
 
 
+	DIR_NOT_EXISTS: "Directory does not exist",
+
 	FILE_READ_ERROR:     "File read error",
 	FILE_READ_ERROR:     "File read error",
 	FILE_DELETE_ERROR:   "Delete error",
 	FILE_DELETE_ERROR:   "Delete error",
 	SHORTCUTS_URL_ERROR: "URL error",
 	SHORTCUTS_URL_ERROR: "URL error",
 
 
-	PERSION_REMOTE_ERROR:   "Remote connection error",
-	PERSION_DOWN_NOT_EXIST: "Download record does not exist",
+	PERSON_REMOTE_ERROR:   "Remote connection error",
+	PERSON_DOWN_NOT_EXIST: "Download record does not exist",
+	PERSON_EXIST_DOWNLOAD: "The same download task exists",
+	PERSON_EXIST_FRIEND:   "Friend already exist",
+	PERSON_NOT_EXIST_USER: "User does not exist",
+	PERSON_MYSELF:         "You can not add yourself",
 }
 }
 
 
 //获取错误信息
 //获取错误信息

+ 0 - 47
pkg/zerotier/zerotier_api.go

@@ -1,47 +0,0 @@
-package zerotier
-
-import (
-	httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
-	"github.com/tidwall/gjson"
-	"net/http"
-)
-
-func PostData(url, token string, data string) interface{} {
-
-	body, code := httper2.ZeroTierPostJson(url, data, GetHead(token))
-
-	if code != http.StatusOK {
-		return ""
-	}
-	result := gjson.Parse(body)
-	return result.Value()
-}
-
-func GetData(url, token string) interface{} {
-
-	body, code := httper2.ZeroTierGet(url, GetHead(token))
-
-	if code != http.StatusOK {
-		return ""
-	}
-	result := gjson.Parse(body)
-	return result.Value()
-}
-
-func DeleteMember(url, token string) interface{} {
-
-	body, code := httper2.ZeroTierDelete(url, GetHead(token))
-
-	if code != http.StatusOK {
-		return ""
-	}
-	result := gjson.Parse(body)
-	return result.Value()
-}
-
-func GetHead(token string) map[string]string {
-	var head = make(map[string]string)
-	head["Authorization"] = "Bearer " + token
-	head["Content-Type"] = "application/json"
-	return head
-}

+ 24 - 9
route/init.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"encoding/xml"
 	"encoding/xml"
 	"fmt"
 	"fmt"
+	"runtime"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
 
 
@@ -231,10 +232,10 @@ func CheckSerialDiskMount() {
 	}
 	}
 	service.MyService.Disk().RemoveLSBLKCache()
 	service.MyService.Disk().RemoveLSBLKCache()
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
-
 }
 }
 func Update2_3() {
 func Update2_3() {
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
 	command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
+
 }
 }
 func CheckToken2_11() {
 func CheckToken2_11() {
 	if len(config.ServerInfo.Token) == 0 {
 	if len(config.ServerInfo.Token) == 0 {
@@ -253,19 +254,33 @@ func CheckToken2_11() {
 	// 	config.AppInfo.RootPath = "/casaOS"
 	// 	config.AppInfo.RootPath = "/casaOS"
 	// 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	// 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	// }
 	// }
-	if len(config.FileSettingInfo.ShareDir) == 0 {
-		config.Cfg.Section("file").Key("ShareDir").SetValue("/DATA")
-		config.FileSettingInfo.ShareDir[0] = "/DATA"
-
+	sysType := runtime.GOOS
+	if len(config.FileSettingInfo.DownloadDir) == 0 {
+		downloadPath := "/DATA/Downloads"
+		if sysType == "windows" {
+			downloadPath = "C:\\CasaOS\\DATA\\Downloads"
+		}
+		if sysType == "darwin" {
+			downloadPath = "~/CasaOS/DATA/Downloads"
+		}
+		config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
+		config.FileSettingInfo.DownloadDir = downloadPath
+		file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
 		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	}
 	}
 
 
-	if len(config.FileSettingInfo.DownloadDir) == 0 {
-		config.Cfg.Section("file").Key("DownloadDir").SetValue("/DATA/share")
-		config.FileSettingInfo.DownloadDir = "/DATA/share"
-		file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
+	if len(config.UserInfo.Description) == 0 {
+		config.Cfg.Section("user").Key("Description").SetValue("nothing")
+		config.UserInfo.Description = "nothing"
 		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	}
 	}
+	if len(config.ServerInfo.Handshake) == 0 {
+		config.Cfg.Section("server").Key("Handshake").SetValue("socket.casaos.io")
+		config.ServerInfo.Handshake = "socket.casaos.io"
+		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	}
+
+	service.MyService.System().ExecUSBAutoMountShell(config.ServerInfo.USBAutoMount)
 
 
 	// str := []string{}
 	// str := []string{}
 	// str = append(str, "ddd")
 	// str = append(str, "ddd")

+ 27 - 57
route/route.go

@@ -18,6 +18,7 @@ var OnlineDemo bool = false
 func InitRouter() *gin.Engine {
 func InitRouter() *gin.Engine {
 
 
 	r := gin.Default()
 	r := gin.Default()
+
 	r.Use(middleware.Cors())
 	r.Use(middleware.Cors())
 	r.Use(gzip.Gzip(gzip.DefaultCompression))
 	r.Use(gzip.Gzip(gzip.DefaultCompression))
 	gin.SetMode(config.ServerInfo.RunMode)
 	gin.SetMode(config.ServerInfo.RunMode)
@@ -52,13 +53,16 @@ func InitRouter() *gin.Engine {
 			//chang head
 			//chang head
 			v1UserGroup.POST("/head", v1.PostUserHead)
 			v1UserGroup.POST("/head", v1.PostUserHead)
 			//chang user name
 			//chang user name
-			v1UserGroup.PUT("/changusername", v1.PutUserName)
+			v1UserGroup.PUT("/username", v1.PutUserName)
 			//chang pwd
 			//chang pwd
-			v1UserGroup.PUT("/changuserpwd", v1.PutUserPwd)
+			v1UserGroup.PUT("/password", v1.PutUserPwd)
 			//edit user info
 			//edit user info
 			v1UserGroup.POST("/info", v1.PostUserChangeInfo)
 			v1UserGroup.POST("/info", v1.PostUserChangeInfo)
 			v1UserGroup.PUT("/nick", v1.PutUserChangeNick)
 			v1UserGroup.PUT("/nick", v1.PutUserChangeNick)
 			v1UserGroup.PUT("/desc", v1.PutUserChangeDesc)
 			v1UserGroup.PUT("/desc", v1.PutUserChangeDesc)
+			v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
+
+			v1UserGroup.GET("/shareid", v1.GetUserShareID)
 
 
 		}
 		}
 
 
@@ -78,51 +82,6 @@ func InitRouter() *gin.Engine {
 			//获取系统信息
 			//获取系统信息
 			v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
 			v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
 		}
 		}
-
-		v1ZeroTierGroup := v1Group.Group("/zerotier")
-		v1ZeroTierGroup.Use()
-		{
-			//获取zerotier token
-			v1ZeroTierGroup.POST("/login", v1.ZeroTierGetToken)
-			//注册zerotier
-			v1ZeroTierGroup.POST("/register", v1.ZeroTierRegister)
-			//是否需要登录
-			v1ZeroTierGroup.GET("/islogin", v1.ZeroTierIsNeedLogin)
-			//获取网络列表
-			v1ZeroTierGroup.GET("/list", v1.ZeroTierGetNetworkList)
-			//加入网络
-			v1ZeroTierGroup.POST("/join/:id", v1.ZeroTierJoinNetwork)
-			//离开网络
-			v1ZeroTierGroup.POST("/leave/:id", v1.ZeroTierLeaveNetwork)
-			//详情
-			v1ZeroTierGroup.GET("/info/:id", v1.ZeroTierGetNetworkGetInfo)
-			////网络状态
-			//v1ZeroTierGroup.GET("/status", v1.ZeroTierGetNetworkGetStatus)
-			//修改网络类型
-			//v1ZeroTierGroup.PUT("/type/:id", v1.ZeroTierEditType)
-			//修改网络类型
-			//v1ZeroTierGroup.PUT("/name/:id", v1.ZeroTierEditName)
-			//修改v6 assign
-			//v1ZeroTierGroup.PUT("/v6assign/:id", v1.ZeroTierEditV6Assign)
-			//修改 broadcast
-			//v1ZeroTierGroup.PUT("/broadcast/:id", v1.ZeroTierEditBroadcast)
-			//create new network
-			v1ZeroTierGroup.POST("/create", v1.ZeroTierCreateNetwork)
-			//获取用户列表
-			v1ZeroTierGroup.GET("/member/:id", v1.ZeroTierMemberList)
-			//修改用户信息
-			//v1ZeroTierGroup.PUT("/members/:id/auth/:mId", v1.ZeroTierMemberAuth)
-			//修改网络用户name
-			//v1ZeroTierGroup.PUT("/members/:id/name/:mId", v1.ZeroTierMemberName)
-			v1ZeroTierGroup.DELETE("/members/:id/del/:mId", v1.ZeroTierMemberDelete)
-			v1ZeroTierGroup.DELETE("/network/:id/del", v1.ZeroTierDeleteNetwork)
-			//修改网络用户bridge功能
-			//v1ZeroTierGroup.PUT("/members/:id/bridge/:mId", v1.ZeroTierMemberBridge)
-			v1ZeroTierGroup.PUT("/edit/:id", v1.ZeroTierEdit)
-			v1ZeroTierGroup.GET("/joined/list", v1.ZeroTierJoinedList)
-			v1ZeroTierGroup.PUT("/member/:id/edit/:mId", v1.ZeroTierMemberEdit)
-
-		}
 		v1DDNSGroup := v1Group.Group("/ddns")
 		v1DDNSGroup := v1Group.Group("/ddns")
 		v1DDNSGroup.Use()
 		v1DDNSGroup.Use()
 		{
 		{
@@ -201,6 +160,9 @@ func InitRouter() *gin.Engine {
 			v1SysGroup.PUT("/port", v1.PutCasaOSPort)
 			v1SysGroup.PUT("/port", v1.PutCasaOSPort)
 			v1SysGroup.POST("/kill", v1.PostKillCasaOS)
 			v1SysGroup.POST("/kill", v1.PostKillCasaOS)
 			v1SysGroup.GET("/info", v1.Info)
 			v1SysGroup.GET("/info", v1.Info)
+			v1SysGroup.PUT("/usb/off", v1.PutSystemOffUSBAutoMount)
+			v1SysGroup.GET("/usb/on", v1.PutSystemOnUSBAutoMount)
+			v1SysGroup.GET("/usb", v1.GetSystemUSBAutoMount)
 		}
 		}
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup := v1Group.Group("/file")
 		v1FileGroup.Use()
 		v1FileGroup.Use()
@@ -216,6 +178,7 @@ func InitRouter() *gin.Engine {
 			v1FileGroup.POST("/create", v1.PostCreateFile)
 			v1FileGroup.POST("/create", v1.PostCreateFile)
 
 
 			v1FileGroup.GET("/download", v1.GetDownloadFile)
 			v1FileGroup.GET("/download", v1.GetDownloadFile)
+			v1FileGroup.GET("/new/download", v1.GetFileDownloadNew)
 			v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
 			v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
 			v1FileGroup.DELETE("/delete", v1.DeleteFile)
 			v1FileGroup.DELETE("/delete", v1.DeleteFile)
 			v1FileGroup.PUT("/update", v1.PutFileContent)
 			v1FileGroup.PUT("/update", v1.PutFileContent)
@@ -289,19 +252,26 @@ func InitRouter() *gin.Engine {
 		{
 		{
 			v1SearchGroup.GET("/search", v1.GetSearchList)
 			v1SearchGroup.GET("/search", v1.GetSearchList)
 		}
 		}
-		v1PersonGroup := v1Group.Group("/persion")
+		v1PersonGroup := v1Group.Group("/person")
 		v1PersonGroup.Use()
 		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("/file", v1.GetPersionFile)
-			v1PersonGroup.GET("/refile/:uuid", v1.GetPersionReFile)
-			v1PersonGroup.PUT("/nick/:token", v1.PutPersionNick)
-			v1PersonGroup.GET("/list", v1.GetPersionDownloadList)
-			v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersionDownloadFile)
-			// v1PersonGroup.PUT("/state/:id", v1.PutPersionCancelDownload) //修改下载状态(开始暂停删除)
+			v1PersonGroup.GET("/users", v1.GetPersonFriend)
+			v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
+			v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
+			v1PersonGroup.GET("/directory", v1.GetPersonDirectory)
+			v1PersonGroup.GET("/file", v1.GetPersonFile)
+			v1PersonGroup.GET("/refile/:uuid", v1.GetPersonReFile)
+			v1PersonGroup.PUT("/remarks/:shareid", v1.PutPersonRemarks)
+			v1PersonGroup.GET("/list", v1.GetPersonDownloadList)
+			v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
+
+			v1PersonGroup.POST("/share", v1.PostPersonShare)
+			v1PersonGroup.GET("/share", v1.GetPersonShare)
+			v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
+			v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
+			v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
+			v1PersonGroup.GET("/public", v1.GetPersonPublic)
 
 
 		}
 		}
 		v1AnalyseGroup := v1Group.Group("/analyse")
 		v1AnalyseGroup := v1Group.Group("/analyse")

+ 1 - 1
route/v1/app.go

@@ -248,7 +248,7 @@ func ShareAppFile(c *gin.Context) {
 // @Tags app
 // @Tags app
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /app/share [post]
+// @Router /app/shares [post]
 func AppListResourceUsage() {
 func AppListResourceUsage() {
 
 
 }
 }

+ 49 - 4
route/v1/file.go

@@ -7,6 +7,7 @@ import (
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
+	url2 "net/url"
 	"os"
 	"os"
 	"path"
 	"path"
 	"strconv"
 	"strconv"
@@ -17,6 +18,7 @@ import (
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
+	"github.com/spf13/afero"
 )
 )
 
 
 func downloadReadFile(c *gin.Context) {
 func downloadReadFile(c *gin.Context) {
@@ -157,16 +159,59 @@ func GetDownloadFile(c *gin.Context) {
 	//获取文件的名称
 	//获取文件的名称
 	fileName := path.Base(filePath)
 	fileName := path.Base(filePath)
 	c.Header("Content-Type", "application/octet-stream")
 	c.Header("Content-Type", "application/octet-stream")
-	c.Header("Content-Disposition", "attachment; filename="+fileName)
+	c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
 	c.Header("Content-Transfer-Encoding", "binary")
 	c.Header("Content-Transfer-Encoding", "binary")
 	c.Header("Cache-Control", "no-cache")
 	c.Header("Cache-Control", "no-cache")
-	c.Header("Content-Type", "application/octet-stream")
-	c.Header("Content-Disposition", "attachment; filename="+fileName)
-	c.Header("Content-Transfer-Encoding", "binary")
 
 
 	c.File(filePath)
 	c.File(filePath)
 }
 }
 
 
+// @Summary download
+// @Produce  application/json
+// @Accept application/json
+// @Tags file
+// @Security ApiKeyAuth
+// @Param path query string true "path of file"
+// @Success 200 {string} string "ok"
+// @Router /file/new/download [get]
+func GetFileDownloadNew(c *gin.Context) {
+	filePath := c.Query("path")
+	if len(filePath) == 0 {
+		c.JSON(http.StatusOK, model.Result{
+			Success: oasis_err2.INVALID_PARAMS,
+			Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
+		})
+		return
+	}
+	if !file.Exists(filePath) {
+		c.JSON(http.StatusOK, model.Result{
+			Success: oasis_err2.FILE_DOES_NOT_EXIST,
+			Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
+		})
+		return
+	}
+	//打开文件
+	fileStat, _ := os.Stat(filePath)
+	var AppFs = afero.NewOsFs()
+	fileT, _ := AppFs.Open(filePath)
+	//fileTmp, _ := os.Open(filePath)
+	//defer fileTmp.Close()
+	//获取文件的名称
+	//fileName := path.Base(filePath)
+
+	//c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
+	//在线
+	//c.Header("Content-Disposition", "inline")
+	// extraHeaders := map[string]string{
+	// 	"Content-Disposition": `attachment; filename="` + url2.PathEscape(fileName) + `"`,
+	// }
+
+	//c.Header("Cache-Control", "private")
+	//c.Header("Content-Type", "application/octet-stream")
+
+	http.ServeContent(c.Writer, c.Request, fileStat.Name(), fileStat.ModTime(), fileT)
+}
+
 // @Summary 获取目录列表
 // @Summary 获取目录列表
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json

+ 293 - 81
route/v1/persion.go

@@ -7,9 +7,12 @@ import (
 	"net/http"
 	"net/http"
 	"reflect"
 	"reflect"
 	"strconv"
 	"strconv"
+	"strings"
+	"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/utils/file"
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
 	"github.com/IceWhaleTech/CasaOS/service"
 	"github.com/IceWhaleTech/CasaOS/service"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
 	model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -19,8 +22,10 @@ import (
 )
 )
 
 
 func PersonTest(c *gin.Context) {
 func PersonTest(c *gin.Context) {
-
 	token := c.Query("token")
 	token := c.Query("token")
+	_, err := uuid.FromString(token)
+	fmt.Println(err)
+
 	//service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9")
 	//service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9")
 
 
 	msg := model.MessageModel{}
 	msg := model.MessageModel{}
@@ -35,45 +40,48 @@ func PersonTest(c *gin.Context) {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
 	fmt.Println(dd)
 	fmt.Println(dd)
+	user := service.MyService.Casa().GetUserInfoByShareId(token)
+	if reflect.DeepEqual(user, model.UserInfo{}) {
+		fmt.Println("空数据")
+	}
+	fmt.Println(user)
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 }
 }
 
 
-// @Summary retry download file
+// @Summary Retry the file that failed to download
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
+// @Tags person
 // @Param  uui path string true "download uuid"
 // @Param  uui path string true "download uuid"
-// @Param  path query string true "file path"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /persion/refile/{uuid} [get]
-func GetPersionReFile(c *gin.Context) {
+// @Router /person/refile/{uuid} [get]
+func GetPersonReFile(c *gin.Context) {
 
 
-	path := c.Query("path")
-	uuid := c.Param("uuid")
-
-	if len(path) == 0 && len(uuid) == 0 {
+	uid := c.Param("uuid")
+	_, err := uuid.FromString(uid)
+	if err != nil {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 
 
-	task := service.MyService.Download().GetDownloadById(uuid)
-	if reflect.DeepEqual(task, model2.PersionDownloadDBModel{}) {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSION_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSION_REMOTE_ERROR)})
+	task := service.MyService.Download().GetDownloadById(uid)
+	if reflect.DeepEqual(task, model2.PersonDownloadDBModel{}) {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
 		return
 		return
 	}
 	}
 	token := task.From
 	token := task.From
 	if _, ok := service.UDPAddressMap[token]; !ok {
 	if _, ok := service.UDPAddressMap[token]; !ok {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSION_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSION_REMOTE_ERROR)})
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
 		return
 		return
 	}
 	}
 
 
 	m := model.MessageModel{}
 	m := model.MessageModel{}
-	m.Data = path
+	m.Data = task.Path
 	m.From = config.ServerInfo.Token
 	m.From = config.ServerInfo.Token
 	m.To = token
 	m.To = token
 	m.Type = types.PERSONDOWNLOAD
 	m.Type = types.PERSONDOWNLOAD
-	m.UUId = uuid
+	m.UUId = uid
 	go service.Dial(m, false)
 	go service.Dial(m, false)
 
 
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
@@ -82,35 +90,57 @@ func GetPersionReFile(c *gin.Context) {
 // @Summary download file
 // @Summary download file
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
-// @Param  token query string true "opponent token"
+// @Tags person
+// @Param  share_id query string true "opponent share_id"
 // @Param  path query string true "file path"
 // @Param  path query string true "file path"
+// @Param  file_name query string true "file name"
+// @Param  local_path query string true "local_path"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /persion/file [get]
-func GetPersionFile(c *gin.Context) {
+// @Router /person/file [get]
+func GetPersonFile(c *gin.Context) {
 
 
 	path := c.Query("path")
 	path := c.Query("path")
-	token := c.Query("token")
-	if len(path) == 0 && len(token) == 0 {
+	localPath := c.Query("local_path")
+	token := c.Query("share_id")
+	fileName := c.Query("file_name")
+	_, err := uuid.FromString(token)
+	if len(path) == 0 || err != nil || len(localPath) == 0 || len(fileName) == 0 {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
+	if file.CheckNotExist(localPath) {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
+		return
+	}
+	if _, ok := service.UDPAddressMap[token]; !ok {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
+		return
+	}
+
 	if _, ok := service.UDPAddressMap[token]; !ok {
 	if _, ok := service.UDPAddressMap[token]; !ok {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSION_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSION_REMOTE_ERROR)})
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
 		return
 		return
 	}
 	}
+
 	// task id
 	// task id
 	uuid := uuid.NewV4().String()
 	uuid := uuid.NewV4().String()
 
 
-	task := model2.PersionDownloadDBModel{}
+	task := model2.PersonDownloadDBModel{}
 	task.UUID = uuid
 	task.UUID = uuid
-	task.Name = ""
+	task.Name = fileName
 	task.Length = 0
 	task.Length = 0
 	task.From = token
 	task.From = token
+	task.Path = path
 	task.Size = 0
 	task.Size = 0
 	task.State = types.DOWNLOADAWAIT
 	task.State = types.DOWNLOADAWAIT
+	task.Created = time.Now().Unix()
 	task.Type = 0
 	task.Type = 0
+	task.LocalPath = localPath
+	if service.MyService.Download().GetDownloadListByPath(task) > 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
+		return
+	}
 	service.MyService.Download().AddDownloadTask(task)
 	service.MyService.Download().AddDownloadTask(task)
 
 
 	m := model.MessageModel{}
 	m := model.MessageModel{}
@@ -127,79 +157,92 @@ func GetPersionFile(c *gin.Context) {
 // @Summary delete download file records
 // @Summary delete download file records
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
+// @Tags person
 // @Param  uuid path string true "download uuid"
 // @Param  uuid path string true "download uuid"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /persion/file/{uuid} [delete]
-func DeletePersionDownloadFile(c *gin.Context) {
+// @Router /person/file/{uuid} [delete]
+func DeletePersonDownloadFile(c *gin.Context) {
 
 
 	id := c.Param("uuid")
 	id := c.Param("uuid")
-	if len(id) == 0 {
+	_, err := uuid.FromString(id)
+	if err != nil {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 
 
+	task := service.MyService.Download().GetDownloadById(id)
+	if task.State == types.DOWNLOADING {
+		m := model.MessageModel{}
+		m.Data = ""
+		m.From = config.ServerInfo.Token
+		m.To = task.From
+		m.Type = types.PERSONCANCEL
+		m.UUId = task.UUID
+		service.CancelList[task.UUID] = task.UUID
+		service.Dial(m, false)
+	}
 	service.MyService.Download().DelDownload(id)
 	service.MyService.Download().DelDownload(id)
 
 
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 }
 }
 
 
-// @Summary get file download list
+// @Summary Get file download list
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
-// @Param  state query int true "wait:1,downloading:1,pause:2,finish:3,error:4" Enums(0,1,2,4)
+// @Tags person
+// @Param  state query int false "wait:0,downloading:1,pause:2,finish:3,error:4,finished:5" Enums(0,1,2,3,4,5)
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /persion/list [get]
-func GetPersionDownloadList(c *gin.Context) {
+// @Success 200 {object} []model2.PersonDownloadDBModel
+// @Router /person/list [get]
+func GetPersonDownloadList(c *gin.Context) {
 	state := c.DefaultQuery("state", "")
 	state := c.DefaultQuery("state", "")
 	list := service.MyService.Download().GetDownloadListByState(state)
 	list := service.MyService.Download().GetDownloadListByState(state)
 	//if it is  downloading, it need to add 'already'
 	//if it is  downloading, it need to add 'already'
-	if state == strconv.Itoa(types.DOWNLOADING) {
-		for i := 0; i < len(list); i++ {
+	for i := 0; i < len(list); i++ {
+		if list[i].State == types.DOWNLOADING {
 			tempDir := config.AppInfo.RootPath + "/temp" + "/" + list[i].UUID
 			tempDir := config.AppInfo.RootPath + "/temp" + "/" + list[i].UUID
 			files, err := ioutil.ReadDir(tempDir)
 			files, err := ioutil.ReadDir(tempDir)
 			if err == nil {
 			if err == nil {
 				list[i].Already = len(files)
 				list[i].Already = len(files)
 			}
 			}
 		}
 		}
+		list[i].Duration = time.Now().Unix() - list[i].Created
 	}
 	}
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
 }
 }
 
 
-// @Summary edit friend's nick
+// @Summary edit friend's remarks
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
-// @Param token path string true "token"
-// @Param nick formData string true "nick name"
+// @Tags person
+// @Param remarks formData string true "remarks name"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /persion/nick/{token} [put]
-func PutPersionNick(c *gin.Context) {
-	token := c.Param("token")
-	nick := c.PostForm("nick")
-	if len(token) == 0 || len(nick) == 0 {
+// @Router /person/remarks/{shareid} [put]
+func PutPersonRemarks(c *gin.Context) {
+	token := c.Param("shareid")
+	_, err := uuid.FromString(token)
+	mark := c.PostForm("remarks")
+	if err != nil || len(mark) == 0 {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 	friend := model2.FriendModel{}
 	friend := model2.FriendModel{}
 	friend.Token = token
 	friend.Token = token
-	friend.NickName = nick
-	service.MyService.Friend().EditFriendNick(friend)
+	friend.Mark = mark
+	service.MyService.Friend().EditFriendMark(friend)
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 }
 }
 
 
-// @Summary get friend list
+// @Summary get my friend list
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
+// @Tags person
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /persion/users [get]
-func GetPersionFriend(c *gin.Context) {
+// @Success 200 {object}  []model2.FriendModel
+// @Router /person/users [get]
+func GetPersonFriend(c *gin.Context) {
 	list := service.MyService.Friend().GetFriendList()
 	list := service.MyService.Friend().GetFriendList()
 	for i := 0; i < len(list); i++ {
 	for i := 0; i < len(list); i++ {
 		if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
 		if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
@@ -212,51 +255,79 @@ func GetPersionFriend(c *gin.Context) {
 // @Summary add friend
 // @Summary add friend
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
-// @Param  token formData int true "Opponent token"
+// @Tags person
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /persion/user [post]
-func PostAddPersionFriend(c *gin.Context) {
-	token := c.PostForm("token")
-	if len(token) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
+// @Router /person/user/{shareids} [post]
+func PostAddPersonFriend(c *gin.Context) {
+	token := c.Param("shareids")
+	tokenList := strings.Split(token, ",")
 
 
-	msg := model.MessageModel{}
-	msg.Type = types.PERSONCONNECTION
-	msg.Data = token
-	msg.From = config.ServerInfo.Token
-	msg.To = token
-	msg.UUId = uuid.NewV4().String()
+	for _, v := range tokenList {
+		_, err := uuid.FromString(v)
+		if err != nil {
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+			return
+		}
 
 
-	go service.Dial(msg, true)
+		if v == config.ServerInfo.Token {
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_MYSELF, Message: oasis_err2.GetMsg(oasis_err2.PERSON_MYSELF)})
+			return
+		}
+
+		udb := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: v})
+		if !reflect.DeepEqual(udb, model2.FriendModel{Token: v}) {
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_FRIEND, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_FRIEND)})
+			return
+		}
+
+		user := service.MyService.Casa().GetUserInfoByShareId(v)
+		if reflect.DeepEqual(user, model.UserInfo{}) {
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_NOT_EXIST_USER, Message: oasis_err2.GetMsg(oasis_err2.PERSON_NOT_EXIST_USER)})
+			return
+		}
+
+		message := model.MessageModel{}
+		message.Type = types.PERSONCONNECTION
+		message.Data = v
+		message.From = config.ServerInfo.Token
+		message.To = v
+		message.UUId = uuid.NewV4().String()
+
+		go service.Dial(message, true)
+
+		friend := model2.FriendModel{}
+		friend.Token = v
+		friend.Avatar = user.Avatar
+		friend.Block = false
+		friend.NickName = user.NickName
+		friend.Profile = user.Desc
+		friend.Version = user.Version
+		service.MyService.Friend().AddFriend(friend)
+	}
 
 
-	friend := model2.FriendModel{}
-	friend.Token = token
-	service.MyService.Friend().AddFriend(friend)
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
 }
 }
 
 
-// @Summary get directory list
+// @Summary Get a list of directories
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
-// @Tags persion
-// @Param  token query string true "Opponent token"
+// @Tags person
+// @Param  share_id query string true "Opponent share_id"
 // @Param  path query string true "dir path"
 // @Param  path query string true "dir path"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /persion/directory [get]
-func GetPersionDirectory(c *gin.Context) {
+// @Success 200 {object}  []model.Path
+// @Router /person/directory [get]
+func GetPersonDirectory(c *gin.Context) {
 	path := c.Query("path")
 	path := c.Query("path")
-	token := c.Query("token")
-	if len(path) == 0 && len(token) == 0 {
+	token := c.Query("share_id")
+	_, err := uuid.FromString(token)
+	if len(path) == 0 || err != nil {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 	if _, ok := service.UDPAddressMap[token]; !ok {
 	if _, ok := service.UDPAddressMap[token]; !ok {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSION_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSION_REMOTE_ERROR)})
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
 		return
 		return
 	}
 	}
 	uuid := uuid.NewV4().String()
 	uuid := uuid.NewV4().String()
@@ -282,3 +353,144 @@ func GetPersionDirectory(c *gin.Context) {
 	}
 	}
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: dataModel})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: dataModel})
 }
 }
+
+// @Summary Modify the download storage directory
+// @Produce  application/json
+// @Accept  multipart/form-data
+// @Tags person
+// @Security ApiKeyAuth
+// @Param path formData string true "path"
+// @Success 200 {string} string "ok"
+// @Router /person/down/dir [post]
+func PostPersonDownDir(c *gin.Context) {
+
+	downPath := c.PostForm("path")
+
+	if len(downPath) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+	if file.CheckNotExist(downPath) {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
+		return
+	}
+	config.Cfg.Section("file").Key("DownloadDir").SetValue(downPath)
+	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	config.FileSettingInfo.DownloadDir = downPath
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
+}
+
+// @Summary Get the download storage directory
+// @Produce  application/json
+// @Accept application/json
+// @Tags person
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /person/down/dir [get]
+func GetPersonDownDir(c *gin.Context) {
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.DownloadDir})
+}
+
+// @Summary Modify the shared directory
+// @Produce  application/json
+// @Accept  multipart/form-data
+// @Tags person
+// @Security ApiKeyAuth
+// @Param share formData string true "share"
+// @Success 200 {string} string "ok"
+// @Router /person/share [post]
+func PostPersonShare(c *gin.Context) {
+
+	share := c.PostForm("share")
+
+	if len(share) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+
+	var list []string
+	json.Unmarshal([]byte(share), &list)
+
+	if len(list) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+	for _, v := range list {
+		if !file.Exists(v) {
+			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
+			return
+		}
+	}
+
+	config.Cfg.Section("file").Key("ShareDir").SetValue(strings.Join(list, "|"))
+	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	config.FileSettingInfo.ShareDir = list
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
+}
+
+// @Summary Get the shared directory
+// @Produce  application/json
+// @Accept application/json
+// @Tags person
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /person/share [get]
+func GetPersonShare(c *gin.Context) {
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.ShareDir})
+}
+
+// @Summary Modify disabled status
+// @Produce  application/json
+// @Accept application/json
+// @Tags person
+// @Param block formData bool false "Disable or not,Default:false "
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /person/block/{shareid} [put]
+func PutPersonBlock(c *gin.Context) {
+	token := c.Param("shareid")
+	_, err := uuid.FromString(token)
+	block, _ := strconv.ParseBool(c.PostForm("block"))
+	if err != nil {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+	friend := model2.FriendModel{}
+	friend.Token = token
+	friend.Block = block
+	service.MyService.Friend().EditFriendBlock(friend)
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
+}
+
+// @Summary Delete my friend
+// @Produce  application/json
+// @Accept application/json
+// @Tags person
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /person/user/{shareid} [delete]
+func DeletePersonFriend(c *gin.Context) {
+	token := c.Param("shareid")
+	_, err := uuid.FromString(token)
+	if err != nil {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+	friend := model2.FriendModel{}
+	friend.Token = token
+
+	service.MyService.Friend().DeleteFriend(friend)
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
+}
+
+// @Summary Get public person
+// @Produce  application/json
+// @Accept application/json
+// @Tags person
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /person/public [delete]
+func GetPersonPublic(c *gin.Context) {
+	list := service.MyService.Casa().GetPersonPublic()
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
+}

+ 55 - 1
route/v1/system.go

@@ -251,6 +251,60 @@ func PostKillCasaOS(c *gin.Context) {
 	os.Exit(0)
 	os.Exit(0)
 }
 }
 
 
+// @Summary Turn off usb auto-mount
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /sys/usg/off [put]
+func PutSystemOffUSBAutoMount(c *gin.Context) {
+	service.MyService.System().UpdateUSBAutoMount("False")
+	service.MyService.System().ExecUSBAutoMountShell("False")
+	c.JSON(http.StatusOK,
+		model.Result{
+			Success: oasis_err.SUCCESS,
+			Message: oasis_err.GetMsg(oasis_err.SUCCESS),
+		})
+}
+
+// @Summary Turn off usb auto-mount
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /sys/usb [get]
+func GetSystemUSBAutoMount(c *gin.Context) {
+	state := "True"
+	if config.ServerInfo.USBAutoMount == "False" {
+		state = "False"
+	}
+	c.JSON(http.StatusOK,
+		model.Result{
+			Success: oasis_err.SUCCESS,
+			Message: oasis_err.GetMsg(oasis_err.SUCCESS),
+			Data:    state,
+		})
+}
+
+// @Summary Turn off usb auto-mount
+// @Produce  application/json
+// @Accept application/json
+// @Tags sys
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /sys/usb/on [put]
+func PutSystemOnUSBAutoMount(c *gin.Context) {
+	service.MyService.System().UpdateUSBAutoMount("True")
+	service.MyService.System().ExecUSBAutoMountShell("True")
+	c.JSON(http.StatusOK,
+		model.Result{
+			Success: oasis_err.SUCCESS,
+			Message: oasis_err.GetMsg(oasis_err.SUCCESS),
+		})
+}
+
 // @Summary system info
 // @Summary system info
 // @Produce  application/json
 // @Produce  application/json
 // @Accept application/json
 // @Accept application/json
@@ -374,7 +428,7 @@ func Info(c *gin.Context) {
 			if n.Name == netCardName {
 			if n.Name == netCardName {
 				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
 				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
 				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
 				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
-				item.DateTime = time.Now()
+				item.Time = time.Now().Unix()
 				newNet = append(newNet, item)
 				newNet = append(newNet, item)
 				break
 				break
 			}
 			}

+ 48 - 11
route/v1/user.go

@@ -121,7 +121,7 @@ func PostUserHead(c *gin.Context) {
 // @Param oldname  formData string true "Old user name"
 // @Param oldname  formData string true "Old user name"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /user/changusername [put]
+// @Router /user/username [put]
 func PutUserName(c *gin.Context) {
 func PutUserName(c *gin.Context) {
 	if config.ServerInfo.LockAccount {
 	if config.ServerInfo.LockAccount {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
@@ -142,14 +142,14 @@ func PutUserName(c *gin.Context) {
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags user
 // @Tags user
 // @Param pwd formData string true "Password"
 // @Param pwd formData string true "Password"
-// @Param oldpwd  formData string true "Old password"
+// @Param old_pwd  formData string true "Old password"
 // @Security ApiKeyAuth
 // @Security ApiKeyAuth
 // @Success 200 {string} string "ok"
 // @Success 200 {string} string "ok"
-// @Router /user/changuserpwd [put]
+// @Router /user/password [put]
 func PutUserPwd(c *gin.Context) {
 func PutUserPwd(c *gin.Context) {
-	oldpwd := c.PostForm("oldpwd")
+	oldPwd := c.PostForm("old_pwd")
 	pwd := c.PostForm("pwd")
 	pwd := c.PostForm("pwd")
-	if config.UserInfo.PWD != oldpwd {
+	if config.UserInfo.PWD != oldPwd {
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID_OLD, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID_OLD)})
 		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID_OLD, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID_OLD)})
 		return
 		return
 	}
 	}
@@ -199,7 +199,7 @@ func PostUserChangeInfo(c *gin.Context) {
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 }
 }
 
 
-// @Summary edit user info
+// @Summary edit user nick
 // @Produce  application/json
 // @Produce  application/json
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags user
 // @Tags user
@@ -211,17 +211,18 @@ func PutUserChangeNick(c *gin.Context) {
 
 
 	nickName := c.PostForm("nick_name")
 	nickName := c.PostForm("nick_name")
 
 
-	if len(nickName) > 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID)})
+	if len(nickName) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 	user_service.SetUser("", "", "", "", "", nickName)
 	user_service.SetUser("", "", "", "", "", nickName)
 	data := make(map[string]string, 1)
 	data := make(map[string]string, 1)
 	data["nick_name"] = config.UserInfo.NickName
 	data["nick_name"] = config.UserInfo.NickName
+	go service.MyService.Casa().PushUserInfo()
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 }
 }
 
 
-// @Summary edit user info
+// @Summary edit user description
 // @Produce  application/json
 // @Produce  application/json
 // @Accept multipart/form-data
 // @Accept multipart/form-data
 // @Tags user
 // @Tags user
@@ -232,13 +233,38 @@ func PutUserChangeNick(c *gin.Context) {
 func PutUserChangeDesc(c *gin.Context) {
 func PutUserChangeDesc(c *gin.Context) {
 	desc := c.PostForm("description")
 	desc := c.PostForm("description")
 
 
-	if len(desc) > 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID)})
+	if len(desc) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
 		return
 		return
 	}
 	}
 	user_service.SetUser("", "", "", "", desc, "")
 	user_service.SetUser("", "", "", "", desc, "")
 	data := make(map[string]string, 1)
 	data := make(map[string]string, 1)
 	data["description"] = config.UserInfo.Description
 	data["description"] = config.UserInfo.Description
+	go service.MyService.Casa().PushUserInfo()
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
+}
+
+// @Summary Modify user person information (Initialization use)
+// @Produce  application/json
+// @Accept multipart/form-data
+// @Tags user
+// @Param nick_name formData string false "user nick name"
+// @Param description formData string false "Description"
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /user/person/info [post]
+func PostUserPersonInfo(c *gin.Context) {
+	desc := c.PostForm("description")
+	nickName := c.PostForm("nick_name")
+	if len(desc) == 0 || len(nickName) == 0 {
+		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
+		return
+	}
+	user_service.SetUser("", "", "", "", desc, nickName)
+	data := make(map[string]string, 2)
+	data["description"] = config.UserInfo.Description
+	data["nick_name"] = config.UserInfo.NickName
+	go service.MyService.Casa().PushUserInfo()
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
 }
 }
 
 
@@ -262,3 +288,14 @@ func GetUserInfo(c *gin.Context) {
 			Data:    u,
 			Data:    u,
 		})
 		})
 }
 }
+
+// @Summary Get my shareId
+// @Produce  application/json
+// @Accept application/json
+// @Tags user
+// @Security ApiKeyAuth
+// @Success 200 {string} string "ok"
+// @Router /user/shareid [get]
+func GetUserShareID(c *gin.Context) {
+	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.ServerInfo.Token})
+}

+ 0 - 475
route/v1/zerotier.go

@@ -1,475 +0,0 @@
-package v1
-
-import (
-	json2 "encoding/json"
-	"net/http"
-
-	"github.com/IceWhaleTech/CasaOS/model"
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
-	oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
-	"github.com/IceWhaleTech/CasaOS/service"
-	"github.com/gin-gonic/gin"
-)
-
-// @Summary 登录zerotier获取token
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags zerotier
-// @Param username formData string true "User name"
-// @Param pwd  formData string true "password"
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/login [post]
-func ZeroTierGetToken(c *gin.Context) {
-	username := c.PostForm("username")
-	pwd := c.PostForm("pwd")
-	if len(username) == 0 || len(pwd) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	errInfo := service.MyService.ZeroTier().GetToken(username, pwd)
-
-	if len(errInfo) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.GET_TOKEN_ERROR)})
-	} else {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
-	}
-}
-
-// @Summary 注册zerotier
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags zerotier
-// @Param firstName formData string true "first name"
-// @Param pwd  formData string true "password"
-// @Param email  formData string true "email"
-// @Param lastName  formData string true "last name"
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/register [post]
-func ZeroTierRegister(c *gin.Context) {
-	firstName := c.PostForm("firstName")
-	pwd := c.PostForm("pwd")
-	email := c.PostForm("email")
-	lastName := c.PostForm("lastName")
-	if len(firstName) == 0 || len(pwd) == 0 || len(email) == 0 || len(lastName) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	errInfo := service.MyService.ZeroTier().ZeroTierRegister(email, lastName, firstName, pwd)
-	if len(errInfo) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
-	} else {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: errInfo})
-	}
-}
-
-// @Summary 是否需要登录zerotier
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Success 200 {string} string "false:需要登录,true:不需要登录"
-// @Router /zerotier/islogin [get]
-func ZeroTierIsNeedLogin(c *gin.Context) {
-	if len(config.ZeroTierInfo.Token) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: false})
-	} else {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: true})
-	}
-}
-
-// @Summary 获取zerotier网络列表
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/list [get]
-func ZeroTierGetNetworkList(c *gin.Context) {
-	jsonList, joined := service.MyService.ZeroTier().ZeroTierNetworkList(config.ZeroTierInfo.Token)
-	rdata := make(map[string]interface{})
-	rdata["network_list"] = jsonList
-	rdata["joined"] = joined
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
-}
-
-// @Summary 获取zerotier网络详情
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/info/{id} [get]
-func ZeroTierGetNetworkGetInfo(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
-	}
-	info, joined := service.MyService.ZeroTier().ZeroTierGetInfo(config.ZeroTierInfo.Token, id)
-	rdata := make(map[string]interface{})
-	rdata["info"] = info
-	rdata["joined"] = joined
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
-}
-
-//// @Summary 获取zerotier网络状态
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/status [get]
-//func ZeroTierGetNetworkGetStatus(c *gin.Context) {
-//	status := service.MyService.ZeroTier().ZeroTierGetStatus(config.ZeroTierInfo.Token)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: status})
-//}
-
-//// @Summary 修改网络类型
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param type formData string true "Private true/false"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/type/{id} [put]
-//func ZeroTierEditType(c *gin.Context) {
-//	id := c.Param("id")
-//	t := c.PostForm("type")
-//	if len(id) == 0 || len(t) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"config":{"private":` + t + `}}`
-//	info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-//// @Summary 修改名称
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param name formData string true "需要过滤特殊字符串"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/name/{id} [put]
-//func ZeroTierEditName(c *gin.Context) {
-//	id := c.Param("id")
-//	name := c.PostForm("name")
-//	if len(id) == 0 || len(name) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"config":{"name":"` + name + `"}}`
-//	info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-//// @Summary V6Assign (注意三个属性需要一起传过来,不传的会被zerotier设置成false)
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param v6plan formData string false "true/false"
-//// @Param rfc formData string false "true/false"
-//// @Param auto formData string false "true/false"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/v6assign/{id} [put]
-//func ZeroTierEditV6Assign(c *gin.Context) {
-//	id := c.Param("id")
-//	v6plan := c.PostForm("v6plan")
-//	rfc := c.PostForm("rfc")
-//	auto := c.PostForm("auto")
-//	if len(id) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	var spicing string
-//	if len(v6plan) > 0 {
-//		spicing = `"6plane":` + v6plan
-//	}
-//	if len(rfc) > 0 {
-//		if len(spicing) > 0 {
-//			spicing += ","
-//		}
-//		spicing += `"rfc4193":` + rfc
-//	}
-//
-//	if len(auto) > 0 {
-//		if len(spicing) > 0 {
-//			spicing += ","
-//		}
-//		spicing += `"zt":` + auto
-//	}
-//	postData := `{"config":{"v6AssignMode":{` + spicing + `}}}`
-//	info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-//// @Summary Broadcast
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param broadcast formData string true "true/false"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/broadcast/{id} [put]
-//func ZeroTierEditBroadcast(c *gin.Context) {
-//	id := c.Param("id")
-//	broadcast := c.PostForm("broadcast")
-//	if len(id) == 0 || len(broadcast) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"config":{"enableBroadcast":` + broadcast + `}}`
-//	info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-// @Summary 网络列表
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/member/{id} [get]
-func ZeroTierMemberList(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
-	}
-	info := service.MyService.ZeroTier().MemberList(config.ZeroTierInfo.Token, id)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-// @Summary create new network
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/create [post]
-func ZeroTierCreateNetwork(c *gin.Context) {
-	info := service.MyService.ZeroTier().CreateNetwork(config.ZeroTierInfo.Token)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-//// @Summary 通过/拒绝客户端
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param mId path string true "member_id"
-//// @Param auth formData string true "true/false"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/member/{id}/auth/{mId} [put]
-//func ZeroTierMemberAuth(c *gin.Context) {
-//	id := c.Param("id")
-//	mId := c.Param("mId")
-//	auth := c.PostForm("auth")
-//	if len(id) == 0 || len(mId) == 0 || len(auth) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"config":{"authorized":` + auth + `}}`
-//	info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-//// @Summary 修改名字
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param mId path string true "member_id"
-//// @Param name formData string true "name"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/member/{id}/name/{mId} [put]
-//func ZeroTierMemberName(c *gin.Context) {
-//	id := c.Param("id")
-//	mId := c.Param("mId")
-//	name := c.PostForm("name")
-//	if len(id) == 0 || len(mId) == 0 || len(name) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"name":"` + name + `"}`
-//	info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-//// @Summary 修改桥接
-//// @Produce  application/json
-//// @Accept application/json
-//// @Tags zerotier
-//// @Security ApiKeyAuth
-//// @Param id path string true "network id"
-//// @Param mId path string true "member_id"
-//// @Param bridge formData string true "true/false"
-//// @Success 200 {string} string "ok"
-//// @Router /zerotier/member/{id}/bridge/{mId} [put]
-//func ZeroTierMemberBridge(c *gin.Context) {
-//	id := c.Param("id")
-//	mId := c.Param("mId")
-//	bridge := c.PostForm("bridge")
-//	if len(id) == 0 || len(mId) == 0 || len(bridge) == 0 {
-//		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-//		return
-//	}
-//	postData := `{"config":{"activeBridge":` + bridge + `}}`
-//	info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
-//	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-//}
-
-// @Summary 修改网络
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Param json formData string true "json数据"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/edit/{id} [put]
-func ZeroTierEdit(c *gin.Context) {
-	id := c.Param("id")
-	json := c.PostForm("json")
-	if len(id) == 0 || len(json) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, json, id)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-// @Summary 获取已加入的网络
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/joined/list [get]
-func ZeroTierJoinedList(c *gin.Context) {
-	info := service.MyService.ZeroTier().GetJoinNetworks()
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: json2.RawMessage(info)})
-}
-
-// @Summary 修改网络用户信息
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Param mId path string true "mId"
-// @Param json formData string true "json数据"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/member/{id}/edit/{mId} [put]
-func ZeroTierMemberEdit(c *gin.Context) {
-	id := c.Param("id")
-	mId := c.Param("mId")
-	json := c.PostForm("json")
-	if len(id) == 0 || len(json) == 0 || len(mId) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, json, id, mId)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-// @Summary 删除网络中的用户
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Param mId path string true "member_id"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/member/{id}/del/{mId} [delete]
-func ZeroTierMemberDelete(c *gin.Context) {
-	id := c.Param("id")
-	mId := c.Param("mId")
-	if len(id) == 0 || len(mId) == 0 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	info := service.MyService.ZeroTier().DeleteMember(config.ZeroTierInfo.Token, id, mId)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-// @Summary 删除网络
-// @Produce  application/json
-// @Accept application/json
-// @Tags zerotier
-// @Security ApiKeyAuth
-// @Param id path string true "network id"
-// @Success 200 {string} string "ok"
-// @Router /zerotier/network/{id}/del [delete]
-func ZeroTierDeleteNetwork(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
-	}
-	info := service.MyService.ZeroTier().DeleteNetwork(config.ZeroTierInfo.Token, id)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
-}
-
-// @Summary 加入网络
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags zerotier
-// @Param id path string true "network id"
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/join/{id} [post]
-func ZeroTierJoinNetwork(c *gin.Context) {
-	networkId := c.Param("id")
-	if len(networkId) != 16 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-	for _, v := range networkId {
-		if !service.MyService.ZeroTier().NetworkIdFilter(v) {
-			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-			return
-		}
-	}
-	service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
-}
-
-// @Summary 获取zerotier网络列表
-// @Produce  application/json
-// @Accept multipart/form-data
-// @Tags zerotier
-// @Param id path string true "network id"
-// @Security ApiKeyAuth
-// @Success 200 {string} string "ok"
-// @Router /zerotier/leave/{id} [post]
-func ZeroTierLeaveNetwork(c *gin.Context) {
-	networkId := c.Param("id")
-
-	if len(networkId) != 16 {
-		c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-		return
-	}
-
-	for _, v := range networkId {
-		if !service.MyService.ZeroTier().NetworkIdFilter(v) {
-			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
-			return
-		}
-	}
-	service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
-
-	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
-}

+ 1 - 1
route/v1/zima_info.go

@@ -73,7 +73,7 @@ func NetInfo(c *gin.Context) {
 			if n.Name == netCardName {
 			if n.Name == netCardName {
 				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
 				item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
 				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
 				item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
-				item.DateTime = time.Now()
+				item.Time = time.Now().Unix()
 				newNet = append(newNet, item)
 				newNet = append(newNet, item)
 				break
 				break
 			}
 			}

+ 45 - 2
service/casa.go

@@ -22,6 +22,9 @@ type CasaService interface {
 	PushHeart(id, t string, language string)
 	PushHeart(id, t string, language string)
 	PushAppAnalyse(uuid, t string, name, language string)
 	PushAppAnalyse(uuid, t string, name, language string)
 	PushConnectionStatus(uuid, err string, from, to, event string)
 	PushConnectionStatus(uuid, err string, from, to, event string)
+	PushUserInfo()
+	GetUserInfoByShareId(shareId string) model.UserInfo
+	GetPersonPublic() (list []model.FriendsModel)
 }
 }
 
 
 type casaService struct {
 type casaService struct {
@@ -118,7 +121,6 @@ func GetToken() string {
 	}
 	}
 	go func() {
 	go func() {
 		str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
 		str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
-
 		t <- gjson.Get(str, "data").String()
 		t <- gjson.Get(str, "data").String()
 	}()
 	}()
 	auth = <-t
 	auth = <-t
@@ -178,13 +180,54 @@ func (o *casaService) PushConnectionStatus(uuid, err string, from, to, event str
 
 
 	head["Authorization"] = GetToken()
 	head["Authorization"] = GetToken()
 
 
-	infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/app", b, "application/json", head)
+	infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/connect", b, "application/json", head)
+
+	info := model.ServerAppList{}
+	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
+
+}
+func (o *casaService) PushUserInfo() {
+	m := model.UserInfo{}
+	m.Desc = config.UserInfo.Description
+	m.Avatar = config.UserInfo.Avatar
+	m.NickName = config.UserInfo.NickName
+	m.ShareId = config.ServerInfo.Token
+	b, _ := json.Marshal(m)
+
+	head := make(map[string]string)
+
+	head["Authorization"] = GetToken()
+
+	infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/user/info", b, "application/json", head)
 
 
 	info := model.ServerAppList{}
 	info := model.ServerAppList{}
 	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
 	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
 
 
 }
 }
 
 
+func (o *casaService) GetUserInfoByShareId(shareId string) model.UserInfo {
+
+	head := make(map[string]string)
+
+	head["Authorization"] = GetToken()
+
+	infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/user/info/"+shareId, head)
+
+	info := model.UserInfo{}
+	json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
+	return info
+}
+func (o *casaService) GetPersonPublic() (list []model.FriendsModel) {
+	head := make(map[string]string)
+
+	head["Authorization"] = GetToken()
+
+	listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/person/public", head)
+
+	json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
+
+	return list
+}
 func NewCasaService() CasaService {
 func NewCasaService() CasaService {
 	return &casaService{}
 	return &casaService{}
 }
 }

+ 23 - 15
service/download.go

@@ -6,43 +6,51 @@ import (
 )
 )
 
 
 type DownloadService interface {
 type DownloadService interface {
-	AddDownloadTask(m model2.PersionDownloadDBModel)   //添加下载任务
-	EditDownloadState(m model2.PersionDownloadDBModel) //只修改状态
-	SaveDownload(m model2.PersionDownloadDBModel)
+	AddDownloadTask(m model2.PersonDownloadDBModel)   //添加下载任务
+	EditDownloadState(m model2.PersonDownloadDBModel) //只修改状态
+	SaveDownload(m model2.PersonDownloadDBModel)
 	DelDownload(uuid string)
 	DelDownload(uuid string)
-	GetDownloadById(uuid string) model2.PersionDownloadDBModel
-	GetDownloadListByState(state string) []model2.PersionDownloadDBModel
-	SetDownloadError(m model2.PersionDownloadDBModel)
+	GetDownloadById(uuid string) model2.PersonDownloadDBModel
+	GetDownloadListByState(state string) []model2.PersonDownloadDBModel
+	SetDownloadError(m model2.PersonDownloadDBModel)
+	GetDownloadListByPath(m model2.PersonDownloadDBModel) int
 }
 }
 type downloadService struct {
 type downloadService struct {
 	db *gorm.DB
 	db *gorm.DB
 }
 }
 
 
-func (d *downloadService) AddDownloadTask(m model2.PersionDownloadDBModel) {
+func (d *downloadService) GetDownloadListByPath(m model2.PersonDownloadDBModel) int {
+	var list []model2.PersonDownloadDBModel
+	d.db.Select("path").Where("path = ? AND `from` = ? AND state = 0", m.Path, m.From).Find(&list)
+	return len(list)
+}
+
+func (d *downloadService) AddDownloadTask(m model2.PersonDownloadDBModel) {
+
 	d.db.Create(&m)
 	d.db.Create(&m)
 }
 }
-func (d *downloadService) EditDownloadState(m model2.PersionDownloadDBModel) {
+func (d *downloadService) EditDownloadState(m model2.PersonDownloadDBModel) {
+
 	d.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State)
 	d.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State)
 }
 }
 
 
 //failed during download
 //failed during download
-func (d *downloadService) SetDownloadError(m model2.PersionDownloadDBModel) {
+func (d *downloadService) SetDownloadError(m model2.PersonDownloadDBModel) {
 	d.db.Model(&m).Updates(m)
 	d.db.Model(&m).Updates(m)
 }
 }
 
 
 func (d *downloadService) DelDownload(uuid string) {
 func (d *downloadService) DelDownload(uuid string) {
-	var m model2.PersionDownloadDBModel
+	var m model2.PersonDownloadDBModel
 	d.db.Where("uuid = ?", uuid).Delete(&m)
 	d.db.Where("uuid = ?", uuid).Delete(&m)
 }
 }
-func (d *downloadService) GetDownloadById(uuid string) model2.PersionDownloadDBModel {
-	var m model2.PersionDownloadDBModel
+func (d *downloadService) GetDownloadById(uuid string) model2.PersonDownloadDBModel {
+	var m model2.PersonDownloadDBModel
 	d.db.Model(m).Where("uuid = ?", uuid).First(&m)
 	d.db.Model(m).Where("uuid = ?", uuid).First(&m)
 	return m
 	return m
 }
 }
-func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersionDownloadDBModel) {
+func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersonDownloadDBModel) {
 	if len(state) == 0 {
 	if len(state) == 0 {
 		d.db.Find(&list)
 		d.db.Find(&list)
-
 	} else {
 	} else {
 		d.db.Where("state = ?", state).Find(&list)
 		d.db.Where("state = ?", state).Find(&list)
 	}
 	}
@@ -50,7 +58,7 @@ func (d *downloadService) GetDownloadListByState(state string) (list []model2.Pe
 	return
 	return
 }
 }
 
 
-func (d *downloadService) SaveDownload(m model2.PersionDownloadDBModel) {
+func (d *downloadService) SaveDownload(m model2.PersonDownloadDBModel) {
 	d.db.Save(&m)
 	d.db.Save(&m)
 }
 }
 func NewDownloadService(db *gorm.DB) DownloadService {
 func NewDownloadService(db *gorm.DB) DownloadService {

+ 8 - 5
service/friend.go

@@ -10,7 +10,8 @@ import (
 type FriendService interface {
 type FriendService interface {
 	AddFriend(m model2.FriendModel)
 	AddFriend(m model2.FriendModel)
 	DeleteFriend(m model2.FriendModel)
 	DeleteFriend(m model2.FriendModel)
-	EditFriendNick(m model2.FriendModel)
+	EditFriendMark(m model2.FriendModel)
+	EditFriendBlock(m model2.FriendModel)
 	GetFriendById(m model2.FriendModel) model2.FriendModel
 	GetFriendById(m model2.FriendModel) model2.FriendModel
 	GetFriendList() (list []model2.FriendModel)
 	GetFriendList() (list []model2.FriendModel)
 	UpdateAddFriendType(m model2.FriendModel)
 	UpdateAddFriendType(m model2.FriendModel)
@@ -27,17 +28,19 @@ func (p *friendService) AddFriend(m model2.FriendModel) {
 func (p *friendService) DeleteFriend(m model2.FriendModel) {
 func (p *friendService) DeleteFriend(m model2.FriendModel) {
 	p.db.Where("token = ?", m.Token).Delete(&m)
 	p.db.Where("token = ?", m.Token).Delete(&m)
 }
 }
-func (p *friendService) EditFriendNick(m model2.FriendModel) {
-	p.db.Model(&m).Where("token = ?", m.Token).Update("nick_name", m.NickName)
+func (p *friendService) EditFriendMark(m model2.FriendModel) {
+	p.db.Model(&m).Where("token = ?", m.Token).Update("mark", m.Mark)
+}
+func (p *friendService) EditFriendBlock(m model2.FriendModel) {
+	p.db.Model(&m).Where("token = ?", m.Token).Update("block", m.Block)
 }
 }
-
 func (p *friendService) GetFriendById(m model2.FriendModel) model2.FriendModel {
 func (p *friendService) GetFriendById(m model2.FriendModel) model2.FriendModel {
 	p.db.Model(m).Where("token = ?", m.Token).First(&m)
 	p.db.Model(m).Where("token = ?", m.Token).First(&m)
 	return m
 	return m
 }
 }
 
 
 func (p *friendService) GetFriendList() (list []model2.FriendModel) {
 func (p *friendService) GetFriendList() (list []model2.FriendModel) {
-	p.db.Select("nick_name", "avatar", "name", "profile", "token", "state").Find(&list)
+	p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Find(&list)
 	return list
 	return list
 }
 }
 
 

+ 18 - 15
service/model/o_download.go

@@ -1,21 +1,24 @@
 package model
 package model
 
 
-type PersionDownloadDBModel struct {
+type PersonDownloadDBModel struct {
 	UUID      string `gorm:"column:uuid;primary_key" json:"uuid"`
 	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
-	Size      int64  `json:"size"`  //file size
-	BlockSize int    `json:"block_size"`
-	Length    int    `json:"length"` //slice length
-	Hash      string `json:"hash"`
-	Error     string `json:"error"`
-	From      string `json:"from"`
-	Already   int    `json:"already" gorm:"-"`
-	CreatedAt int64  `gorm:"autoCreateTime" json:"created_at"`
-	UpdatedAt int64  `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
+	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"`        //Size of each file block
+	Length    int    `json:"length"`            //slice length
+	Hash      string `json:"hash"`              //File hash value
+	Error     string `json:"error"`             //
+	From      string `json:"from"`              //Error message
+	Path      string `json:"path"`              //Full path to the file
+	Already   int    `json:"already" gorm:"-"`  //Folder blocks that have been downloaded
+	LocalPath string `json:"local_path"`        //The address where the file is saved after download
+	Duration  int64  `json:"duration" gorm:"-"` //Length of time
+	Created   int64  `gorm:"autoCreateTime" json:"created"`
+	Updated   int64  `gorm:"autoCreateTime;autoUpdateTime" json:"updated"`
 }
 }
 
 
-func (p *PersionDownloadDBModel) TableName() string {
-	return "o_persion_download"
+func (p *PersonDownloadDBModel) TableName() string {
+	return "o_person_download"
 }
 }

+ 7 - 5
service/model/o_friend.go

@@ -1,15 +1,17 @@
 package model
 package model
 
 
 type FriendModel struct {
 type FriendModel struct {
-	State     int    `json:"state"` //备用
+	State     int    `json:"state"` //Reserved
 	CreatedAt int64  `gorm:"autoCreateTime" json:"created_at"`
 	CreatedAt int64  `gorm:"autoCreateTime" json:"created_at"`
 	UpdatedAt int64  `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
 	UpdatedAt int64  `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
-	NickName  string `json:"nick_name"` //custom name
-	Avatar    string `json:"avatar"`    //头像
-	Name      string `json:"name"`
+	NickName  string `json:"nick_name"`
+	Mark      string `json:"mark"`   //Remarks
+	Block     bool   `json:"block"`  //Disable or not
+	Avatar    string `json:"avatar"` //User avatar
 	Token     string `gorm:"column:token;primary_key" json:"token"`
 	Token     string `gorm:"column:token;primary_key" json:"token"`
-	Profile   string `json:"profile"`
+	Profile   string `json:"profile"` //Description
 	OnLine    bool   `json:"on_line" gorm:"-"`
 	OnLine    bool   `json:"on_line" gorm:"-"`
+	Version   int    `json:"version"`
 }
 }
 
 
 func (p *FriendModel) TableName() string {
 func (p *FriendModel) TableName() string {

+ 21 - 0
service/notify.go

@@ -18,6 +18,7 @@ type NotifyServer interface {
 	DelLog(id string)
 	DelLog(id string)
 	GetList(c int) (list []model.AppNotify)
 	GetList(c int) (list []model.AppNotify)
 	MarkRead(id string, state int)
 	MarkRead(id string, state int)
+	SendText(m model.AppNotify)
 }
 }
 
 
 type notifyServer struct {
 type notifyServer struct {
@@ -102,6 +103,26 @@ func SendMeg() {
 	//	}
 	//	}
 }
 }
 
 
+func (i notifyServer) SendText(m model.AppNotify) {
+	list := []model.AppNotify{}
+	list = append(list, m)
+	json, _ := json2.Marshal(list)
+	var temp []*websocket.Conn
+	for _, v := range WebSocketConns {
+
+		err := v.WriteMessage(1, json)
+		if err == nil {
+			temp = append(temp, v)
+		}
+	}
+	WebSocketConns = temp
+
+	if len(WebSocketConns) == 0 {
+		SocketRun = false
+	}
+
+}
+
 func NewNotifyService(db *gorm.DB) NotifyServer {
 func NewNotifyService(db *gorm.DB) NotifyServer {
 	return &notifyServer{db: db}
 	return &notifyServer{db: db}
 }
 }

+ 55 - 15
service/person.go

@@ -17,6 +17,7 @@ import (
 	"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
 	"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"
@@ -32,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) {
 
 
@@ -63,9 +65,16 @@ var StreamList map[string]quic.Stream
 var ServiceMessage chan model.MessageModel
 var ServiceMessage chan model.MessageModel
 
 
 func UDPService() {
 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: 9904}
+		IP: net.IPv4zero, Port: port}
 	var err error
 	var err error
 	UDPConn, err = net.ListenUDP("udp", srcAddr)
 	UDPConn, err = net.ListenUDP("udp", srcAddr)
 	if err != nil {
 	if err != nil {
@@ -146,6 +155,7 @@ func ProcessingContent(stream quic.Stream) {
 		prefixByte := make([]byte, 6)
 		prefixByte := make([]byte, 6)
 		_, err := io.ReadFull(stream, prefixByte)
 		_, err := io.ReadFull(stream, prefixByte)
 		if err != nil {
 		if err != nil {
+			fmt.Println(err)
 			return
 			return
 		}
 		}
 		prefixLength, err := strconv.Atoi(string(prefixByte))
 		prefixLength, err := strconv.Atoi(string(prefixByte))
@@ -166,14 +176,22 @@ func ProcessingContent(stream quic.Stream) {
 			//nothing
 			//nothing
 			continue
 			continue
 		} else if m.Type == types.PERSONDIRECTORY {
 		} else if m.Type == types.PERSONDIRECTORY {
+			friend := model2.FriendModel{}
+			friend.Token = m.From
 			var list []model.Path
 			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...)
+			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 {
 			} else {
-				list = MyService.ZiMa().GetDirPath(m.Data.(string))
+				list = []model.Path{}
 			}
 			}
 			m.To = m.From
 			m.To = m.From
 			m.Data = list
 			m.Data = list
@@ -185,6 +203,7 @@ func ProcessingContent(stream quic.Stream) {
 			SendFileData(stream, m.Data.(string), m.From, m.UUId)
 			SendFileData(stream, m.Data.(string), m.From, m.UUId)
 			break
 			break
 		} else if m.Type == types.PERSONADDFRIEND {
 		} else if m.Type == types.PERSONADDFRIEND {
+			fmt.Println("有用户来请求加好友", m)
 			friend := model2.FriendModel{}
 			friend := model2.FriendModel{}
 			dataModelByte, _ := json.Marshal(m.Data)
 			dataModelByte, _ := json.Marshal(m.Data)
 			err := json.Unmarshal(dataModelByte, &friend)
 			err := json.Unmarshal(dataModelByte, &friend)
@@ -196,7 +215,7 @@ func ProcessingContent(stream quic.Stream) {
 			mi := model2.FriendModel{}
 			mi := model2.FriendModel{}
 			mi.Avatar = config.UserInfo.Avatar
 			mi.Avatar = config.UserInfo.Avatar
 			mi.Profile = config.UserInfo.Description
 			mi.Profile = config.UserInfo.Description
-			mi.Name = config.UserInfo.NickName
+			mi.NickName = config.UserInfo.NickName
 			m.To = m.From
 			m.To = m.From
 			m.Data = mi
 			m.Data = mi
 			m.Type = types.PERSONADDFRIEND
 			m.Type = types.PERSONADDFRIEND
@@ -210,19 +229,34 @@ func ProcessingContent(stream quic.Stream) {
 			} else {
 			} else {
 				delete(UDPAddressMap, m.From)
 				delete(UDPAddressMap, m.From)
 			}
 			}
-			mi := model2.FriendModel{}
-			mi.Avatar = config.UserInfo.Avatar
-			mi.Profile = config.UserInfo.Description
-			mi.Name = config.UserInfo.NickName
-			mi.Token = config.ServerInfo.Token
+			// 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 := model.MessageModel{}
-			msg.Type = types.PERSONADDFRIEND
-			msg.Data = mi
+			msg.Type = types.PERSONHELLO
+			msg.Data = ""
 			msg.To = m.From
 			msg.To = m.From
 			msg.From = config.ServerInfo.Token
 			msg.From = config.ServerInfo.Token
 			msg.UUId = m.UUId
 			msg.UUId = m.UUId
 			Dial(msg, false)
 			Dial(msg, false)
 
 
+			break
+		} else if m.Type == types.PERSONCANCEL {
+			CancelList[m.UUId] = "cancel"
 			break
 			break
 		} else {
 		} else {
 			//不应有不做返回的数据
 			//不应有不做返回的数据
@@ -289,6 +323,9 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
 
 
 	bufferedReader := bufio.NewReader(f)
 	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{}
@@ -313,8 +350,11 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
 		prefixLength := file.PrefixLength(len(b))
 		prefixLength := file.PrefixLength(len(b))
 		dataLength := file.DataLength(len(buf[:n]))
 		dataLength := file.DataLength(len(buf[:n]))
 		data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...)
 		data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...)
+		if _, ok := CancelList[uuid]; ok {
+			delete(CancelList, uuid)
+			return nil
+		}
 		stream.Write(data)
 		stream.Write(data)
 	}
 	}
-	defer stream.Close()
 	return nil
 	return nil
 }
 }

+ 0 - 6
service/service.go

@@ -21,7 +21,6 @@ type Repository interface {
 	User() UserService
 	User() UserService
 	Docker() DockerService
 	Docker() DockerService
 	//Redis() RedisService
 	//Redis() RedisService
-	ZeroTier() ZeroTierService
 	ZiMa() ZiMaService
 	ZiMa() ZiMaService
 	Casa() CasaService
 	Casa() CasaService
 	Disk() DiskService
 	Disk() DiskService
@@ -45,7 +44,6 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
 		user:   NewUserService(),
 		user:   NewUserService(),
 		docker: NewDockerService(log),
 		docker: NewDockerService(log),
 		//redis:      NewRedisService(rp),
 		//redis:      NewRedisService(rp),
-		zerotier:       NewZeroTierService(),
 		zima:           NewZiMaService(),
 		zima:           NewZiMaService(),
 		casa:           NewCasaService(),
 		casa:           NewCasaService(),
 		disk:           NewDiskService(log, db),
 		disk:           NewDiskService(log, db),
@@ -68,7 +66,6 @@ type store struct {
 	ddns           DDNSService
 	ddns           DDNSService
 	user           UserService
 	user           UserService
 	docker         DockerService
 	docker         DockerService
-	zerotier       ZeroTierService
 	zima           ZiMaService
 	zima           ZiMaService
 	casa           CasaService
 	casa           CasaService
 	disk           DiskService
 	disk           DiskService
@@ -123,9 +120,6 @@ func (c *store) Docker() DockerService {
 	return c.docker
 	return c.docker
 }
 }
 
 
-func (c *store) ZeroTier() ZeroTierService {
-	return c.zerotier
-}
 func (c *store) ZiMa() ZiMaService {
 func (c *store) ZiMa() ZiMaService {
 	return c.zima
 	return c.zima
 }
 }

+ 16 - 0
service/system.go

@@ -18,6 +18,8 @@ type SystemService interface {
 	UpdateAssist()
 	UpdateAssist()
 	UpSystemPort(port string)
 	UpSystemPort(port string)
 	GetTimeZone() string
 	GetTimeZone() string
+	UpdateUSBAutoMount(state string)
+	ExecUSBAutoMountShell(state string)
 }
 }
 type systemService struct {
 type systemService struct {
 	log loger.OLog
 	log loger.OLog
@@ -37,6 +39,15 @@ func (s *systemService) GetTimeZone() string {
 	return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetTimeZone")
 	return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetTimeZone")
 }
 }
 
 
+func (s *systemService) ExecUSBAutoMountShell(state string) {
+	if state == "False" {
+		command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;USB_Remove_File")
+	} else {
+		command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;USB_Move_File")
+	}
+
+}
+
 func (s *systemService) GetSystemConfigDebug() []string {
 func (s *systemService) GetSystemConfigDebug() []string {
 	return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
 	return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
 }
 }
@@ -51,6 +62,11 @@ func (s *systemService) UpSystemConfig(str string, widget string) {
 	}
 	}
 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
 }
 }
+func (s *systemService) UpdateUSBAutoMount(state string) {
+	config.ServerInfo.USBAutoMount = state
+	config.Cfg.Section("system").Key("USBAutoMount").SetValue(state)
+	config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+}
 func (s *systemService) UpSystemPort(port string) {
 func (s *systemService) UpSystemPort(port string) {
 	if len(port) > 0 && port != config.ServerInfo.HttpPort {
 	if len(port) > 0 && port != config.ServerInfo.HttpPort {
 		config.Cfg.Section("server").Key("HttpPort").SetValue(port)
 		config.Cfg.Section("server").Key("HttpPort").SetValue(port)

+ 126 - 53
service/udpconn.go

@@ -10,6 +10,7 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"net"
 	"net"
 	"os"
 	"os"
+	path2 "path"
 	"strconv"
 	"strconv"
 	"time"
 	"time"
 
 
@@ -32,29 +33,52 @@ func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error)
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 	defer cancel()
 	Message = make(chan model.MessageModel)
 	Message = make(chan model.MessageModel)
-
+	_, port, err := net.SplitHostPort(UDPConn.LocalAddr().String())
+	if config.ServerInfo.UDPPort != port {
+		config.ServerInfo.UDPPort = port
+		config.Cfg.Section("server").Key("UDPPort").SetValue(port)
+		config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
+	}
+	p, err := strconv.Atoi(port)
 	srcAddr := &net.UDPAddr{
 	srcAddr := &net.UDPAddr{
-		IP: net.IPv4zero, Port: 9904} //注意端口必须固定
+		IP: net.IPv4zero, Port: p} //注意端口必须固定
 	addr := UDPAddressMap[msg.To]
 	addr := UDPAddressMap[msg.To]
-	ticker := msg.To
+	ticket := msg.To
 	if server {
 	if server {
 		addr = config.ServerInfo.Handshake + ":9527"
 		addr = config.ServerInfo.Handshake + ":9527"
-		ticker = "bench"
+		ticket = "bench"
 	}
 	}
 	dstAddr, err := net.ResolveUDPAddr("udp", addr)
 	dstAddr, err := net.ResolveUDPAddr("udp", addr)
 
 
 	//DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。
 	//DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。
 	//(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口
 	//(conn)UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口
 
 
-	session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticker), quic_helper.GetQUICConfig())
+	session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
 	if err != nil {
 	if err != nil {
-		go MyService.Casa().PushConnectionStatus(m.UUId, err.Error(), m.From, m.To, m.Type)
+		if msg.Type == types.PERSONDOWNLOAD {
+			task := MyService.Download().GetDownloadById(msg.UUId)
+			task.Error = err.Error()
+			task.State = types.DOWNLOADERROR
+			MyService.Download().SetDownloadError(task)
+		}
+		if config.SystemConfigInfo.Analyse != "False" {
+			go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
+		}
+
 		return m, err
 		return m, err
 	}
 	}
 
 
 	stream, err := session.OpenStreamSync(ctx)
 	stream, err := session.OpenStreamSync(ctx)
 	if err != nil {
 	if err != nil {
-		go MyService.Casa().PushConnectionStatus(m.UUId, err.Error(), m.From, m.To, m.Type)
+		if msg.Type == types.PERSONDOWNLOAD {
+			task := MyService.Download().GetDownloadById(msg.UUId)
+			task.Error = err.Error()
+			task.State = types.DOWNLOADERROR
+			MyService.Download().SetDownloadError(task)
+		}
+		if config.SystemConfigInfo.Analyse != "False" {
+			go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
+		}
 		session.CloseWithError(1, err.Error())
 		session.CloseWithError(1, err.Error())
 		return m, err
 		return m, err
 	}
 	}
@@ -66,7 +90,9 @@ func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error)
 	go ReadContent(stream)
 	go ReadContent(stream)
 	result := <-Message
 	result := <-Message
 	stream.Close()
 	stream.Close()
-	go MyService.Casa().PushConnectionStatus(m.UUId, "OK", m.From, m.To, m.Type)
+	if config.SystemConfigInfo.Analyse != "False" {
+		go MyService.Casa().PushConnectionStatus(msg.UUId, "OK", msg.From, msg.To, msg.Type)
+	}
 	return result, nil
 	return result, nil
 }
 }
 
 
@@ -88,8 +114,6 @@ func SendData(stream quic.Stream, m model.MessageModel) {
 	stream.Write(data)
 	stream.Write(data)
 }
 }
 
 
-var Summary map[string]model.FileSummaryModel
-
 //读取数据
 //读取数据
 func ReadContent(stream quic.Stream) {
 func ReadContent(stream quic.Stream) {
 	for {
 	for {
@@ -97,6 +121,12 @@ func ReadContent(stream quic.Stream) {
 		_, err := io.ReadFull(stream, prefixByte)
 		_, err := io.ReadFull(stream, prefixByte)
 		if err != nil {
 		if err != nil {
 			fmt.Println(err)
 			fmt.Println(err)
+			time.Sleep(time.Second * 1)
+			for k, v := range CancelList {
+				tempPath := config.AppInfo.RootPath + "/temp" + "/" + v
+				fmt.Println(file.RMDir(tempPath))
+				delete(CancelList, k)
+			}
 			break
 			break
 		}
 		}
 		prefixLength, err := strconv.Atoi(string(prefixByte))
 		prefixLength, err := strconv.Atoi(string(prefixByte))
@@ -112,12 +142,14 @@ func ReadContent(stream quic.Stream) {
 		}
 		}
 		m := model.MessageModel{}
 		m := model.MessageModel{}
 		err = json.Unmarshal(messageByte, &m)
 		err = json.Unmarshal(messageByte, &m)
+		fmt.Println("客户端", m)
 		if err != nil {
 		if err != nil {
 			fmt.Println(err)
 			fmt.Println(err)
 			break
 			break
 		}
 		}
 
 
 		if m.Type == types.PERSONDOWNLOAD {
 		if m.Type == types.PERSONDOWNLOAD {
+
 			dataModelByte, _ := json.Marshal(m.Data)
 			dataModelByte, _ := json.Marshal(m.Data)
 			dataModel := model.TranFileModel{}
 			dataModel := model.TranFileModel{}
 			err := json.Unmarshal(dataModelByte, &dataModel)
 			err := json.Unmarshal(dataModelByte, &dataModel)
@@ -149,29 +181,32 @@ func ReadContent(stream quic.Stream) {
 				fmt.Println("hash不匹配", hash, dataModel.Hash)
 				fmt.Println("hash不匹配", hash, dataModel.Hash)
 				continue
 				continue
 			}
 			}
-
 			tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
 			tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
 			file.IsNotExistMkDir(tempPath)
 			file.IsNotExistMkDir(tempPath)
 			filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
 			filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
-			tempFile, err := os.Stat(filepath)
+			_, err = os.Stat(filepath)
 
 
-			if os.IsNotExist(err) || tempFile.Size() == 0 {
+			if os.IsNotExist(err) {
 				err = ioutil.WriteFile(filepath, dataByte, 0644)
 				err = ioutil.WriteFile(filepath, dataByte, 0644)
-				task := model2.PersionDownloadDBModel{}
+				task := model2.PersonDownloadDBModel{}
 				task.UUID = m.UUId
 				task.UUID = m.UUId
-				task.Error = err.Error()
-				task.State = types.DOWNLOADERROR
-				MyService.Download().SetDownloadError(task)
+				if err != nil {
+					task.Error = err.Error()
+					task.State = types.DOWNLOADERROR
+					MyService.Download().SetDownloadError(task)
+				}
 
 
 			} else {
 			} else {
 				if file.GetHashByPath(filepath) != dataModel.Hash {
 				if file.GetHashByPath(filepath) != dataModel.Hash {
 					os.Remove(filepath)
 					os.Remove(filepath)
 					err = ioutil.WriteFile(filepath, dataByte, 0644)
 					err = ioutil.WriteFile(filepath, dataByte, 0644)
-					task := model2.PersionDownloadDBModel{}
+					task := model2.PersonDownloadDBModel{}
 					task.UUID = m.UUId
 					task.UUID = m.UUId
-					task.Error = err.Error()
-					task.State = types.DOWNLOADERROR
-					MyService.Download().SetDownloadError(task)
+					if err != nil {
+						task.Error = err.Error()
+						task.State = types.DOWNLOADERROR
+						MyService.Download().SetDownloadError(task)
+					}
 				}
 				}
 			}
 			}
 
 
@@ -181,21 +216,21 @@ func ReadContent(stream quic.Stream) {
 				continue
 				continue
 			}
 			}
 			if len(files) >= dataModel.Length {
 			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 {
+				summary := MyService.Download().GetDownloadById(m.UUId)
+				summary.State = types.DOWNLOADFINISH
+				MyService.Download().EditDownloadState(summary)
+				fullPath := file.GetNoDuplicateFileName(path2.Join(summary.LocalPath, summary.Name))
+				file.SpliceFiles(tempPath, fullPath, dataModel.Length, 0)
+				if file.GetHashByPath(fullPath) == summary.Hash {
 					file.RMDir(tempPath)
 					file.RMDir(tempPath)
-					task := model2.PersionDownloadDBModel{}
-					task.UUID = m.UUId
-					task.State = types.DOWNLOADFINISH
-					MyService.Download().EditDownloadState(task)
-					delete(Summary, m.UUId)
+					summary.State = types.DOWNLOADFINISHED
+					MyService.Download().EditDownloadState(summary)
 				} else {
 				} else {
 					os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
 					os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
-					task := model2.PersionDownloadDBModel{}
-					task.UUID = m.UUId
-					task.State = types.DOWNLOADERROR
-					MyService.Download().EditDownloadState(task)
+
+					summary.State = types.DOWNLOADERROR
+					summary.Error = "hash mismatch"
+					MyService.Download().SetDownloadError(summary)
 				}
 				}
 
 
 				break
 				break
@@ -205,42 +240,55 @@ func ReadContent(stream quic.Stream) {
 			dataModel := model.FileSummaryModel{}
 			dataModel := model.FileSummaryModel{}
 			dataModelByte, _ := json.Marshal(m.Data)
 			dataModelByte, _ := json.Marshal(m.Data)
 			err := json.Unmarshal(dataModelByte, &dataModel)
 			err := json.Unmarshal(dataModelByte, &dataModel)
-			fmt.Println(err)
+			if err != nil {
+				fmt.Println(err)
+			}
+
+			task := MyService.Download().GetDownloadById(m.UUId)
+			fullPath := path2.Join(task.LocalPath, task.Name)
+			task.State = types.DOWNLOADING
+			if len(dataModel.Message) > 0 {
+				task.State = types.DOWNLOADERROR
+				task.Error = dataModel.Message
+			}
+			if file.Exists(fullPath) && file.GetHashByPath(fullPath) == dataModel.Hash {
+				task.State = types.DOWNLOADFINISHED
+				go func(from, uuid string) {
+					m := model.MessageModel{}
+					m.Data = ""
+					m.From = config.ServerInfo.Token
+					m.To = from
+					m.Type = types.PERSONCANCEL
+					m.UUId = uuid
+					CancelList[uuid] = uuid
+					Dial(m, false)
+				}(task.From, task.UUID)
 
 
-			task := model2.PersionDownloadDBModel{}
+			}
 			task.UUID = m.UUId
 			task.UUID = m.UUId
 			task.Name = dataModel.Name
 			task.Name = dataModel.Name
 			task.Length = dataModel.Length
 			task.Length = dataModel.Length
 			task.Size = dataModel.Size
 			task.Size = dataModel.Size
-			task.State = types.DOWNLOADING
 			task.BlockSize = dataModel.BlockSize
 			task.BlockSize = dataModel.BlockSize
 			task.Hash = dataModel.Hash
 			task.Hash = dataModel.Hash
 			task.Type = 0
 			task.Type = 0
 			task.From = m.From
 			task.From = m.From
-			if len(dataModel.Message) > 0 {
-				task.State = types.DOWNLOADERROR
-				task.Error = dataModel.Message
-			}
-
 			MyService.Download().SaveDownload(task)
 			MyService.Download().SaveDownload(task)
 
 
-			Summary[m.UUId] = dataModel
-
 		} else if m.Type == types.PERSONCONNECTION {
 		} else if m.Type == types.PERSONCONNECTION {
-
 			if len(m.Data.(string)) > 0 {
 			if len(m.Data.(string)) > 0 {
 				UDPAddressMap[m.From] = m.Data.(string)
 				UDPAddressMap[m.From] = m.Data.(string)
 			} else {
 			} else {
 				delete(UDPAddressMap, m.From)
 				delete(UDPAddressMap, m.From)
 			}
 			}
-			mi := model2.FriendModel{}
-			mi.Avatar = config.UserInfo.Avatar
-			mi.Profile = config.UserInfo.Description
-			mi.Name = config.UserInfo.NickName
-			mi.Token = config.ServerInfo.Token
+			// mi := model2.FriendModel{}
+			// mi.Avatar = config.UserInfo.Avatar
+			// mi.Profile = config.UserInfo.Description
+			// mi.NickName = config.UserInfo.NickName
+			// mi.Token = config.ServerInfo.Token
 			msg := model.MessageModel{}
 			msg := model.MessageModel{}
-			msg.Type = types.PERSONADDFRIEND
-			msg.Data = mi
+			msg.Type = types.PERSONHELLO
+			msg.Data = ""
 			msg.To = m.From
 			msg.To = m.From
 			msg.From = config.ServerInfo.Token
 			msg.From = config.ServerInfo.Token
 			msg.UUId = m.UUId
 			msg.UUId = m.UUId
@@ -248,10 +296,21 @@ func ReadContent(stream quic.Stream) {
 			Message <- m
 			Message <- m
 			break
 			break
 		} else if m.Type == "get_ip" {
 		} else if m.Type == "get_ip" {
+			notify := model2.AppNotify{}
+			notify.CustomId = m.From
 			if len(m.Data.(string)) == 0 {
 			if len(m.Data.(string)) == 0 {
+				if _, ok := UDPAddressMap[m.From]; ok {
+					notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LEAVE
+					go MyService.Notify().SendText(notify)
+				}
 				delete(UDPAddressMap, m.From)
 				delete(UDPAddressMap, m.From)
+				Message <- m
 				break
 				break
 			}
 			}
+			if _, ok := UDPAddressMap[m.From]; !ok {
+				notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LIVE
+				go MyService.Notify().SendText(notify)
+			}
 			UDPAddressMap[m.From] = m.Data.(string)
 			UDPAddressMap[m.From] = m.Data.(string)
 			Message <- m
 			Message <- m
 			break
 			break
@@ -264,7 +323,7 @@ func ReadContent(stream quic.Stream) {
 
 
 func SendIPToServer() {
 func SendIPToServer() {
 	msg := model.MessageModel{}
 	msg := model.MessageModel{}
-	msg.Type = "hello"
+	msg.Type = types.PERSONHELLO
 	msg.Data = ""
 	msg.Data = ""
 	msg.From = config.ServerInfo.Token
 	msg.From = config.ServerInfo.Token
 	msg.To = config.ServerInfo.Token
 	msg.To = config.ServerInfo.Token
@@ -282,9 +341,10 @@ func LoopFriend() {
 		msg.From = config.ServerInfo.Token
 		msg.From = config.ServerInfo.Token
 		msg.To = list[i].Token
 		msg.To = list[i].Token
 		msg.UUId = uuid.NewV4().String()
 		msg.UUId = uuid.NewV4().String()
+
 		Dial(msg, true)
 		Dial(msg, true)
 
 
-		msg.Type = "hello"
+		msg.Type = types.PERSONHELLO
 		msg.Data = ""
 		msg.Data = ""
 		msg.From = config.ServerInfo.Token
 		msg.From = config.ServerInfo.Token
 		msg.To = list[i].Token
 		msg.To = list[i].Token
@@ -292,6 +352,19 @@ func LoopFriend() {
 		if _, ok := UDPAddressMap[list[i].Token]; ok {
 		if _, ok := UDPAddressMap[list[i].Token]; ok {
 			go Dial(msg, false)
 			go Dial(msg, false)
 		}
 		}
+		go func(shareId string) {
+			user := MyService.Casa().GetUserInfoByShareId(shareId)
+			m := model2.FriendModel{}
+			m.Token = shareId
+			friend := MyService.Friend().GetFriendById(m)
+			if friend.Version != user.Version {
+				friend.Avatar = user.Avatar
+				friend.NickName = user.NickName
+				friend.Profile = user.Desc
+				friend.Version = user.Version
+				MyService.Friend().UpdateOrCreate(friend)
+			}
+		}(list[i].Token)
 
 
 	}
 	}
 }
 }

+ 0 - 353
service/zerotier.go

@@ -1,353 +0,0 @@
-package service
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"math/rand"
-	"net/http"
-	"strconv"
-	"strings"
-	"time"
-	"unicode"
-
-	"github.com/IceWhaleTech/CasaOS/pkg/config"
-	command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
-	httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
-	"github.com/IceWhaleTech/CasaOS/pkg/zerotier"
-	"github.com/PuerkitoBio/goquery"
-	"github.com/tidwall/gjson"
-)
-
-type ZeroTierService interface {
-	GetToken(username, pwd string) string
-	ZeroTierRegister(email, lastName, firstName, password string) string
-	ZeroTierNetworkList(token string) (interface{}, []string)
-	ZeroTierJoinNetwork(networkId string)
-	ZeroTierLeaveNetwork(networkId string)
-	ZeroTierGetInfo(token, id string) (interface{}, []string)
-	ZeroTierGetStatus(token string) interface{}
-	EditNetwork(token string, data string, id string) interface{}
-	CreateNetwork(token string) interface{}
-	MemberList(token string, id string) interface{}
-	EditNetworkMember(token string, data string, id, mId string) interface{}
-	DeleteMember(token string, id, mId string) interface{}
-	DeleteNetwork(token, id string) interface{}
-	GetJoinNetworks() string
-	NetworkIdFilter(letter rune) bool
-}
-type zerotierStruct struct {
-}
-
-var client http.Client
-
-func (c *zerotierStruct) ZeroTierJoinNetwork(networkId string) {
-	command2.OnlyExec(`zerotier-cli join ` + networkId)
-}
-func (c *zerotierStruct) ZeroTierLeaveNetwork(networkId string) {
-	command2.OnlyExec(`zerotier-cli leave ` + networkId)
-}
-
-//登录并获取token
-func (c *zerotierStruct) GetToken(username, pwd string) string {
-	if len(config.ZeroTierInfo.Token) > 0 {
-		return config.ZeroTierInfo.Token
-	} else {
-		return LoginGetToken(username, pwd)
-	}
-}
-
-func (c *zerotierStruct) ZeroTierRegister(email, lastName, firstName, password string) string {
-
-	url := "https://accounts.zerotier.com/auth/realms/zerotier/protocol/openid-connect/registrations?client_id=zt-central&redirect_uri=https%3A%2F%2Fmy.zerotier.com%2Fapi%2F_auth%2Foidc%2Fcallback&response_type=code&scope=openid+profile+email+offline_access&state=state"
-
-	action, cookies, _ := ZeroTierGet(url, nil, 4)
-	var buff bytes.Buffer
-	buff.WriteString("email=")
-	buff.WriteString(email)
-	buff.WriteString("&password=")
-	buff.WriteString(password)
-	buff.WriteString("&password-confirm=")
-	buff.WriteString(password)
-	buff.WriteString("&user.attributes.marketingOptIn=true")
-	buff.WriteString("&firstName")
-	buff.WriteString(firstName)
-	buff.WriteString("&lastName")
-	buff.WriteString(lastName)
-
-	action, errInfo, _ := ZeroTierPost(buff, action, cookies, false)
-	if len(errInfo) > 0 {
-		return errInfo
-	}
-	action, _, _ = ZeroTierGet(action, cookies, 5)
-	return ""
-}
-
-//固定请求head
-func GetHead() map[string]string {
-	var head = make(map[string]string, 4)
-	head["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
-	head["Accept-Language"] = "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"
-	head["Connection"] = "keep-alive"
-	head["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
-	return head
-}
-
-//登录并获取token,会出现账号密码错误,和邮箱未验证情况,目前未出现其他情况
-func LoginGetToken(username, pwd string) string {
-	//拿到登录的action
-	var loginUrl = "https://accounts.zerotier.com/auth/realms/zerotier/protocol/openid-connect/auth?client_id=zt-central&redirect_uri=https%3A%2F%2Fmy.zerotier.com%2Fapi%2F_auth%2Foidc%2Fcallback&response_type=code&scope=openid+profile+email+offline_access&state=states"
-	action, cookies, _ := ZeroTierGet(loginUrl, nil, 1)
-	if len(action) == 0 {
-		//没有拿到action,页面结构变了
-		return ""
-	}
-	//登录
-	var str bytes.Buffer
-	str.WriteString("username=")
-	str.WriteString(username)
-	str.WriteString("&password=")
-	str.WriteString(pwd)
-	str.WriteString("&credentialId=&login=Log+In")
-	url, logingErrInfo, _ := ZeroTierPost(str, action, cookies, true)
-
-	action, cookies, isLoginOk := ZeroTierGet(url, cookies, 2)
-
-	if isLoginOk {
-		//登录成功,可以继续调用api
-		randomTokenUrl := "https://my.zerotier.com/api/randomToken"
-		json, _, _ := ZeroTierGet(randomTokenUrl, cookies, 3)
-		//获取一个随机token
-		token := gjson.Get(json, "token")
-
-		userInfoUrl := "https://my.zerotier.com/api/status"
-		json, _, _ = ZeroTierGet(userInfoUrl, cookies, 3)
-		//拿到用户id
-		userId := gjson.Get(json, "user.id")
-
-		//设置新token
-		addTokenUrl := "https://my.zerotier.com/api/user/" + userId.String() + "/token"
-		data := make(map[string]string)
-		rand.Seed(time.Now().UnixNano())
-		data["tokenName"] = "oasis-token-" + strconv.Itoa(rand.Intn(1000))
-		data["token"] = token.String()
-		head := make(map[string]string)
-		head["Content-Type"] = "application/json"
-		_, statusCode := httper2.ZeroTierPost(addTokenUrl, data, head, cookies)
-		if statusCode == http.StatusOK {
-			config.Cfg.Section("zerotier").Key("Token").SetValue(token.String())
-			config.Cfg.SaveTo("conf/conf.ini")
-			config.ZeroTierInfo.Token = token.String()
-		}
-	} else {
-		//登录错误信息
-		if len(logingErrInfo) > 0 {
-			return logingErrInfo
-		} else {
-			//验证邮箱
-			action, _, _ = ZeroTierGet(url, cookies, 5)
-			return "You need to verify your email address to activate your account."
-		}
-	}
-	return ""
-}
-
-// t 1:获取action,2:登录成功后拿session(可能需要验证有了或登录失败) 3:随机生成token 4:注册页面拿action  5:注册成功后拿验证邮箱的地址
-func ZeroTierGet(url string, cookies []*http.Cookie, t uint8) (action string, c []*http.Cookie, isExistSession bool) {
-	isExistSession = false
-	action = ""
-	c = []*http.Cookie{}
-	request, _ := http.NewRequest(http.MethodGet, url, nil)
-	for k, v := range GetHead() {
-		request.Header.Add(k, v)
-	}
-	for _, cookie := range cookies {
-		request.AddCookie(cookie)
-	}
-	resp, err := client.Do(request)
-	if err != nil {
-		return
-	}
-	defer resp.Body.Close()
-	c = resp.Cookies()
-	if t == 1 {
-		doc, err := goquery.NewDocumentFromReader(resp.Body)
-		if err != nil {
-			return
-		}
-		action, _ = doc.Find("#kc-form-login").Attr("action")
-		return
-	} else if t == 2 {
-		for _, cookie := range resp.Cookies() {
-			if cookie.Name == "pgx-session" {
-				isExistSession = true
-				break
-			}
-		}
-		//判断是否登录成功,如果需要验证邮箱,则返回验证邮箱的地址。
-		if resp.StatusCode == http.StatusFound && len(resp.Header.Get("Location")) > 0 {
-			action = resp.Header.Get("Location")
-		}
-		return
-	} else if t == 3 {
-		//返回获取到的字符串
-		byteArr, _ := ioutil.ReadAll(resp.Body)
-		action = string(byteArr)
-	} else if t == 4 {
-		doc, err := goquery.NewDocumentFromReader(resp.Body)
-		if err != nil {
-			return
-		}
-		action, _ = doc.Find("#kc-register-form").Attr("action")
-		return
-
-	} else if t == 5 {
-		doc, _ := goquery.NewDocumentFromReader(resp.Body)
-		fmt.Println(doc.Html())
-		action, _ = doc.Find("#kc-info-wrapper a").Attr("href")
-		return
-	}
-
-	return
-}
-
-//模拟提交表单
-func ZeroTierPost(str bytes.Buffer, action string, cookies []*http.Cookie, isLogin bool) (url, errInfo string, err error) {
-	req, err := http.NewRequest(http.MethodPost, action, strings.NewReader(str.String()))
-	if err != nil {
-		return "", "", errors.New("newrequest error")
-	}
-	for k, v := range GetHead() {
-		req.Header.Set(k, v)
-	}
-	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-	for _, cookie := range cookies {
-		req.AddCookie(cookie)
-	}
-	res, err := client.Do(req)
-	defer res.Body.Close()
-	if err != nil {
-		return "", "", errors.New("request error")
-	}
-	if !isLogin {
-		//注册成功
-		if res.StatusCode == http.StatusFound && len(res.Header.Get("Location")) > 0 {
-			return res.Header.Get("Location"), "", nil
-		} else {
-			register, _ := goquery.NewDocumentFromReader(res.Body)
-			firstErr := strings.TrimSpace(register.Find("#input-error-firstname").Text())
-			lastErr := strings.TrimSpace(register.Find("#input-error-lastname").Text())
-			emailErr := strings.TrimSpace(register.Find("#input-error-email").Text())
-			pwdErr := strings.TrimSpace(register.Find("#input-error-password").Text())
-			var errD strings.Builder
-			if len(firstErr) > 0 {
-				errD.WriteString(firstErr + ",")
-			}
-			if len(lastErr) > 0 {
-				errD.WriteString(lastErr + ",")
-			}
-			if len(emailErr) > 0 {
-				errD.WriteString(emailErr + ",")
-			}
-			if len(pwdErr) > 0 {
-				errD.WriteString(pwdErr + ",")
-			}
-			return "", errD.String(), nil
-		}
-
-	} else {
-		if res.StatusCode == http.StatusFound && len(res.Header.Get("Location")) > 0 {
-			return res.Header.Get("Location"), "", nil
-		}
-		doc, err := goquery.NewDocumentFromReader(res.Body)
-		if err != nil {
-			return "", "", errors.New("request error")
-		}
-
-		errDesc := doc.Find("#input-error").Text()
-		if len(errDesc) > 0 {
-			return "", strings.TrimSpace(errDesc), nil
-		}
-
-	}
-
-	return "", "", nil
-}
-
-//获取zerotile网络列表和本地用户已加入的网络
-func (c *zerotierStruct) ZeroTierNetworkList(token string) (interface{}, []string) {
-	url := "https://my.zerotier.com/api/network"
-	return zerotier.GetData(url, token), command2.ExecResultStrArray(`zerotier-cli listnetworks | awk 'NR>1 {print $3} {line=$0}'`)
-}
-
-// get network info
-func (c *zerotierStruct) ZeroTierGetInfo(token, id string) (interface{}, []string) {
-	url := "https://my.zerotier.com/api/network/" + id
-	info := zerotier.GetData(url, token)
-	return info, command2.ExecResultStrArray(`zerotier-cli listnetworks | awk 'NR>1 {print $3} {line=$0}'`)
-}
-
-//get status
-func (c *zerotierStruct) ZeroTierGetStatus(token string) interface{} {
-	url := "https://my.zerotier.com/api/v1/status"
-	info := zerotier.GetData(url, token)
-	return info
-}
-
-func (c *zerotierStruct) EditNetwork(token string, data string, id string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network/" + id
-	info := zerotier.PostData(url, token, data)
-	return info
-}
-
-func (c *zerotierStruct) EditNetworkMember(token string, data string, id, mId string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network/" + id + "/member/" + mId
-	info := zerotier.PostData(url, token, data)
-	return info
-}
-
-func (c *zerotierStruct) MemberList(token string, id string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network/" + id + "/member"
-	info := zerotier.GetData(url, token)
-	return info
-}
-
-func (c *zerotierStruct) DeleteMember(token string, id, mId string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network/" + id + "/member/" + mId
-	info := zerotier.DeleteMember(url, token)
-	return info
-}
-
-func (c *zerotierStruct) DeleteNetwork(token, id string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network/" + id
-	info := zerotier.DeleteMember(url, token)
-	return info
-}
-
-func (c *zerotierStruct) CreateNetwork(token string) interface{} {
-	url := "https://my.zerotier.com/api/v1/network"
-	info := zerotier.PostData(url, token, "{}")
-	return info
-}
-
-func (c *zerotierStruct) GetJoinNetworks() string {
-	json := command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetLocalJoinNetworks")
-	return json
-}
-
-func (c *zerotierStruct) NetworkIdFilter(letter rune) bool {
-	if unicode.IsNumber(letter) || unicode.IsLetter(letter) {
-		return true
-	} else {
-		return false
-	}
-}
-func NewZeroTierService() ZeroTierService {
-	//初始化client
-	client = http.Client{Timeout: 30 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {
-		return http.ErrUseLastResponse //禁止重定向
-	},
-	}
-	return &zerotierStruct{}
-}

+ 69 - 2
service/zima_info.go

@@ -4,10 +4,12 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
+	"path/filepath"
 	"runtime"
 	"runtime"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
+	"unsafe"
 
 
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/model"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
 	"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -32,12 +34,15 @@ type ZiMaService interface {
 	GetNetState(name string) string
 	GetNetState(name string) string
 	GetSysInfo() host.InfoStat
 	GetSysInfo() host.InfoStat
 	GetDirPath(path string) []model.Path
 	GetDirPath(path string) []model.Path
+	GetDirPathOne(path string) (m model.Path)
 	MkdirAll(path string) (int, error)
 	MkdirAll(path string) (int, error)
 	CreateFile(path string) (int, error)
 	CreateFile(path string) (int, error)
 	RenameFile(oldF, newF string) (int, error)
 	RenameFile(oldF, newF string) (int, error)
 	GetCpuInfo() []cpu.InfoStat
 	GetCpuInfo() []cpu.InfoStat
 }
 }
 
 
+var NetArray [][]model.IOCountersStat
+
 type zima struct {
 type zima struct {
 }
 }
 
 
@@ -84,10 +89,19 @@ func (c *zima) GetDirPath(path string) []model.Path {
 
 
 	ls, _ := ioutil.ReadDir(path)
 	ls, _ := ioutil.ReadDir(path)
 	dirs := []model.Path{}
 	dirs := []model.Path{}
-
 	if len(path) > 0 {
 	if len(path) > 0 {
 		for _, l := range ls {
 		for _, l := range ls {
-			dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir(), Date: l.ModTime(), Size: l.Size()})
+			filePath := filepath.Join(path, l.Name())
+			link, err := filepath.EvalSymlinks(filePath)
+			if err != nil {
+				link = filePath
+			}
+			temp := model.Path{Name: l.Name(), Path: filePath, IsDir: l.IsDir(), Date: l.ModTime(), Size: l.Size()}
+			if filePath != link {
+				file, _ := os.Stat(link)
+				temp.IsDir = file.IsDir()
+			}
+			dirs = append(dirs, temp)
 		}
 		}
 	} else {
 	} else {
 		dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
 		dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
@@ -95,6 +109,21 @@ func (c *zima) GetDirPath(path string) []model.Path {
 	return dirs
 	return dirs
 }
 }
 
 
+func (c *zima) GetDirPathOne(path string) (m model.Path) {
+
+	f, err := os.Stat(path)
+
+	if err != nil {
+		return
+	}
+	m.IsDir = f.IsDir()
+	m.Name = f.Name()
+	m.Path = path
+	m.Size = f.Size()
+	m.Date = f.ModTime()
+	return
+}
+
 //获取系统信息
 //获取系统信息
 func (c *zima) GetSysInfo() host.InfoStat {
 func (c *zima) GetSysInfo() host.InfoStat {
 	info, _ := host.Info()
 	info, _ := host.Info()
@@ -174,3 +203,41 @@ func (c *zima) RenameFile(oldF, newF string) (int, error) {
 func NewZiMaService() ZiMaService {
 func NewZiMaService() ZiMaService {
 	return &zima{}
 	return &zima{}
 }
 }
+
+func LoopNet() {
+	netList := MyService.ZiMa().GetNetInfo()
+
+	nets := MyService.ZiMa().GetNet(true)
+	num := 0
+	for i := 0; i < len(netList); i++ {
+
+		for _, netCardName := range nets {
+
+			if netList[i].Name == netCardName {
+				var netArray []model.IOCountersStat
+				if len(NetArray) < (num + 1) {
+					netArray = []model.IOCountersStat{}
+				} else {
+					netArray = NetArray[num]
+				}
+				item := *(*model.IOCountersStat)(unsafe.Pointer(&netList[i]))
+				item.State = strings.TrimSpace(MyService.ZiMa().GetNetState(netList[i].Name))
+				item.Time = time.Now().Unix()
+
+				if len(netArray) >= 60 {
+					netArray = netArray[1:]
+				}
+				netArray = append(netArray, item)
+				if len(NetArray) < (num + 1) {
+					NetArray = append(NetArray, []model.IOCountersStat{})
+				}
+
+				NetArray[num] = netArray
+
+				num++
+				break
+			}
+		}
+
+	}
+}

+ 5 - 10
shell/assist.sh

@@ -1,13 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-#add in v0.2.3
-version_0_2_3() {
-  ((EUID)) && sudo_cmd="sudo"
-  $sudo_cmd cp -rf /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/
-  $sudo_cmd chmod +x /casaOS/server/shell/usb-mount.sh
-  $sudo_cmd cp -rf /casaOS/server/shell/usb-mount@.service /etc/systemd/system/
 
 
-}
 
 
 # add in v0.2.5
 # add in v0.2.5
 
 
@@ -16,7 +9,9 @@ readonly CASA_DEPANDS="curl smartmontools parted fdisk ntfs-3g"
 version_0_2_5() {
 version_0_2_5() {
   install_depends "$CASA_DEPANDS"
   install_depends "$CASA_DEPANDS"
 }
 }
-
+version_0_2_11() {
+  sysctl -w net.core.rmem_max=2500000
+}
 
 
 #Install Depends
 #Install Depends
 install_depends() {
 install_depends() {
@@ -35,6 +30,6 @@ install_depends() {
     fi
     fi
 }
 }
 
 
-version_0_2_3
-
 version_0_2_5
 version_0_2_5
+
+version_0_2_11

+ 18 - 1
shell/helper.sh

@@ -245,9 +245,13 @@ do_umount() {
   if [[ -z ${MOUNT_POINT} ]]; then
   if [[ -z ${MOUNT_POINT} ]]; then
     ${log} "Warning: ${DEVICE} is not mounted"
     ${log} "Warning: ${DEVICE} is not mounted"
   else
   else
+    /bin/kill -9 $(lsof ${MOUNT_POINT})
     umount -l ${DEVICE}
     umount -l ${DEVICE}
     ${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
     ${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
-    /bin/rmdir "${MOUNT_POINT}"
+    if [ "`ls -A ${MOUNT_POINT}`" = "" ]; then
+      /bin/rm -fr "${MOUNT_POINT}"
+    fi
+    
     sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
     sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
   fi
   fi
 
 
@@ -325,3 +329,16 @@ TarFolder() {
   #查看固定文件夹大小
   #查看固定文件夹大小
   du -sh /DATA
   du -sh /DATA
 }
 }
+
+USB_Move_File() {
+  ((EUID)) && sudo_cmd="sudo"
+  $sudo_cmd cp -rf /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/
+  $sudo_cmd chmod +x /casaOS/server/shell/usb-mount.sh
+  $sudo_cmd cp -rf /casaOS/server/shell/usb-mount@.service /etc/systemd/system/
+}
+
+USB_Remove_File() {
+  ((EUID)) && sudo_cmd="sudo"
+  $sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules
+  $sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service
+}

+ 5 - 2
shell/usb-mount.sh

@@ -12,7 +12,7 @@ DEVBASE=$2
 DEVICE="/dev/${DEVBASE}"
 DEVICE="/dev/${DEVBASE}"
 
 
 # See if this drive is already mounted, and if so where
 # See if this drive is already mounted, and if so where
-MOUNT_POINT=$(lsblk -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
+MOUNT_POINT=$(lsblk -l -p -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
 
 
 do_mount() {
 do_mount() {
 
 
@@ -112,9 +112,12 @@ do_umount() {
   if [[ -z ${MOUNT_POINT} ]]; then
   if [[ -z ${MOUNT_POINT} ]]; then
     ${log} "Warning: ${DEVICE} is not mounted"
     ${log} "Warning: ${DEVICE} is not mounted"
   else
   else
+    #/bin/kill -9 $(lsof ${MOUNT_POINT})
     umount -l ${DEVICE}
     umount -l ${DEVICE}
     ${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
     ${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
-    /bin/rmdir "${MOUNT_POINT}"
+    if [ "`ls -A ${MOUNT_POINT}`" = "" ]; then
+      /bin/rm -fr "${MOUNT_POINT}"
+    fi
     sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
     sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
   fi
   fi
 
 

+ 2 - 0
types/notify.go

@@ -10,6 +10,8 @@ const (
 	NOTIFY_TYPE_NEED_CONFIRM
 	NOTIFY_TYPE_NEED_CONFIRM
 	NOTIFY_TYPE_ERROR
 	NOTIFY_TYPE_ERROR
 	NOTIFY_TYPE_INSTALL_LOG
 	NOTIFY_TYPE_INSTALL_LOG
+	NOTIFY_TYPE_PERSION_FIRNED_LEAVE
+	NOTIFY_TYPE_PERSION_FIRNED_LIVE
 )
 )
 
 
 const (
 const (

+ 1 - 0
types/persion.go → types/person.go

@@ -6,3 +6,4 @@ const PERSONSUMMARY = "summary"
 const PERSONCONNECTION = "connection"
 const PERSONCONNECTION = "connection"
 const PERSONDIRECTORY = "directory"
 const PERSONDIRECTORY = "directory"
 const PERSONHELLO = "hello"
 const PERSONHELLO = "hello"
+const PERSONCANCEL = "cancel" // Cancel Download

+ 1 - 0
types/persion_download.go → types/person_download.go

@@ -6,4 +6,5 @@ const (
 	DOWNLOADPAUSE
 	DOWNLOADPAUSE
 	DOWNLOADFINISH
 	DOWNLOADFINISH
 	DOWNLOADERROR
 	DOWNLOADERROR
+	DOWNLOADFINISHED
 )
 )

+ 2 - 2
types/system.go

@@ -1,5 +1,5 @@
 package types
 package types
 
 
-const CURRENTVERSION = "0.2.10"
+const CURRENTVERSION = "0.3.0"
 
 
-const BODY = "<li>Added CasaOS own file manager</li><li>Fixed the problem of failed to create storage space</li>"
+const BODY = "<li>Add CasaConnect function, now you can share private files peer-to-peer with your friends.</li><li>Add a widget for network traffic monitoring</li><li>Updated the initial directory of Files to the Root directory</li><li>Fix the application ipv6 opening problem</li>"

BIN
web/img/1-small.1b74d2ba.png


+ 55 - 0
web/img/folder-publicshare.0219e0d4.svg

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+  <linearGradient id="linearGradient1911" x1="25.085" x2="25.085" y1="24.031" y2="26.412" gradientTransform="translate(-35.822,-21.385)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#fcbc19" stop-opacity=".99608" offset="0"/>
+   <stop stop-color="#f4b61f" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient4625" x1=".52918" x2="16.404" y1="5.0665" y2="5.0665" gradientTransform="translate(-17.925)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#b78815" offset="0"/>
+   <stop stop-color="#e2b24b" stop-opacity="0" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient1951" x1="100" x2="133.19" y1="17.453" y2="51.606" gradientTransform="matrix(.26458 0 0 .26458 -38.033 -.13539)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#fce798" offset="0"/>
+   <stop stop-color="#ffc937" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient11110" x1=".52917" x2="16.404" y1="5.3815" y2="5.3815" gradientTransform="translate(-17.925)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#fff" offset="0"/>
+   <stop stop-color="#fff" stop-opacity="0" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient1119" x1="8.4665" x2="8.4665" y1="6.0853" y2="9.4879" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#fddb7a" offset="0"/>
+   <stop stop-color="#ffd970" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient1284" x1="8.4665" x2="8.4665" y1="10.26" y2="13.229" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#ffd96e" offset="0"/>
+   <stop stop-color="#ffd561" offset="1"/>
+  </linearGradient>
+  <linearGradient id="linearGradient1272" x1="-3.9033" x2="-3.9033" y1="7.7839" y2="15.613" gradientTransform="translate(12.362 -2.1249)" gradientUnits="userSpaceOnUse">
+   <stop stop-color="#c68d00" offset="0"/>
+   <stop stop-color="#a67100" offset="1"/>
+  </linearGradient>
+ </defs>
+ <metadata>
+  <rdf:RDF>
+   <cc:Work rdf:about="">
+    <dc:format>image/svg+xml</dc:format>
+    <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+   </cc:Work>
+  </rdf:RDF>
+ </metadata>
+ <g transform="translate(17.925 4.2e-5)">
+  <path d="m-16.728 2.2489c-0.3653 0-0.66145 0.32575-0.66145 0.72759v2.9636c-0.0026 0.02629-0.0072 0.052-0.0072 0.07906v7.9373c0 0.40184 0.29614 0.72759 0.66144 0.72759h14.552c0.36531 0 0.66144-0.32575 0.66144-0.72759v-9.393c0-0.40184-0.29614-0.72759-0.66144-0.72759v5.16e-4h-8.1993l-0.89864-1.1095s-0.36607-0.478-1.0583-0.478h-1.3229z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="url(#linearGradient1911)" image-rendering="auto" shape-rendering="auto" solid-color="#000000" stop-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;font-variation-settings:normal;inline-size:0;isolation:auto;mix-blend-mode:normal;shape-margin:0;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
+  <path d="m-9.5646 3.8364c-0.11312 0.0018-0.30848-0.01542-0.51986 0.09508-0.73647 0.37946-0.77226 0.59366-1.557 0.71415h-4.9608c-0.21986 0-0.41824 0.08855-0.56171 0.23202-0.13937 0.13936-0.22041 0.33333-0.2253 0.54569v0.2775c0.0049-0.21236 0.08593-0.40633 0.2253-0.54569 0.14347-0.14347 0.34185-0.23202 0.56171-0.23202h4.9608c0.78472-0.1205 0.82051-0.33469 1.557-0.71415 0.21138-0.1105 0.40673-0.09328 0.51986-0.09508h7.3828c0.18216 3.65e-4 0.3472 0.08101 0.46663 0.21239 0.1197 0.13167 0.19378 0.31377 0.19378 0.51469v-0.2775c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11943-0.13137-0.28447-0.21202-0.46663-0.21239h-1.1652zm-7.8247 2.1037c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v0.2775c0-0.02705 0.0041-0.05277 0.0067-0.07906z" fill="url(#linearGradient4625)" opacity=".001" stroke-width=".26458"/>
+  <path d="m-17.396 13.674v0.28215c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-0.28215c0 0.20092-0.07409 0.3825-0.19378 0.51417-0.1197 0.13167-0.28501 0.21342-0.46766 0.21342h-14.552c-0.18265 0-0.34848-0.08176-0.46818-0.21342s-0.19327-0.31325-0.19327-0.51417z" fill="#e4a729" fill-opacity=".99608" stroke-width=".26458"/>
+  <path d="m-10.383 4.0979s-0.35919 0.47868-1.1575 0.79218c-0.03271 0.00587-0.06509 0.011575-0.10077 0.017052h-4.9608c-0.21986 0-0.41824 0.088552-0.56171 0.23202-0.13937 0.13936-0.22042 0.33333-0.2253 0.54569v0.51675c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v7.3953c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-8.851c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11945-0.13137-0.28449-0.21202-0.46665-0.21239h-7.4821z" fill="url(#linearGradient1951)"/>
+  <path d="m-10.383 4.0979s-0.35919 0.47868-1.1575 0.79218c-0.03271 0.00587-0.06509 0.011575-0.10077 0.017052h-4.9608c-0.21986 0-0.41824 0.088552-0.56171 0.23202-0.13937 0.13936-0.22041 0.33333-0.2253 0.54569v0.38446c0.0049-0.21236 0.08593-0.40633 0.2253-0.54569 0.14347-0.14347 0.34185-0.23202 0.56171-0.23202h4.9608c0.03568-0.00548 0.06806-0.011184 0.10077-0.017052 0.75911-0.26303 1.2883-0.79218 1.2883-0.79218h8.0707c0.18216 3.704e-4 0.34718 0.081016 0.46663 0.21239 0.1197 0.13167 0.19378 0.31377 0.19378 0.51469v-0.38446c0-0.20092-0.07408-0.38302-0.19378-0.51469-0.11945-0.13137-0.28447-0.21202-0.46663-0.21239h-7.4821zm-7.0062 2.1037c-0.0026 0.02629-0.0067 0.05201-0.0067 0.07906v0.38446c0-0.02705 0.0041-0.05277 0.0067-0.07906z" fill="url(#linearGradient11110)" opacity=".3"/>
+ </g>
+ <circle cx="8.4665" cy="9.525" r="3.9687" fill="url(#linearGradient1272)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".1726"/>
+ <g transform="matrix(.77756 0 0 .77756 10.567 2.0159)">
+  <g transform="matrix(1.0741 0 0 1.0741 -11.796 -.7153)">
+   <circle cx="8.4665" cy="7.8051" r="1.7198" fill="url(#linearGradient1119)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".34395" style="paint-order:stroke fill markers"/>
+   <path d="m5.2916 11.064 5.4e-6 -0.14432c0-0.43295 0.43294-0.72158 0.72157-0.72158h4.9067c0.28863 0 0.72158 0.28863 0.72158 0.72158v0.14432c0 1.3096-1.416 2.1647-3.1749 2.1647-1.7589 0-3.1749-0.85514-3.1749-2.1647z" fill="url(#linearGradient1284)" stroke-width=".14049"/>
+  </g>
+ </g>
+</svg>

BIN
web/img/folder.c8ff81f3.png


BIN
web/img/xfile.402f9e59.png


+ 1 - 1
web/index.html

@@ -20,7 +20,7 @@
   <title>
   <title>
     CasaOS
     CasaOS
   </title>
   </title>
-<link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/chunk-vendors.js" rel="preload" as="script"></head>
+<link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/chunk-vendors.js" rel="preload" as="script"></head>
 
 
 <body>
 <body>
   <noscript>
   <noscript>

File diff suppressed because it is too large
+ 9 - 9
web/js/0.js


File diff suppressed because it is too large
+ 0 - 8
web/js/1.js


File diff suppressed because it is too large
+ 9 - 10
web/js/2.js


File diff suppressed because it is too large
+ 0 - 8
web/js/3.js


File diff suppressed because it is too large
+ 4 - 4
web/js/4.js


File diff suppressed because it is too large
+ 4 - 4
web/js/5.js


File diff suppressed because it is too large
+ 10 - 0
web/js/6.js


File diff suppressed because it is too large
+ 10 - 0
web/js/7.js


File diff suppressed because it is too large
+ 0 - 0
web/js/app.js


File diff suppressed because it is too large
+ 7 - 0
web/js/chunk-vendors.js


Some files were not shown because too many files changed in this diff