diff --git a/UI b/UI index 247c099..74fa1f8 160000 --- a/UI +++ b/UI @@ -1 +1 @@ -Subproject commit 247c099bf14a2d9eb94bf7798e04d00dbc8f7efd +Subproject commit 74fa1f8920aa23f40b04b87cc04ebef5c36b0890 diff --git a/conf/conf.ini.sample b/conf/conf.ini.sample index 808e6ea..612c015 100644 --- a/conf/conf.ini.sample +++ b/conf/conf.ini.sample @@ -14,11 +14,12 @@ RootPath = /casaOS [server] HttpPort = 8089 +UDPPort = RunMode = release ServerApi = https://api.casaos.zimaboard.com -Handshake = +Handshake = socket.casaos.io Token = -NickName = +USBAutoMount = true [user] @@ -28,11 +29,7 @@ Email = user@gmail.com Description = description Initialized = false Avatar = - -[zerotier] -UserName = user -PWD = pwd -Token = yBKYyavr2RdFAIVN7iTpzlsB1o6CqTgm +NickName = [redis] Host = 127.0.0.1:6379 @@ -48,4 +45,4 @@ Analyse = [file] ShareDir = -DownloadDir = /DATA \ No newline at end of file +DownloadDir = \ No newline at end of file diff --git a/go.mod b/go.mod index 4d293b4..a703c0c 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/smartystreets/assertions v1.2.0 // 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/swag v1.7.3 github.com/tidwall/gjson v1.10.2 diff --git a/go.sum b/go.sum index 2043428..cce619d 100644 --- a/go.sum +++ b/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/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.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= 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/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= diff --git a/main.go b/main.go index d089b7a..9cf8f67 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,9 @@ import ( "flag" "fmt" "net/http" + "runtime" "time" - "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/sqlite" @@ -29,6 +29,24 @@ func init() { config.InitSetup(*configFlag) config.UpdateSetup() 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) //gredis.GetRedisConn(config.RedisInfo), service.MyService = service.NewService(sqliteDB, loger2.NewOLoger()) @@ -36,10 +54,10 @@ func init() { go service.UDPService() - service.Summary = make(map[string]model.FileSummaryModel) + fmt.Println("token", service.GetToken()) service.UDPAddressMap = make(map[string]string) //go service.SocketConnect() - + service.CancelList = make(map[string]string) route.InitFunction() go service.SendIPToServer() @@ -69,20 +87,30 @@ func main() { //gredis.Setup() r := route.InitRouter() //service.SyncTask(sqliteDB) - cron2 := cron.New() //创建一个cron实例 + cron2 := cron.New() //every day execution err := cron2.AddFunc("0 0/5 * * * *", func() { //service.PushIpInfo(*&config.ServerInfo.Token) //service.UpdataDDNSList(mysqldb) //service.SyncTask(sqliteDB) + service.SendIPToServer() + service.LoopFriend() + }) if err != nil { fmt.Println(err) } + // err = cron2.AddFunc("0/1 * * * * *", func() { - //启动/关闭 + // //service.SendIPToServer() + // //service.LoopNet() + + // }) + // if err != nil { + // fmt.Println(err) + // } cron2.Start() defer cron2.Stop() s := &http.Server{ diff --git a/model/net.go b/model/net.go index fcc90a6..1f2897a 100644 --- a/model/net.go +++ b/model/net.go @@ -1,19 +1,17 @@ package model -import "time" - 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"` } diff --git a/model/person.go b/model/person.go index 0dbcf16..d8a119a 100644 --- a/model/person.go +++ b/model/person.go @@ -45,3 +45,10 @@ type FileSummaryModel struct { Size int64 `json:"size"` 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"` +} diff --git a/model/sys_common.go b/model/sys_common.go index 8c33ec7..0c166ce 100644 --- a/model/sys_common.go +++ b/model/sys_common.go @@ -22,12 +22,14 @@ type UserModel 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:"返回结果"` } -//zeritier相关 -type ZeroTierModel struct { - UserName string - PWD string - Token string -} - //redis配置文件 type RedisModel struct { Host string diff --git a/model/user.go b/model/user.go new file mode 100644 index 0000000..fbc9398 --- /dev/null +++ b/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"` +} diff --git a/model/zima.go b/model/zima.go index dafaa43..6d3afbb 100644 --- a/model/zima.go +++ b/model/zima.go @@ -3,11 +3,11 @@ package model import "time" 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"` - Size int64 `json:"size"` + Size int64 `json:"size"` //File Size Type string `json:"type,omitempty"` Label string `json:"label,omitempty"` } diff --git a/pkg/config/init.go b/pkg/config/init.go index 5cb0df4..38680c0 100644 --- a/pkg/config/init.go +++ b/pkg/config/init.go @@ -25,9 +25,6 @@ var AppInfo = &model.APPModel{} //redis相关配置 var RedisInfo = &model.RedisModel{} -//zerotier相关 -var ZeroTierInfo = &model.ZeroTierModel{} - //server相关 var ServerInfo = &model.ServerModel{} @@ -56,7 +53,6 @@ func InitSetup(config string) { mapTo("user", UserInfo) mapTo("app", AppInfo) - mapTo("zerotier", ZeroTierInfo) mapTo("redis", RedisInfo) mapTo("server", ServerInfo) mapTo("system", SystemConfigInfo) diff --git a/pkg/config/update.go b/pkg/config/update.go index 9091a34..7dbae82 100644 --- a/pkg/config/update.go +++ b/pkg/config/update.go @@ -1,13 +1,30 @@ package config -import "github.com/IceWhaleTech/CasaOS/pkg/utils/file" +import ( + "runtime" + + "github.com/IceWhaleTech/CasaOS/pkg/utils/file" +) //检查目录是否存在 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 { file.IsNotExistMkDir(v) } + } func UpdateSetup() { diff --git a/pkg/sqlite/db.go b/pkg/sqlite/db.go index 2b85a71..0338d05 100644 --- a/pkg/sqlite/db.go +++ b/pkg/sqlite/db.go @@ -31,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB { return nil } 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 { fmt.Println("检查和创建数据库出错", err) } diff --git a/pkg/utils/file/file.go b/pkg/utils/file/file.go index c2d3316..069b2c0 100644 --- a/pkg/utils/file/file.go +++ b/pkg/utils/file/file.go @@ -8,6 +8,8 @@ import ( "mime/multipart" "os" "path" + path2 "path" + "path/filepath" "strconv" "strings" ) @@ -226,6 +228,17 @@ func CopyFile(src, dst string) error { 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 func CopyDir(src string, dst string) error { var err error diff --git a/pkg/utils/httper/httper.go b/pkg/utils/httper/httper.go index 09848d9..651453f 100644 --- a/pkg/utils/httper/httper.go +++ b/pkg/utils/httper/httper.go @@ -3,6 +3,7 @@ package httper import ( "bytes" "encoding/json" + "fmt" "io" "io/ioutil" "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} resp, error := client.Do(req) if error != nil { - panic(error) + fmt.Println(error) + return } defer resp.Body.Close() diff --git a/pkg/utils/ini_helper.go b/pkg/utils/ini_helper.go deleted file mode 100644 index d4b585b..0000000 --- a/pkg/utils/ini_helper.go +++ /dev/null @@ -1 +0,0 @@ -package utils diff --git a/pkg/utils/oasis_err/e.go b/pkg/utils/oasis_err/e.go index 4b1c15c..bb6fcbd 100644 --- a/pkg/utils/oasis_err/e.go +++ b/pkg/utils/oasis_err/e.go @@ -37,13 +37,18 @@ const ( FILE_DOES_NOT_EXIST = 60001 FILE_READ_ERROR = 60002 FILE_DELETE_ERROR = 60003 + DIR_NOT_EXISTS = 60004 //shortcuts 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{ @@ -82,12 +87,18 @@ var MsgFlags = map[int]string{ // FILE_DOES_NOT_EXIST: "File does not exist", + DIR_NOT_EXISTS: "Directory does not exist", + FILE_READ_ERROR: "File read error", FILE_DELETE_ERROR: "Delete 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", } //获取错误信息 diff --git a/pkg/zerotier/zerotier_api.go b/pkg/zerotier/zerotier_api.go deleted file mode 100644 index f7ad214..0000000 --- a/pkg/zerotier/zerotier_api.go +++ /dev/null @@ -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 -} diff --git a/route/init.go b/route/init.go index 4db6a6f..3859361 100644 --- a/route/init.go +++ b/route/init.go @@ -4,6 +4,7 @@ import ( "encoding/json" "encoding/xml" "fmt" + "runtime" "strconv" "time" @@ -231,10 +232,10 @@ func CheckSerialDiskMount() { } service.MyService.Disk().RemoveLSBLKCache() command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir") - } func Update2_3() { command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh") + } func CheckToken2_11() { if len(config.ServerInfo.Token) == 0 { @@ -253,20 +254,34 @@ func CheckToken2_11() { // config.AppInfo.RootPath = "/casaOS" // 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" - - config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) - } - + sysType := runtime.GOOS if len(config.FileSettingInfo.DownloadDir) == 0 { - config.Cfg.Section("file").Key("DownloadDir").SetValue("/DATA/share") - config.FileSettingInfo.DownloadDir = "/DATA/share" + 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) } + if len(config.UserInfo.Description) == 0 { + config.Cfg.Section("user").Key("Description").SetValue("nothing") + config.UserInfo.Description = "nothing" + 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 = append(str, "ddd") // str = append(str, "aaa") diff --git a/route/route.go b/route/route.go index 04671dd..80b7eee 100644 --- a/route/route.go +++ b/route/route.go @@ -18,6 +18,7 @@ var OnlineDemo bool = false func InitRouter() *gin.Engine { r := gin.Default() + r.Use(middleware.Cors()) r.Use(gzip.Gzip(gzip.DefaultCompression)) gin.SetMode(config.ServerInfo.RunMode) @@ -52,13 +53,16 @@ func InitRouter() *gin.Engine { //chang head v1UserGroup.POST("/head", v1.PostUserHead) //chang user name - v1UserGroup.PUT("/changusername", v1.PutUserName) + v1UserGroup.PUT("/username", v1.PutUserName) //chang pwd - v1UserGroup.PUT("/changuserpwd", v1.PutUserPwd) + v1UserGroup.PUT("/password", v1.PutUserPwd) //edit user info v1UserGroup.POST("/info", v1.PostUserChangeInfo) v1UserGroup.PUT("/nick", v1.PutUserChangeNick) 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) } - - 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.Use() { @@ -201,6 +160,9 @@ func InitRouter() *gin.Engine { v1SysGroup.PUT("/port", v1.PutCasaOSPort) v1SysGroup.POST("/kill", v1.PostKillCasaOS) 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.Use() @@ -216,6 +178,7 @@ func InitRouter() *gin.Engine { v1FileGroup.POST("/create", v1.PostCreateFile) v1FileGroup.GET("/download", v1.GetDownloadFile) + v1FileGroup.GET("/new/download", v1.GetFileDownloadNew) v1FileGroup.POST("/operate", v1.PostOperateFileOrDir) v1FileGroup.DELETE("/delete", v1.DeleteFile) v1FileGroup.PUT("/update", v1.PutFileContent) @@ -289,19 +252,26 @@ func InitRouter() *gin.Engine { { v1SearchGroup.GET("/search", v1.GetSearchList) } - v1PersonGroup := v1Group.Group("/persion") + v1PersonGroup := v1Group.Group("/person") v1PersonGroup.Use() { 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") diff --git a/route/v1/app.go b/route/v1/app.go index 6b2425b..a2b326e 100644 --- a/route/v1/app.go +++ b/route/v1/app.go @@ -248,7 +248,7 @@ func ShareAppFile(c *gin.Context) { // @Tags app // @Security ApiKeyAuth // @Success 200 {string} string "ok" -// @Router /app/share [post] +// @Router /app/shares [post] func AppListResourceUsage() { } diff --git a/route/v1/file.go b/route/v1/file.go index 9f3a7c6..f85fbea 100644 --- a/route/v1/file.go +++ b/route/v1/file.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "net/http" + url2 "net/url" "os" "path" "strconv" @@ -17,6 +18,7 @@ import ( oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err" "github.com/IceWhaleTech/CasaOS/service" "github.com/gin-gonic/gin" + "github.com/spf13/afero" ) func downloadReadFile(c *gin.Context) { @@ -157,16 +159,59 @@ func GetDownloadFile(c *gin.Context) { //获取文件的名称 fileName := path.Base(filePath) 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("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) } +// @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 获取目录列表 // @Produce application/json // @Accept application/json diff --git a/route/v1/persion.go b/route/v1/persion.go index 3f7b651..7900fc1 100644 --- a/route/v1/persion.go +++ b/route/v1/persion.go @@ -7,9 +7,12 @@ import ( "net/http" "reflect" "strconv" + "strings" + "time" "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/config" + "github.com/IceWhaleTech/CasaOS/pkg/utils/file" oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err" "github.com/IceWhaleTech/CasaOS/service" model2 "github.com/IceWhaleTech/CasaOS/service/model" @@ -19,8 +22,10 @@ import ( ) func PersonTest(c *gin.Context) { - token := c.Query("token") + _, err := uuid.FromString(token) + fmt.Println(err) + //service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9") msg := model.MessageModel{} @@ -35,45 +40,48 @@ func PersonTest(c *gin.Context) { fmt.Println(err) } 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)}) } -// @Summary retry download file +// @Summary Retry the file that failed to download // @Produce application/json // @Accept application/json -// @Tags persion +// @Tags person // @Param uui path string true "download uuid" -// @Param path query string true "file path" // @Security ApiKeyAuth // @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)}) 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 } token := task.From 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 } m := model.MessageModel{} - m.Data = path + m.Data = task.Path m.From = config.ServerInfo.Token m.To = token m.Type = types.PERSONDOWNLOAD - m.UUId = uuid + m.UUId = uid go service.Dial(m, false) 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 // @Produce 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 file_name query string true "file name" +// @Param local_path query string true "local_path" // @Security ApiKeyAuth // @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") - 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)}) return } - 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)}) + 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 { + c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)}) + return + } + // task id uuid := uuid.NewV4().String() - task := model2.PersionDownloadDBModel{} + task := model2.PersonDownloadDBModel{} task.UUID = uuid - task.Name = "" + task.Name = fileName task.Length = 0 task.From = token + task.Path = path task.Size = 0 task.State = types.DOWNLOADAWAIT + task.Created = time.Now().Unix() 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) m := model.MessageModel{} @@ -127,79 +157,92 @@ func GetPersionFile(c *gin.Context) { // @Summary delete download file records // @Produce application/json // @Accept application/json -// @Tags persion +// @Tags person // @Param uuid path string true "download uuid" // @Security ApiKeyAuth // @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") - 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)}) 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) 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 // @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 -// @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", "") list := service.MyService.Download().GetDownloadListByState(state) //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 files, err := ioutil.ReadDir(tempDir) if err == nil { 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}) } -// @Summary edit friend's nick +// @Summary edit friend's remarks // @Produce 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 // @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)}) return } friend := model2.FriendModel{} 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)}) } -// @Summary get friend list +// @Summary get my friend list // @Produce application/json // @Accept application/json -// @Tags persion +// @Tags person // @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() for i := 0; i < len(list); i++ { if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 { @@ -212,51 +255,79 @@ func GetPersionFriend(c *gin.Context) { // @Summary add friend // @Produce application/json // @Accept application/json -// @Tags persion -// @Param token formData int true "Opponent token" +// @Tags person // @Security ApiKeyAuth // @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, ",") + + 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 + } + + 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) } - msg := model.MessageModel{} - msg.Type = types.PERSONCONNECTION - msg.Data = token - msg.From = config.ServerInfo.Token - msg.To = token - msg.UUId = uuid.NewV4().String() - - go service.Dial(msg, true) - - 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)}) } -// @Summary get directory list +// @Summary Get a list of directories // @Produce 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" // @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") - 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)}) return } 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 } 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}) } + +// @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}) +} diff --git a/route/v1/system.go b/route/v1/system.go index 472acdd..d30e93a 100644 --- a/route/v1/system.go +++ b/route/v1/system.go @@ -251,6 +251,60 @@ func PostKillCasaOS(c *gin.Context) { 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 // @Produce application/json // @Accept application/json @@ -374,7 +428,7 @@ func Info(c *gin.Context) { if n.Name == netCardName { item := *(*model.IOCountersStat)(unsafe.Pointer(&n)) item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name)) - item.DateTime = time.Now() + item.Time = time.Now().Unix() newNet = append(newNet, item) break } diff --git a/route/v1/user.go b/route/v1/user.go index a4d3a42..0ff05cd 100644 --- a/route/v1/user.go +++ b/route/v1/user.go @@ -121,7 +121,7 @@ func PostUserHead(c *gin.Context) { // @Param oldname formData string true "Old user name" // @Security ApiKeyAuth // @Success 200 {string} string "ok" -// @Router /user/changusername [put] +// @Router /user/username [put] func PutUserName(c *gin.Context) { if config.ServerInfo.LockAccount { 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 // @Tags user // @Param pwd formData string true "Password" -// @Param oldpwd formData string true "Old password" +// @Param old_pwd formData string true "Old password" // @Security ApiKeyAuth // @Success 200 {string} string "ok" -// @Router /user/changuserpwd [put] +// @Router /user/password [put] func PutUserPwd(c *gin.Context) { - oldpwd := c.PostForm("oldpwd") + oldPwd := c.PostForm("old_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)}) 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}) } -// @Summary edit user info +// @Summary edit user nick // @Produce application/json // @Accept multipart/form-data // @Tags user @@ -211,17 +211,18 @@ func PutUserChangeNick(c *gin.Context) { 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 } user_service.SetUser("", "", "", "", "", nickName) data := make(map[string]string, 1) 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}) } -// @Summary edit user info +// @Summary edit user description // @Produce application/json // @Accept multipart/form-data // @Tags user @@ -232,13 +233,38 @@ func PutUserChangeNick(c *gin.Context) { func PutUserChangeDesc(c *gin.Context) { 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 } user_service.SetUser("", "", "", "", desc, "") data := make(map[string]string, 1) 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}) } @@ -262,3 +288,14 @@ func GetUserInfo(c *gin.Context) { 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}) +} diff --git a/route/v1/zerotier.go b/route/v1/zerotier.go deleted file mode 100644 index 0966ef9..0000000 --- a/route/v1/zerotier.go +++ /dev/null @@ -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)}) -} diff --git a/route/v1/zima_info.go b/route/v1/zima_info.go index fa7ba9e..91bfda6 100644 --- a/route/v1/zima_info.go +++ b/route/v1/zima_info.go @@ -73,7 +73,7 @@ func NetInfo(c *gin.Context) { if n.Name == netCardName { item := *(*model.IOCountersStat)(unsafe.Pointer(&n)) item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name)) - item.DateTime = time.Now() + item.Time = time.Now().Unix() newNet = append(newNet, item) break } diff --git a/service/casa.go b/service/casa.go index 62c890f..1c51da9 100644 --- a/service/casa.go +++ b/service/casa.go @@ -22,6 +22,9 @@ type CasaService interface { PushHeart(id, t string, language string) PushAppAnalyse(uuid, t string, name, language string) PushConnectionStatus(uuid, err string, from, to, event string) + PushUserInfo() + GetUserInfoByShareId(shareId string) model.UserInfo + GetPersonPublic() (list []model.FriendsModel) } type casaService struct { @@ -118,7 +121,6 @@ func GetToken() string { } go func() { str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil) - t <- gjson.Get(str, "data").String() }() auth = <-t @@ -178,13 +180,54 @@ func (o *casaService) PushConnectionStatus(uuid, err string, from, to, event str 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{} 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 { return &casaService{} } diff --git a/service/download.go b/service/download.go index d007c31..b2b2c46 100644 --- a/service/download.go +++ b/service/download.go @@ -6,43 +6,51 @@ import ( ) 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) - 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 { 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) } -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) } //failed during download -func (d *downloadService) SetDownloadError(m model2.PersionDownloadDBModel) { +func (d *downloadService) SetDownloadError(m model2.PersonDownloadDBModel) { d.db.Model(&m).Updates(m) } func (d *downloadService) DelDownload(uuid string) { - var m model2.PersionDownloadDBModel + var m model2.PersonDownloadDBModel 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) return m } -func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersionDownloadDBModel) { +func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersonDownloadDBModel) { if len(state) == 0 { d.db.Find(&list) - } else { d.db.Where("state = ?", state).Find(&list) } @@ -50,7 +58,7 @@ func (d *downloadService) GetDownloadListByState(state string) (list []model2.Pe return } -func (d *downloadService) SaveDownload(m model2.PersionDownloadDBModel) { +func (d *downloadService) SaveDownload(m model2.PersonDownloadDBModel) { d.db.Save(&m) } func NewDownloadService(db *gorm.DB) DownloadService { diff --git a/service/friend.go b/service/friend.go index 7a19ff0..23e7ad9 100644 --- a/service/friend.go +++ b/service/friend.go @@ -10,7 +10,8 @@ import ( type FriendService interface { AddFriend(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 GetFriendList() (list []model2.FriendModel) UpdateAddFriendType(m model2.FriendModel) @@ -27,17 +28,19 @@ func (p *friendService) AddFriend(m model2.FriendModel) { func (p *friendService) DeleteFriend(m model2.FriendModel) { 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 { p.db.Model(m).Where("token = ?", m.Token).First(&m) return m } 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 } diff --git a/service/model/o_download.go b/service/model/o_download.go index f9af0c5..5c8b1a4 100644 --- a/service/model/o_download.go +++ b/service/model/o_download.go @@ -1,21 +1,24 @@ package model -type PersionDownloadDBModel struct { +type PersonDownloadDBModel struct { UUID string `gorm:"column:uuid;primary_key" json:"uuid"` - State int `json:"state"` // - Type int `json:"type"` //defult 1 - Name string `json:"name"` //file name - 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" } diff --git a/service/model/o_friend.go b/service/model/o_friend.go index 56693bc..3d59aa9 100644 --- a/service/model/o_friend.go +++ b/service/model/o_friend.go @@ -1,15 +1,17 @@ package model type FriendModel struct { - State int `json:"state"` //备用 + State int `json:"state"` //Reserved CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"` UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"` - NickName string `json:"nick_name"` //custom name - Avatar string `json:"avatar"` //头像 - Name string `json:"name"` + 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"` - Profile string `json:"profile"` + Profile string `json:"profile"` //Description OnLine bool `json:"on_line" gorm:"-"` + Version int `json:"version"` } func (p *FriendModel) TableName() string { diff --git a/service/notify.go b/service/notify.go index 33aa539..fb56c76 100644 --- a/service/notify.go +++ b/service/notify.go @@ -18,6 +18,7 @@ type NotifyServer interface { DelLog(id string) GetList(c int) (list []model.AppNotify) MarkRead(id string, state int) + SendText(m model.AppNotify) } 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 { return ¬ifyServer{db: db} } diff --git a/service/person.go b/service/person.go index 5a3695d..25273ed 100644 --- a/service/person.go +++ b/service/person.go @@ -17,6 +17,7 @@ import ( "github.com/IceWhaleTech/CasaOS/pkg/quic_helper" "github.com/IceWhaleTech/CasaOS/pkg/utils/file" httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" + port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port" model2 "github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/types" "github.com/lucas-clemente/quic-go" @@ -32,6 +33,7 @@ type personService struct { } var IpInfo model.PersionModel +var CancelList map[string]string func PushIpInfo(token string) { @@ -63,9 +65,16 @@ var StreamList map[string]quic.Stream var ServiceMessage chan model.MessageModel func UDPService() { + port := 0 + if len(config.ServerInfo.UDPPort) > 0 { + port, _ = strconv.Atoi(config.ServerInfo.UDPPort) + if port != 0 && !port2.IsPortAvailable(port, "udp") { + port = 0 + } + } srcAddr := &net.UDPAddr{ - IP: net.IPv4zero, Port: 9904} + IP: net.IPv4zero, Port: port} var err error UDPConn, err = net.ListenUDP("udp", srcAddr) if err != nil { @@ -146,6 +155,7 @@ func ProcessingContent(stream quic.Stream) { prefixByte := make([]byte, 6) _, err := io.ReadFull(stream, prefixByte) if err != nil { + fmt.Println(err) return } prefixLength, err := strconv.Atoi(string(prefixByte)) @@ -166,14 +176,22 @@ func ProcessingContent(stream quic.Stream) { //nothing continue } else if m.Type == types.PERSONDIRECTORY { + friend := model2.FriendModel{} + friend.Token = m.From 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 { - list = MyService.ZiMa().GetDirPath(m.Data.(string)) + list = []model.Path{} } m.To = m.From m.Data = list @@ -185,6 +203,7 @@ func ProcessingContent(stream quic.Stream) { SendFileData(stream, m.Data.(string), m.From, m.UUId) break } else if m.Type == types.PERSONADDFRIEND { + fmt.Println("有用户来请求加好友", m) friend := model2.FriendModel{} dataModelByte, _ := json.Marshal(m.Data) err := json.Unmarshal(dataModelByte, &friend) @@ -196,7 +215,7 @@ func ProcessingContent(stream quic.Stream) { mi := model2.FriendModel{} mi.Avatar = config.UserInfo.Avatar mi.Profile = config.UserInfo.Description - mi.Name = config.UserInfo.NickName + mi.NickName = config.UserInfo.NickName m.To = m.From m.Data = mi m.Type = types.PERSONADDFRIEND @@ -210,19 +229,34 @@ func ProcessingContent(stream quic.Stream) { } else { 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.Type = types.PERSONADDFRIEND - msg.Data = mi + msg.Type = types.PERSONHELLO + msg.Data = "" msg.To = m.From msg.From = config.ServerInfo.Token msg.UUId = m.UUId Dial(msg, false) + break + } else if m.Type == types.PERSONCANCEL { + CancelList[m.UUId] = "cancel" break } else { //不应有不做返回的数据 @@ -289,6 +323,9 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error { bufferedReader := bufio.NewReader(f) buf := make([]byte, blockSize) + + defer stream.Close() + for i := 0; i < length; i++ { tran := model.TranFileModel{} @@ -313,8 +350,11 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error { prefixLength := file.PrefixLength(len(b)) dataLength := file.DataLength(len(buf[:n])) data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...) + if _, ok := CancelList[uuid]; ok { + delete(CancelList, uuid) + return nil + } stream.Write(data) } - defer stream.Close() return nil } diff --git a/service/service.go b/service/service.go index c72a91c..8eb681d 100644 --- a/service/service.go +++ b/service/service.go @@ -21,7 +21,6 @@ type Repository interface { User() UserService Docker() DockerService //Redis() RedisService - ZeroTier() ZeroTierService ZiMa() ZiMaService Casa() CasaService Disk() DiskService @@ -45,7 +44,6 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository { user: NewUserService(), docker: NewDockerService(log), //redis: NewRedisService(rp), - zerotier: NewZeroTierService(), zima: NewZiMaService(), casa: NewCasaService(), disk: NewDiskService(log, db), @@ -68,7 +66,6 @@ type store struct { ddns DDNSService user UserService docker DockerService - zerotier ZeroTierService zima ZiMaService casa CasaService disk DiskService @@ -123,9 +120,6 @@ func (c *store) Docker() DockerService { return c.docker } -func (c *store) ZeroTier() ZeroTierService { - return c.zerotier -} func (c *store) ZiMa() ZiMaService { return c.zima } diff --git a/service/system.go b/service/system.go index 8e35d83..bf92a43 100644 --- a/service/system.go +++ b/service/system.go @@ -18,6 +18,8 @@ type SystemService interface { UpdateAssist() UpSystemPort(port string) GetTimeZone() string + UpdateUSBAutoMount(state string) + ExecUSBAutoMountShell(state string) } type systemService struct { log loger.OLog @@ -37,6 +39,15 @@ func (s *systemService) GetTimeZone() string { 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 { 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) } +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) { if len(port) > 0 && port != config.ServerInfo.HttpPort { config.Cfg.Section("server").Key("HttpPort").SetValue(port) diff --git a/service/udpconn.go b/service/udpconn.go index 95ab2bc..90e3a25 100644 --- a/service/udpconn.go +++ b/service/udpconn.go @@ -10,6 +10,7 @@ import ( "io/ioutil" "net" "os" + path2 "path" "strconv" "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) defer cancel() 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{ - IP: net.IPv4zero, Port: 9904} //注意端口必须固定 + IP: net.IPv4zero, Port: p} //注意端口必须固定 addr := UDPAddressMap[msg.To] - ticker := msg.To + ticket := msg.To if server { addr = config.ServerInfo.Handshake + ":9527" - ticker = "bench" + ticket = "bench" } dstAddr, err := net.ResolveUDPAddr("udp", addr) //DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。 //(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 { - 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 } stream, err := session.OpenStreamSync(ctx) 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()) return m, err } @@ -66,7 +90,9 @@ func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) go ReadContent(stream) result := <-Message 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 } @@ -88,8 +114,6 @@ func SendData(stream quic.Stream, m model.MessageModel) { stream.Write(data) } -var Summary map[string]model.FileSummaryModel - //读取数据 func ReadContent(stream quic.Stream) { for { @@ -97,6 +121,12 @@ func ReadContent(stream quic.Stream) { _, err := io.ReadFull(stream, prefixByte) if err != nil { 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 } prefixLength, err := strconv.Atoi(string(prefixByte)) @@ -112,12 +142,14 @@ func ReadContent(stream quic.Stream) { } m := model.MessageModel{} err = json.Unmarshal(messageByte, &m) + fmt.Println("客户端", m) if err != nil { fmt.Println(err) break } if m.Type == types.PERSONDOWNLOAD { + dataModelByte, _ := json.Marshal(m.Data) dataModel := model.TranFileModel{} err := json.Unmarshal(dataModelByte, &dataModel) @@ -149,29 +181,32 @@ func ReadContent(stream quic.Stream) { fmt.Println("hash不匹配", hash, dataModel.Hash) continue } - tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId file.IsNotExistMkDir(tempPath) 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) - task := model2.PersionDownloadDBModel{} + task := model2.PersonDownloadDBModel{} 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 { if file.GetHashByPath(filepath) != dataModel.Hash { os.Remove(filepath) err = ioutil.WriteFile(filepath, dataByte, 0644) - task := model2.PersionDownloadDBModel{} + task := model2.PersonDownloadDBModel{} 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 } 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) - 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 { 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 @@ -205,42 +240,55 @@ func ReadContent(stream quic.Stream) { dataModel := model.FileSummaryModel{} dataModelByte, _ := json.Marshal(m.Data) err := json.Unmarshal(dataModelByte, &dataModel) - fmt.Println(err) + if err != nil { + fmt.Println(err) + } - task := model2.PersionDownloadDBModel{} - task.UUID = m.UUId - task.Name = dataModel.Name - task.Length = dataModel.Length - task.Size = dataModel.Size + task := MyService.Download().GetDownloadById(m.UUId) + fullPath := path2.Join(task.LocalPath, task.Name) task.State = types.DOWNLOADING - task.BlockSize = dataModel.BlockSize - task.Hash = dataModel.Hash - task.Type = 0 - task.From = m.From 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.UUID = m.UUId + task.Name = dataModel.Name + task.Length = dataModel.Length + task.Size = dataModel.Size + task.BlockSize = dataModel.BlockSize + task.Hash = dataModel.Hash + task.Type = 0 + task.From = m.From MyService.Download().SaveDownload(task) - Summary[m.UUId] = dataModel - } else if m.Type == types.PERSONCONNECTION { - if len(m.Data.(string)) > 0 { UDPAddressMap[m.From] = m.Data.(string) } else { 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.Type = types.PERSONADDFRIEND - msg.Data = mi + msg.Type = types.PERSONHELLO + msg.Data = "" msg.To = m.From msg.From = config.ServerInfo.Token msg.UUId = m.UUId @@ -248,10 +296,21 @@ func ReadContent(stream quic.Stream) { Message <- m break } else if m.Type == "get_ip" { + notify := model2.AppNotify{} + notify.CustomId = m.From 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) + Message <- m 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) Message <- m break @@ -264,7 +323,7 @@ func ReadContent(stream quic.Stream) { func SendIPToServer() { msg := model.MessageModel{} - msg.Type = "hello" + msg.Type = types.PERSONHELLO msg.Data = "" msg.From = config.ServerInfo.Token msg.To = config.ServerInfo.Token @@ -282,9 +341,10 @@ func LoopFriend() { msg.From = config.ServerInfo.Token msg.To = list[i].Token msg.UUId = uuid.NewV4().String() + Dial(msg, true) - msg.Type = "hello" + msg.Type = types.PERSONHELLO msg.Data = "" msg.From = config.ServerInfo.Token msg.To = list[i].Token @@ -292,6 +352,19 @@ func LoopFriend() { if _, ok := UDPAddressMap[list[i].Token]; ok { 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) } } diff --git a/service/zerotier.go b/service/zerotier.go deleted file mode 100644 index d1b7862..0000000 --- a/service/zerotier.go +++ /dev/null @@ -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{} -} diff --git a/service/zima_info.go b/service/zima_info.go index 49c1667..0ff66c5 100644 --- a/service/zima_info.go +++ b/service/zima_info.go @@ -4,10 +4,12 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "runtime" "strconv" "strings" "time" + "unsafe" "github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/pkg/config" @@ -32,12 +34,15 @@ type ZiMaService interface { GetNetState(name string) string GetSysInfo() host.InfoStat GetDirPath(path string) []model.Path + GetDirPathOne(path string) (m model.Path) MkdirAll(path string) (int, error) CreateFile(path string) (int, error) RenameFile(oldF, newF string) (int, error) GetCpuInfo() []cpu.InfoStat } +var NetArray [][]model.IOCountersStat + type zima struct { } @@ -84,10 +89,19 @@ func (c *zima) GetDirPath(path string) []model.Path { ls, _ := ioutil.ReadDir(path) dirs := []model.Path{} - if len(path) > 0 { 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 { 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 } +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 { info, _ := host.Info() @@ -174,3 +203,41 @@ func (c *zima) RenameFile(oldF, newF string) (int, error) { func NewZiMaService() ZiMaService { 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 + } + } + + } +} diff --git a/shell/assist.sh b/shell/assist.sh index d4fbe1d..a1686e8 100644 --- a/shell/assist.sh +++ b/shell/assist.sh @@ -1,13 +1,6 @@ #!/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 @@ -16,7 +9,9 @@ readonly CASA_DEPANDS="curl smartmontools parted fdisk ntfs-3g" version_0_2_5() { install_depends "$CASA_DEPANDS" } - +version_0_2_11() { + sysctl -w net.core.rmem_max=2500000 +} #Install Depends install_depends() { @@ -35,6 +30,6 @@ install_depends() { fi } -version_0_2_3 - version_0_2_5 + +version_0_2_11 diff --git a/shell/helper.sh b/shell/helper.sh index b48061f..dad3742 100644 --- a/shell/helper.sh +++ b/shell/helper.sh @@ -245,9 +245,13 @@ do_umount() { if [[ -z ${MOUNT_POINT} ]]; then ${log} "Warning: ${DEVICE} is not mounted" else + /bin/kill -9 $(lsof ${MOUNT_POINT}) umount -l ${DEVICE} ${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 fi @@ -325,3 +329,16 @@ TarFolder() { #查看固定文件夹大小 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 +} \ No newline at end of file diff --git a/shell/usb-mount.sh b/shell/usb-mount.sh index 0376bb9..f6b6139 100644 --- a/shell/usb-mount.sh +++ b/shell/usb-mount.sh @@ -12,7 +12,7 @@ DEVBASE=$2 DEVICE="/dev/${DEVBASE}" # 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() { @@ -112,9 +112,12 @@ do_umount() { if [[ -z ${MOUNT_POINT} ]]; then ${log} "Warning: ${DEVICE} is not mounted" else + #/bin/kill -9 $(lsof ${MOUNT_POINT}) umount -l ${DEVICE} ${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 fi diff --git a/types/notify.go b/types/notify.go index 98999ca..1b7f1df 100644 --- a/types/notify.go +++ b/types/notify.go @@ -10,6 +10,8 @@ const ( NOTIFY_TYPE_NEED_CONFIRM NOTIFY_TYPE_ERROR NOTIFY_TYPE_INSTALL_LOG + NOTIFY_TYPE_PERSION_FIRNED_LEAVE + NOTIFY_TYPE_PERSION_FIRNED_LIVE ) const ( diff --git a/types/persion.go b/types/person.go similarity index 81% rename from types/persion.go rename to types/person.go index 440de5c..7e6e1a8 100644 --- a/types/persion.go +++ b/types/person.go @@ -6,3 +6,4 @@ const PERSONSUMMARY = "summary" const PERSONCONNECTION = "connection" const PERSONDIRECTORY = "directory" const PERSONHELLO = "hello" +const PERSONCANCEL = "cancel" // Cancel Download diff --git a/types/persion_download.go b/types/person_download.go similarity index 87% rename from types/persion_download.go rename to types/person_download.go index c0a5f82..01aeb6e 100644 --- a/types/persion_download.go +++ b/types/person_download.go @@ -6,4 +6,5 @@ const ( DOWNLOADPAUSE DOWNLOADFINISH DOWNLOADERROR + DOWNLOADFINISHED ) diff --git a/types/system.go b/types/system.go index f9d3235..54bf050 100644 --- a/types/system.go +++ b/types/system.go @@ -1,5 +1,5 @@ package types -const CURRENTVERSION = "0.2.10" +const CURRENTVERSION = "0.3.0" -const BODY = "
  • Added CasaOS own file manager
  • Fixed the problem of failed to create storage space
  • " +const BODY = "
  • Add CasaConnect function, now you can share private files peer-to-peer with your friends.
  • Add a widget for network traffic monitoring
  • Updated the initial directory of Files to the Root directory
  • Fix the application ipv6 opening problem
  • " diff --git a/web/img/1-small.1b74d2ba.png b/web/img/1-small.1b74d2ba.png new file mode 100644 index 0000000..406d0ba Binary files /dev/null and b/web/img/1-small.1b74d2ba.png differ diff --git a/web/img/folder-publicshare.0219e0d4.svg b/web/img/folder-publicshare.0219e0d4.svg new file mode 100644 index 0000000..8d5b97b --- /dev/null +++ b/web/img/folder-publicshare.0219e0d4.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/web/img/folder.c8ff81f3.png b/web/img/folder.c8ff81f3.png deleted file mode 100644 index 7610989..0000000 Binary files a/web/img/folder.c8ff81f3.png and /dev/null differ diff --git a/web/img/xfile.402f9e59.png b/web/img/xfile.402f9e59.png deleted file mode 100644 index ee02ec8..0000000 Binary files a/web/img/xfile.402f9e59.png and /dev/null differ diff --git a/web/index.html b/web/index.html index 93bd501..5e67b80 100644 --- a/web/index.html +++ b/web/index.html @@ -20,7 +20,7 @@ CasaOS - +