* delete connect

* update user

* change branch

* API feedback (#341)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* change branch

* update route

* change branch

* Update route.go

* 0.3.4 Function development completed

* Update system.go

* update ui

* Completed v0.3.4 and released alpha

Co-authored-by: Tiger Wang (王豫) <tigerwang@outlook.com>
This commit is contained in:
link 2022-07-22 11:02:11 +08:00 committed by GitHub
parent 5cc41fa040
commit 6f98995e7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 4599 additions and 7968 deletions

2
UI

@ -1 +1 @@
Subproject commit 7af1bf549dd35c93f48b6c501204a4efe57e8d6b
Subproject commit bca27426e1f398c31fb6c5c23885482326514f6e

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-27 11:37:26
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-01 15:51:29
* @LastEditTime: 2022-07-21 18:12:31
* @FilePath: /CasaOS/alpha.md
* @Description:
* @Website: https://www.casaos.io
@ -17,7 +17,7 @@ There is a risk of data loss in non-release versions, so please be careful to ba
## Install/Update
``` curl -fsSL https://get.casaos.io | bash -s -- -v v0.3.3-alpha ```
``` curl -fsSL https://get.casaos.io | bash -s -- -v v0.3.4-alpha ```
## Check change log

View file

@ -15,18 +15,10 @@ TempPath = /var/lib/casaos/temp
[server]
HttpPort = 80
UDPPort =
RunMode = release
ServerApi = https://api.casaos.io/casaos-api
Handshake = socket.casaos.io
Token =
USBAutoMount =
[system]
WidgetList =
[file]
ShareDir =
DownloadDir =

8
go.mod
View file

@ -19,12 +19,10 @@ require (
github.com/docker/go-connections v0.4.0
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b
github.com/gin-contrib/gzip v0.0.2
github.com/gin-gonic/gin v1.7.2
github.com/go-ini/ini v1.62.0
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-playground/validator/v10 v10.6.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/golang-jwt/jwt/v4 v4.4.1
@ -38,9 +36,9 @@ require (
github.com/jinzhu/copier v0.3.2
github.com/json-iterator/go v1.1.11 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lucas-clemente/quic-go v0.25.0
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.11 // indirect
github.com/mholt/archiver/v3 v3.5.1
@ -50,7 +48,6 @@ require (
github.com/opencontainers/selinux v1.8.5 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109
github.com/prometheus/procfs v0.7.3 // indirect
github.com/robfig/cron v1.2.0
github.com/satori/go.uuid v1.2.0
@ -58,8 +55,6 @@ 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/swaggo/gin-swagger v1.3.0
github.com/swaggo/swag v1.7.3
github.com/tidwall/gjson v1.10.2
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/ugorji/go v1.2.6 // indirect
@ -71,6 +66,7 @@ require (
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect
google.golang.org/appengine v1.6.7 // indirect

68
go.sum
View file

@ -59,8 +59,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@ -85,17 +83,13 @@ github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -328,8 +322,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b h1:r13MvtFTtnvxtuKK7z0ZSQ2EfMmTzWDHwfDvGCoqUQE=
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b/go.mod h1:EfR6AU78zUiZ36oVS5YrmTzc2um3zDXWPx4L4st++jo=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
@ -340,15 +332,10 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXt
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
github.com/gin-contrib/gzip v0.0.2 h1:VMBkd4ZB1Hl7e1lOA5gEZ/qdD3d9vLIq57xKWgPCCV8=
github.com/gin-contrib/gzip v0.0.2/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
@ -372,29 +359,13 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@ -563,9 +534,6 @@ github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -611,14 +579,10 @@ github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3m
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
@ -630,8 +594,6 @@ github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaI
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -676,7 +638,6 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -749,8 +710,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109 h1:h9WYaTCQJ7hap8C5vQniEum2YZbc+iRad/ROafTjy10=
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109/go.mod h1:U7VCLF6LMHzOFD/6Kww2MTQuwaNeEA1U1dOxFyZBoBE=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@ -799,7 +758,6 @@ github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvW
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.21.5 h1:YUBf0w/KPLk7w1803AYBnH7BmA+1Z/Q5MEZxpREUaB4=
github.com/shirou/gopsutil/v3 v3.21.5/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
@ -868,12 +826,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI=
github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
github.com/swaggo/swag v1.7.3 h1:ucB7irEdRrhjmW+Z1Ss4GjO68oPKQFjSgOR8BCAvcbU=
github.com/swaggo/swag v1.7.3/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -896,12 +848,9 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc=
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
@ -911,7 +860,6 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
@ -1018,7 +966,6 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1033,7 +980,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -1062,10 +1008,8 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
@ -1098,9 +1042,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1112,7 +1054,6 @@ golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1163,13 +1104,11 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1213,9 +1152,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -1251,7 +1188,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
@ -1375,15 +1311,12 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -1407,7 +1340,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=

39
main.go
View file

@ -24,7 +24,6 @@ var sqliteDB *gorm.DB
var configFlag = flag.String("c", "", "config address")
var dbFlag = flag.String("db", "", "db path")
var showUserInfo = flag.Bool("show-user-info", false, "show user info")
var resetUser = flag.Bool("ru", false, "reset user")
var user = flag.String("user", "", "user name")
@ -42,10 +41,6 @@ func init() {
service.Cache = cache.Init()
service.GetToken()
service.UDPAddressMap = make(map[string]string)
//go service.SocketConnect()
service.CancelList = make(map[string]string)
service.InternalInspection = make(map[string][]string)
service.NewVersionApp = make(map[string]string)
route.InitFunction()
@ -67,15 +62,7 @@ func init() {
// @BasePath /v1
func main() {
service.NotifyMsg = make(chan notify.Message, 10)
if *showUserInfo {
fmt.Println("CasaOS User Info")
fmt.Println("UserName:" + config.UserInfo.UserName)
fmt.Println("Password:" + config.UserInfo.PWD)
return
}
fmt.Println("Reset User", *resetUser)
if *resetUser {
if user == nil || len(*user) == 0 {
fmt.Println("user is empty")
return
@ -89,21 +76,11 @@ func main() {
userData.Password = encryption.GetMD5ByStr(password)
service.MyService.User().UpdateUserPassword(userData)
fmt.Println("User reset successful")
fmt.Println("UserName:" + userData.UserName)
fmt.Println("UserName:" + userData.Username)
fmt.Println("Password:" + password)
return
}
go func() {
service.UDPService()
service.SendIPToServer()
}()
go route.SocketInit(service.NotifyMsg)
go func() {
for i := 0; i < 1000; i++ {
time.Sleep(2 * time.Second)
//service.NotifyMsg <- strconv.Itoa(i)
}
}()
//model.Setup()
//gredis.Setup()
@ -111,20 +88,8 @@ func main() {
//service.SyncTask(sqliteDB)
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()
//service.MyService.App().CheckNewImage()
})
if err != nil {
fmt.Println(err)
}
err = cron2.AddFunc("0/5 * * * * *", func() {
err := cron2.AddFunc("0/5 * * * * *", func() {
if service.ClientCount > 0 {
//route.SendNetINfoBySocket()
//route.SendCPUBySocket()

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-10-08 10:29:08
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-21 15:10:03
* @LastEditTime: 2022-07-13 11:26:12
* @FilePath: /CasaOS/middleware/gin.go
* @Description:
* @Website: https://www.casaos.io
@ -26,14 +26,14 @@ func Cors() gin.HandlerFunc {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language")
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language,Content-Type,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Access-Control-Allow-Methods,Connection,Host,Origin,Referer,User-Agent,X-Requested-With")
// 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, X-CSRF-Token, Token, session, Origin, Host, Connection, Accept-Encoding, Accept-Language, X-Requested-With")
//设置缓存时间
c.Header("Access-Control-Max-Age", "172800")
c.Header("Access-Control-Allow-Credentials", "true")
c.Set("content-type", "application/json")
c.Set("Content-Type", "application/json")
//}
//允许类型校验

View file

@ -1,27 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-03-18 11:40:55
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-13 14:48:01
* @FilePath: /CasaOS/model/app-analyse.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model
type AppAnalyse struct {
Name string `json:"name"`
Type string `json:"type"`
UUId string `json:"uuid"`
Language string `json:"language"`
Version string `json:"version"`
}
type ConnectionStatus struct {
From string `json:"from"`
To string `json:"to"`
Error string `json:"error"`
UUId string `json:"uuid"`
Event string `json:"event"`
}

View file

@ -13,6 +13,15 @@ type ServerAppListCollection struct {
Version string `json:"version"`
}
// @tiger - 对于用于出参的数据结构,静态信息(例如 title
// 动态信息(例如 state、query_count应该划分到不同的数据结构中
//
// 这样的好处是
// 1 - 多次获取动态信息时可以减少出参复杂度,因为静态信息只获取一次就好
// 2 - 在未来的迭代中,可以降低维护成本(所有字段都展开放在一个层级维护成本略高)
//
// 另外,一些针对性字段,例如 Docker 相关的,可以用 map 来保存。
// 这样在未来增加多态 App例如 Snap不需要维护多个结构或者一个结构保存不必要的字段
type ServerAppList struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
Title string `json:"title"`

View file

@ -2,10 +2,9 @@
* @Author: link a624669980@163.com
* @Date: 2022-05-16 17:37:08
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-22 17:45:53
* @LastEditTime: 2022-07-13 10:46:38
* @FilePath: /CasaOS/model/category.go
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
* @Description:
*/
package model
@ -18,7 +17,7 @@ type CategoryList struct {
//CreatedAt time.Time `json:"created_at"`
//
//UpdatedAt time.Time `json:"updated_at"`
Font string `json:"font"`
Font string `json:"font"` // @tiger - 如果这个和前端有关,应该不属于后端的出参范围,而是前端去界定
Name string `json:"name"`
Count uint `json:"count"`
Count uint `json:"count"` // @tiger - count 属于动态信息,应该单独放在一个出参结构中(原因见另外一个关于 静态/动态 出参的注释)
}

View file

@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-13 10:43:45
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-13 11:00:04
* @FilePath: /CasaOS/model/disk.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model
type LSBLKModel struct {
@ -53,8 +63,8 @@ type DriveUSB struct {
Size uint64 `json:"size"`
Used uint64 `json:"use"`
Model string `json:"model"`
Mount bool `json:"mount"` //是否完全挂载
Avail uint64 `json:"avail"` //可用空间
Mount bool `json:"mount"`
Avail uint64 `json:"avail"`
}
type Storage struct {

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-12-08 18:10:25
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-14 17:20:36
* @LastEditTime: 2022-07-13 10:49:16
* @FilePath: /CasaOS/model/docker.go
* @Description:
* @Website: https://www.casaos.io
@ -14,5 +14,5 @@ type DockerStatsModel struct {
Icon string `json:"icon"`
Title string `json:"title"`
Data interface{} `json:"data"`
Pre interface{} `json:"pre"`
Previous interface{} `json:"previous"`
}

View file

@ -104,6 +104,7 @@ func (p *PathArray) Scan(input interface{}) error {
//}
type CustomizationPostData struct {
ContainerName string `json:"container_name"`
CustomId string `json:"custom_id"`
Origin string `json:"origin"`
NetworkModel string `json:"network_model"`

View file

@ -1,16 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-27 18:42:42
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-27 18:43:08
* @FilePath: /CasaOS/model/notify/person.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
type Person struct {
ShareId string `json:"share_id"`
Type string `json:"type"`
}

19
model/notify/storage.go Normal file
View file

@ -0,0 +1,19 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-15 10:43:00
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-15 10:56:17
* @FilePath: /CasaOS/model/notify/storage.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
type StorageMessage struct {
Type string `json:"type"` //sata,usb
Action string `json:"action"` //remove add
Path string `json:"path"`
Volume string `json:"volume"`
Size uint64 `json:"size"`
}

View file

@ -1,54 +0,0 @@
package model
import "time"
type PersionModel struct {
Token string `json:"token"`
Ips []string `json:"ips"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
//记录链接状态
type ConnectState struct {
From string `json:"from"`
To string `json:"to"`
Type string `json:"type"` //current state 1:ready 2:ok
CreatedAt time.Time `json:"created_at"`
UUId string `json:"uuid"` //对接标识
}
type MessageModel struct {
Type string `json:"type"`
Data interface{} `json:"data"`
UUId string `json:"uuid"`
From string `json:"from"`
To string `json:"to"`
}
type TranFileModel struct {
Hash string `json:"hash"` //Verify current fragment integrity
Length int `json:"length"`
Index int `json:"index"`
}
//需要获取文件详情
type FileDetailModel struct {
Path string `json:"path"`
}
//返回文件详情
type FileSummaryModel struct {
Hash string `json:"hash"` //Verify file
Name string `json:"name"`
BlockSize int `json:"block_size"`
Length int `json:"length"`
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"`
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-16 17:50:56
* @LastEditTime: 2022-07-14 11:02:06
* @FilePath: /CasaOS/model/sys_common.go
* @Description:
* @Website: https://www.casaos.io
@ -37,9 +37,7 @@ type ServerModel struct {
RunMode string
ServerApi string
LockAccount bool
Handshake string
Token string
UDPPort string
USBAutoMount string
SocketPort string
}
@ -76,12 +74,7 @@ type RedisModel struct {
}
type SystemConfig struct {
ConfigStr string `json:"config_str"`
WidgetList string `json:"widget_list"`
ConfigPath string `json:"config_path"`
SyncPort string `json:"sync_port"`
SyncKey string `json:"sync_key"`
Analyse string `json:"analyse"`
}
type CasaOSGlobalVariables struct {

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-21 16:01:26
* @LastEditTime: 2022-07-14 10:58:45
* @FilePath: /CasaOS/pkg/config/init.go
* @Description:
* @Website: https://www.casaos.io

View file

@ -6,7 +6,6 @@ import (
"fmt"
"io"
"regexp"
"strconv"
"sync"
"time"
@ -15,7 +14,7 @@ import (
"golang.org/x/crypto/ssh"
)
func NewSshClient(user, password string) (*ssh.Client, error) {
func NewSshClient(user, password string, port string) (*ssh.Client, error) {
// connet to ssh
// addr = fmt.Sprintf("%s:%d", host, port)
@ -32,7 +31,7 @@ func NewSshClient(user, password string) (*ssh.Client, error) {
//} else {
// config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
//}
addr := fmt.Sprintf("%s:%d", "127.0.0.1", 22)
addr := fmt.Sprintf("%s:%s", "127.0.0.1", port)
c, err := ssh.Dial("tcp", addr, config)
if err != nil {
return nil, err
@ -396,7 +395,7 @@ func WsReaderCopy(reader *websocket.Conn, writer io.Writer) {
if err = json2.Unmarshal(p, &msgObj); err != nil {
writer.Write(p)
} else if msgObj.Type == wsMsgResize {
writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
//writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
}
}
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-22 18:50:44
* @LastEditTime: 2022-07-11 18:10:53
* @FilePath: /CasaOS/pkg/sqlite/db.go
* @Description:
* @Website: https://www.casaos.io
@ -42,8 +42,22 @@ func GetDb(dbPath string) *gorm.DB {
return nil
}
gdb = db
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{}, model2.PersonDownRecordDBModel{}, model2.UserDBModel{})
db.Exec(`alter table o_user rename to old_user;
create table o_users ( id integer primary key,username text,password text,role text,email text,nickname text,avatar text,description text,created_at datetime,updated_at datetime);
insert into o_users select id,user_name,password,role,email,nick_name,avatar,description,created_at,updated_at from old_user;
drop table old_user;
drop table o_user;
`)
err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.UserDBModel{})
db.Exec("DROP TABLE IF EXISTS o_application")
db.Exec("DROP TABLE IF EXISTS o_friend")
db.Exec("DROP TABLE IF EXISTS o_person_download")
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
if err != nil {
loger.Error("check or create db error", zap.Any("error", err))
}

View file

@ -2,10 +2,11 @@ package common_err
const (
SUCCESS = 200
ERROR = 500
INVALID_PARAMS = 400
SERVICE_ERROR = 500
CLIENT_ERROR = 400
ERROR_AUTH_TOKEN = 401
INVALID_PARAMS = 4000
//user
PWD_INVALID = 10001
PWD_IS_EMPTY = 10002
@ -49,19 +50,12 @@ const (
//shortcuts
SHORTCUTS_URL_ERROR = 70001
//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{
SUCCESS: "ok",
ERROR: "fail",
SERVICE_ERROR: "Fail",
CLIENT_ERROR: "Fail",
INVALID_PARAMS: "Parameters Error",
ERROR_AUTH_TOKEN: "Error auth token",
@ -108,12 +102,6 @@ var MsgFlags = map[int]string{
FILE_DELETE_ERROR: "Delete error",
SHORTCUTS_URL_ERROR: "URL error",
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",
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
}
@ -123,5 +111,5 @@ func GetMsg(code int) string {
if ok {
return msg
}
return MsgFlags[ERROR]
return MsgFlags[SERVICE_ERROR]
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-24 10:02:46
* @LastEditTime: 2022-07-18 17:30:38
* @FilePath: /CasaOS/pkg/utils/jwt/jwt.go
* @Description:
* @Website: https://www.casaos.io
@ -16,67 +16,26 @@ import (
jwt "github.com/golang-jwt/jwt/v4"
)
// type Claims struct {
// UserName string `json:"username"`
// PassWord string `json:"password"`
// Id int `json:"id"`
// jwt.RegisteredClaims
// }
// var jwtSecret []byte
// //创建token
// func GenerateToken(username, password string, id int, issuer string, t time.Duration) (string, error) {
// clims := Claims{
// username,
// password,
// id,
// jwt.RegisteredClaims{
// ExpiresAt: jwt.NewNumericDate(time.Now().Add(t)),
// IssuedAt: jwt.NewNumericDate(time.Now()),
// NotBefore: jwt.NewNumericDate(time.Now()),
// Issuer: issuer,
// },
// }
// tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, clims)
// token, err := tokenClaims.SignedString(jwtSecret)
// return token, err
// }
// //解析token
// func ParseToken(token string) (*Claims, error) {
// tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
// return jwtSecret, nil
// })
// if tokenClaims != nil {
// if clims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
// return clims, nil
// }
// }
// return nil, err
// }
//****************** soon to be removed ******************
type Claims struct {
UserName string `json:"username"`
Username string `json:"username"`
PassWord string `json:"password"`
jwt.StandardClaims
Id int `json:"id"`
jwt.RegisteredClaims
}
var jwtSecret []byte
//创建token
func GenerateToken(username, password string) (string, error) {
expireTime := time.Now().AddDate(999, 0, 0)
func GenerateToken(username, password string, id int, issuer string, t time.Duration) (string, error) {
clims := Claims{
username,
password,
jwt.StandardClaims{
ExpiresAt: expireTime.Unix(),
Issuer: "gin-blog",
id,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(t)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
Issuer: issuer,
},
}
@ -87,13 +46,17 @@ func GenerateToken(username, password string) (string, error) {
}
//解析token
func ParseToken(token string) (*Claims, error) {
func ParseToken(token string, valid bool) (*Claims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if tokenClaims != nil {
if clims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
if clims, ok := tokenClaims.Claims.(*Claims); ok {
if valid && tokenClaims.Valid {
return clims, nil
} else if !valid {
return clims, nil
}
}
}
return nil, err

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-17 14:01:25
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-04 16:26:22
* @LastEditTime: 2022-07-18 17:31:15
* @FilePath: /CasaOS/pkg/utils/jwt/jwt_helper.go
* @Description:
* @Website: https://www.casaos.io
@ -11,65 +11,16 @@
package jwt
import (
"net/http"
"fmt"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gin-gonic/gin"
)
// func JWT() gin.HandlerFunc {
// return func(c *gin.Context) {
// var code int
// code = common_err.SUCCESS
// token := c.GetHeader("Authorization")
// if len(token) == 0 {
// token = c.Query("token")
// }
// if token == "" {
// code = common_err.INVALID_PARAMS
// }
// claims, err := ParseToken(token)
// //_, err := ParseToken(token)
// if err != nil {
// code = common_err.ERROR_AUTH_TOKEN
// } else if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("casaos", true) {
// code = common_err.ERROR_AUTH_TOKEN
// }
// if code != common_err.SUCCESS {
// c.JSON(code, model.Result{Success: code, Message: common_err.GetMsg(code)})
// c.Abort()
// return
// }
// c.Request.Header.Add("user_id", strconv.Itoa(claims.Id))
// c.Next()
// }
// }
// //get AccessToken
// func GetAccessToken(username, pwd string, id int) string {
// token, err := GenerateToken(username, pwd, id, "casaos", 3*time.Hour*time.Duration(1))
// if err == nil {
// return token
// } else {
// loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
// return ""
// }
// }
// func GetRefreshToken(username, pwd string, id int) string {
// token, err := GenerateToken(username, pwd, id, "fresh", 7*24*time.Hour*time.Duration(1))
// if err == nil {
// return token
// } else {
// loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
// return ""
// }
// }
//*************** soon to be removed *****************
func JWT() gin.HandlerFunc {
return func(c *gin.Context) {
var code int
@ -82,32 +33,43 @@ func JWT() gin.HandlerFunc {
code = common_err.INVALID_PARAMS
}
//claims, err := ParseToken(token)
_, err := ParseToken(token)
claims, err := ParseToken(token, false)
//_, err := ParseToken(token)
if err != nil {
code = common_err.ERROR_AUTH_TOKEN
} else if (c.Request.URL.Path == "/v1/file" || c.Request.URL.Path == "/v1/image" || c.Request.URL.Path == "/v1/file/upload" || c.Request.URL.Path == "/v1/batch") && claims.VerifyIssuer("casaos", true) {
//Special treatment
} else if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("casaos", true) {
code = common_err.ERROR_AUTH_TOKEN
}
//else if time.Now().Unix() > claims.ExpiresAt {
// code = oasis_err2.ERROR_AUTH_TOKEN
//}
if code != common_err.SUCCESS {
c.JSON(http.StatusOK, model.Result{Success: code, Message: common_err.GetMsg(code)})
c.JSON(code, model.Result{Success: code, Message: common_err.GetMsg(code)})
c.Abort()
return
}
c.Request.Header.Add("user_id", strconv.Itoa(claims.Id))
c.Next()
}
}
//获取token
func GetToken(username, pwd string) string {
token, err := GenerateToken(username, pwd)
//get AccessToken
func GetAccessToken(username, pwd string, id int) string {
token, err := GenerateToken(username, pwd, id, "casaos", 3*time.Hour*time.Duration(1))
if err == nil {
return token
} else {
//loger2.NewOLoger().Fatal(fmt.Sprintf("Get Token Fail: %V", err))
loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
return ""
}
}
func GetRefreshToken(username, pwd string, id int) string {
token, err := GenerateToken(username, pwd, id, "refresh", 7*24*time.Hour*time.Duration(1))
if err == nil {
return token
} else {
loger2.Error(fmt.Sprintf("Get Token Fail: %V", err))
return ""
}
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-29 14:29:34
* @LastEditTime: 2022-07-21 15:27:53
* @FilePath: /CasaOS/pkg/utils/version/version.go
* @Description:
* @Website: https://www.casaos.io
@ -33,9 +33,6 @@ func IsNeedUpdate(version model.Version) (bool, model.Version) {
for i := 0; i < len(v1); i++ {
a, _ := strconv.Atoi(v1[i])
b, _ := strconv.Atoi(v2[i])
if i == 0 && a > b {
continue
}
if a > b {
return true, version
}

View file

@ -1,30 +1,21 @@
package route
import (
"encoding/xml"
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/system_app"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
uuid "github.com/satori/go.uuid"
)
func InitFunction() {
go checkSystemApp()
ShellInit()
CheckSerialDiskMount()
@ -35,132 +26,6 @@ func InitFunction() {
MoveUserToDB()
}
var syncIsExistence = false
func installSyncthing(appId string) {
var appInfo model.ServerAppList
m := model.CustomizationPostData{}
var dockerImage string
var dockerImageVersion string
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "system", "us_en")
dockerImage = appInfo.Image
dockerImageVersion = appInfo.ImageVersion
if len(appInfo.ImageVersion) == 0 {
dockerImageVersion = "latest"
}
if appInfo.NetworkModel != "host" {
for i := 0; i < len(appInfo.Ports); i++ {
if p, _ := strconv.Atoi(appInfo.Ports[i].ContainerPort); port.IsPortAvailable(p, appInfo.Ports[i].Protocol) {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
} else {
if appInfo.Ports[i].Protocol == "tcp" {
if p, err := port.GetAvailablePort("tcp"); err == nil {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
}
} else if appInfo.Ports[i].Protocol == "upd" {
if p, err := port.GetAvailablePort("udp"); err == nil {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
}
}
}
if appInfo.Ports[i].Type == 0 {
appInfo.PortMap = appInfo.Ports[i].CommendPort
}
}
}
for i := 0; i < len(appInfo.Devices); i++ {
if !file.CheckNotExist(appInfo.Devices[i].ContainerPath) {
appInfo.Devices[i].Path = appInfo.Devices[i].ContainerPath
}
}
if len(appInfo.Tip) > 0 {
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
}
appInfo.MaxMemory = service.MyService.System().GetMemInfo()["total"].(uint64) >> 20
id := uuid.NewV4().String()
// step下载镜像
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, "", "")
if err != nil {
//pull image error
fmt.Println("pull image error", err, dockerImage, dockerImageVersion)
return
}
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
time.Sleep(time.Second)
}
m.CpuShares = 50
m.Envs = appInfo.Envs
m.Memory = int64(appInfo.MaxMemory)
m.Origin = "system"
m.PortMap = appInfo.PortMap
m.Ports = appInfo.Ports
m.Restart = "always"
m.Volumes = appInfo.Volumes
m.NetworkModel = appInfo.NetworkModel
m.Label = id
m.CustomId = id
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m)
if err != nil {
fmt.Println("container create error", err)
// create container error
return
}
//stepstart container
err = service.MyService.Docker().DockerContainerStart(containerId)
if err != nil {
//start container error
return
}
checkSystemApp()
}
// check if the system application is installed
func checkSystemApp() {
list := service.MyService.App().GetSystemAppList()
for _, v := range list {
info, err := service.MyService.Docker().DockerContainerInfo(v.ID)
if err != nil {
continue
}
if strings.Contains(info.Config.Image, "linuxserver/syncthing") {
if v.State != "running" {
//stepstart container
service.MyService.Docker().DockerContainerStart(v.ID)
}
syncIsExistence = true
if config.SystemConfigInfo.SyncPort != v.Labels["web"] {
config.SystemConfigInfo.SyncPort = v.Labels["web"]
}
path := ""
for _, i := range info.Mounts {
if i.Destination == "/config" {
path = i.Source
break
}
}
content := file.ReadFullFile(filepath.Join(path, "config.xml"))
syncConfig := &system_app.SyncConfig{}
xml.Unmarshal(content, &syncConfig)
config.SystemConfigInfo.SyncKey = syncConfig.Key
break
}
}
if !syncIsExistence {
installSyncthing("74")
}
}
func CheckSerialDiskMount() {
// check mount point
dbList := service.MyService.Disk().GetSerialAll()
@ -216,31 +81,11 @@ func CheckToken2_11() {
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
sysType := runtime.GOOS
if len(config.FileSettingInfo.DownloadDir) == 0 {
downloadPath := "/DATA/Downloads"
if sysType == "windows" {
downloadPath = "C:\\CasaOS\\DATA\\Downloads"
}
if sysType == "darwin" {
downloadPath = "./CasaOS/DATA/Downloads"
}
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
config.FileSettingInfo.DownloadDir = downloadPath
file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
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)
}
if service.MyService.System().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.System().GetDeviceTree(), "Raspberry Pi") {
service.MyService.System().UpdateUSBAutoMount("False")
@ -279,9 +124,9 @@ func MoveUserToDB() {
if len(config.UserInfo.UserName) > 0 && service.MyService.User().GetUserInfoByUserName(config.UserInfo.UserName).Id == 0 {
user := model2.UserDBModel{}
user.UserName = config.UserInfo.UserName
user.Username = config.UserInfo.UserName
user.Email = config.UserInfo.Email
user.NickName = config.UserInfo.NickName
user.Nickname = config.UserInfo.NickName
user.Password = encryption.GetMD5ByStr(config.UserInfo.PWD)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)

View file

@ -2,17 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-01 15:11:36
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-01 15:16:00
* @FilePath: /CasaOS/route/periodical.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-27 15:55:36
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-29 16:47:19
* @LastEditTime: 2022-07-21 15:25:07
* @FilePath: /CasaOS/route/periodical.go
* @Description:
* @Website: https://www.casaos.io

View file

@ -23,6 +23,7 @@ func InitRouter() *gin.Engine {
r.Use(middleware.WriteLog())
r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode)
r.StaticFS("/ui", http.FS(web.Static))
r.GET("/", WebUIHome)
// r.StaticFS("/assets", http.Dir("./static/assets"))
@ -31,199 +32,191 @@ func InitRouter() *gin.Engine {
// c.Redirect(http.StatusMovedPermanently, "ui/")
//})
r.POST("/v1/user/register/:key", v1.PostUserRegister)
r.POST("/v1/user/login", v1.PostUserLogin) //
r.GET("/v1/user/all/name", v1.GetUserAllUserName)
r.POST("/v1/users/register", v1.PostUserRegister)
r.POST("/v1/users/login", v1.PostUserLogin)
r.GET("/v1/users/name", v1.GetUserAllUsername) //all/name
r.POST("/v1/user/refresh", v1.PostUserRefreshToken)
// No short-term modifications
r.GET("/v1/users/image", v1.GetUserImage)
r.GET("/v1/sys/init/check", v1.GetSystemInitCheck)
r.GET("/v1/guide/check", v1.GetGuideCheck)
r.GET("/v1/debug", v1.GetSystemConfigDebug)
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
r.GET("/v1/user/info/:id", v1.GetUserInfo)
r.GET("/v1/user/avatar/:id", v1.GetUserAvatar)
r.GET("/v1/user/image", v1.GetUserImage)
r.GET("/v1/users/status", v1.GetUserStatus) //init/check
//r.GET("/v1/guide/check", v1.GetGuideCheck) // /v1/sys/guide_check
r.GET("/v1/sys/debug", v1.GetSystemConfigDebug) // //debug
r.GET("/v1/sys/socket-port", v1.GetSystemSocketPort) //sys/socket_port
//get user info
r.GET("/v1/person/shareid", v1.GetPersonShareId)
r.GET("/v1/sys/socket/port", v1.GetSystemSocketPort)
//r.POST("/v1/user/refresh/token", v1.PostUserRefreshToken)
v1Group := r.Group("/v1")
v1Group.Use(jwt2.JWT())
{
v1UserGroup := v1Group.Group("/user")
v1UserGroup.Use()
v1UsersGroup := v1Group.Group("/users")
v1UsersGroup.Use()
{
v1UsersGroup.GET("/current", v1.GetUserInfo)
v1UsersGroup.PUT("/current", v1.PutUserInfo)
v1UsersGroup.PUT("/current/password", v1.PutUserPassword)
//****************** New version needs to be modified start ******************
//chang user name
v1UserGroup.PUT("/username", v1.PutUserName)
v1UserGroup.PUT("/password", v1.PutUserPwd)
v1UserGroup.PUT("/nick", v1.PutUserNick)
v1UserGroup.PUT("/desc", v1.PutUserDesc)
v1UserGroup.GET("/info", v1.GetUserInfoByUserName)
v1UserGroup.GET("/custom/:id/:key", v1.GetUserCustomConf)
v1UserGroup.POST("/custom/:id/:key", v1.PostUserCustomConf)
v1UserGroup.DELETE("/custom/:id/:key", v1.DeleteUserCustomConf)
v1UserGroup.POST("/upload/image/:id/:key", v1.PostUserUploadImage)
v1UserGroup.POST("/file/image/:id/:key", v1.PostUserFileImage)
v1UserGroup.DELETE("/image/:id", v1.DeleteUserImage)
//****************** New version needs to be modified end ******************
v1UsersGroup.GET("/current/custom/:key", v1.GetUserCustomConf)
v1UsersGroup.POST("/current/custom/:key", v1.PostUserCustomConf)
v1UsersGroup.DELETE("/current/custom/:key", v1.DeleteUserCustomConf)
//****************** soon to be removed start ******************
v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
v1UserGroup.GET("/shareid", v1.GetUserShareID)
//****************** soon to be removed end ******************
v1UsersGroup.POST("/current/image/:key", v1.PostUserUploadImage)
v1UsersGroup.PUT("/current/image/:key", v1.PutUserImage)
//v1UserGroup.POST("/file/image/:key", v1.PostUserFileImage)
v1UsersGroup.DELETE("/current/image", v1.DeleteUserImage)
//v1UserGroup.GET("/info", v1.GetUserInfo)
//v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
//v1UserGroup.GET("/avatar", v1.GetUserAvatar)
v1UsersGroup.DELETE("/:id", v1.DeleteUser)
v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername)
v1UsersGroup.DELETE("", v1.DeleteUserAll)
}
v1UserGroup.PUT("/avatar", v1.PutUserAvatar)
v1UserGroup.GET("/avatar", v1.GetUserAvatar)
v1UserGroup.DELETE("/delete/:id", v1.DeleteUser)
v1AppsGroup := v1Group.Group("/apps")
v1AppsGroup.Use()
{
v1AppsGroup.GET("", v1.AppList) //list
v1AppsGroup.GET("/:id", v1.AppInfo)
}
v1ContainerGroup := v1Group.Group("/container")
v1ContainerGroup.Use()
{
v1ContainerGroup.GET("", v1.MyAppList) ///my/list
v1ContainerGroup.GET("/usage", v1.AppUsageList)
v1ContainerGroup.GET("/:id", v1.ContainerUpdateInfo) ///update/:id/info
v1ContainerGroup.GET("/:id/logs", v1.ContainerLog) // /app/logs/:id
v1ContainerGroup.GET("/networks", v1.GetDockerNetworks) //app/install/config
v1ContainerGroup.GET("/:id/state", v1.GetContainerState) //app/state/:id ?state=install_progress
// there are problems, temporarily do not deal with
v1ContainerGroup.GET("/:id/terminal", v1.DockerTerminal) //app/terminal/:id
v1ContainerGroup.POST("", v1.InstallApp) //app/install
//v1ContainerGroup.GET("/:id", v1.ContainerInfo) // /app/info/:id
v1ContainerGroup.PUT("/:id", v1.UpdateSetting) ///update/:id/setting
v1ContainerGroup.PUT("/:id/state", v1.ChangAppState) // /app/state/:id
v1ContainerGroup.DELETE("/:id", v1.UnInstallApp) //app/uninstall/:id
//Not used
v1ContainerGroup.PUT("/:id/latest", v1.PutAppUpdate)
//Not used
v1ContainerGroup.POST("/share", v1.ShareAppFile)
}
v1AppGroup := v1Group.Group("/app")
v1AppGroup.Use()
v1AppCategoriesGroup := v1Group.Group("/app-categories")
v1AppCategoriesGroup.Use()
{
//获取我的已安装的列表
v1AppGroup.GET("/my/list", v1.MyAppList)
//
v1AppGroup.GET("/usage", v1.AppUsageList)
//app详情
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
//获取未安装的列表
v1AppGroup.GET("/list", v1.AppList)
//获取端口
v1AppGroup.GET("/port", v1.GetPort)
//检查端口
v1AppGroup.GET("/check/:port", v1.PortCheck)
v1AppGroup.GET("/category", v1.CategoryList)
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
//app容器详情
v1AppGroup.GET("/info/:id", v1.ContainerInfo)
//app容器日志
v1AppGroup.GET("/logs/:id", v1.ContainerLog)
//暂停或启动容器
v1AppGroup.PUT("/state/:id", v1.ChangAppState)
//安装app
v1AppGroup.POST("/install", v1.InstallApp)
//卸载app
v1AppGroup.DELETE("/uninstall/:id", v1.UnInstallApp)
//获取进度
v1AppGroup.GET("/state/:id", v1.GetContainerState)
//更新容器配置
v1AppGroup.PUT("/update/:id/setting", v1.UpdateSetting)
//获取可能新数据
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
v1AppGroup.POST("/share", v1.ShareAppFile)
v1AppCategoriesGroup.GET("", v1.CategoryList)
}
v1SysGroup := v1Group.Group("/sys")
v1SysGroup.Use()
{
v1SysGroup.GET("/version/check", v1.GetSystemCheckVersion)
v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
v1SysGroup.GET("/version", v1.GetSystemCheckVersion) //version/check
v1SysGroup.POST("/update", v1.SystemUpdate)
v1SysGroup.GET("/hardware", v1.GetSystemHardwareInfo) //hardware/info
v1SysGroup.GET("/wsssh", v1.WsSsh)
v1SysGroup.GET("/config", v1.GetSystemConfig)
v1SysGroup.POST("/ssh-login", v1.PostSshLogin)
//v1SysGroup.GET("/config", v1.GetSystemConfig) //delete
//v1SysGroup.POST("/config", v1.PostSetSystemConfig)
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
v1SysGroup.GET("/logs", v1.GetCasaOSErrorLogs) //error/logs
//v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)//delete
//v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)//delete
v1SysGroup.POST("/stop", v1.PostKillCasaOS)
v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
// v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
// v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
// v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
// v1SysGroup.GET("/network", v1.GetSystemNetInfo)
v1SysGroup.PUT("/usb-auto-mount", v1.PutSystemUSBAutoMount) ///sys/usb/:status
v1SysGroup.GET("/usb-auto-mount", v1.GetSystemUSBAutoMount) ///sys/usb/status
v1SysGroup.GET("/server-info", nil)
v1SysGroup.PUT("/server-info", nil)
v1SysGroup.GET("/apps-state", v1.GetSystemAppsStatus)
v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.POST("/stop", v1.PostKillCasaOS)
v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
v1SysGroup.PUT("/usb/:status", v1.PutSystemUSBAutoMount)
v1SysGroup.GET("/usb/status", v1.GetSystemUSBAutoMount)
v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
v1SysGroup.GET("/network", v1.GetSystemNetInfo)
}
v1PortGroup := v1Group.Group("/port")
v1PortGroup.Use()
{
v1PortGroup.GET("/", v1.GetPort) //app/port
v1PortGroup.GET("/state/:port", v1.PortCheck) //app/check/:port
}
v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use()
{
v1FileGroup.PUT("/rename", v1.RenamePath)
v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.GET("", v1.GetDownloadSingleFile) //download/:path
v1FileGroup.POST("", v1.PostCreateFile)
v1FileGroup.PUT("", v1.PutFileContent)
v1FileGroup.PUT("/name", v1.RenamePath)
//file/rename
v1FileGroup.GET("/content", v1.GetFilerContent) //file/read
//File uploads need to be handled separately, and will not be modified here
v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/upload", v1.GetFileUpload)
v1FileGroup.GET("/dirpath", v1.DirPath)
//create folder
v1FileGroup.POST("/mkdir", v1.MkdirAll)
v1FileGroup.POST("/create", v1.PostCreateFile)
v1FileGroup.GET("/download", v1.GetDownloadFile)
v1FileGroup.GET("/download/*path", v1.GetDownloadSingleFile)
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
v1FileGroup.DELETE("/delete", v1.DeleteFile)
v1FileGroup.PUT("/update", v1.PutFileContent)
v1FileGroup.GET("/image", v1.GetFileImage)
v1FileGroup.DELETE("/operate/:id", v1.DeleteOperateFileOrDir)
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
}
v1DiskGroup := v1Group.Group("/disk")
v1DiskGroup.Use()
v1FolderGroup := v1Group.Group("/folder")
v1FolderGroup.Use()
{
v1DiskGroup.GET("/check", v1.GetDiskCheck)
v1DiskGroup.GET("/list", v1.GetDiskList)
//获取磁盘详情
v1DiskGroup.GET("/info", v1.GetDiskInfo)
//format storage
v1DiskGroup.POST("/format", v1.PostDiskFormat)
// add storage
v1DiskGroup.POST("/storage", v1.PostDiskAddPartition)
//mount SATA disk
v1DiskGroup.POST("/mount", v1.PostMountDisk)
//umount sata disk
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
//获取可以格式化的内容
v1DiskGroup.GET("/type", v1.FormatDiskType)
//删除分区
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
v1DiskGroup.GET("/usb", v1.GetUSBList)
v1FolderGroup.PUT("/name", v1.RenamePath)
v1FolderGroup.GET("", v1.DirPath) ///file/dirpath
v1FolderGroup.POST("", v1.MkdirAll) ///file/mkdir
}
v1PersonGroup := v1Group.Group("/person")
v1PersonGroup.Use()
v1BatchGroup := v1Group.Group("/batch")
v1BatchGroup.Use()
{
v1PersonGroup.GET("/detection", v1.GetPersonDetection)
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.POST("/file/:shareid", v1.PostPersonFile)
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)
v1PersonGroup.PUT("/friend/:shareid", v1.PutPersonAgreeFriend)
v1PersonGroup.PUT("/write/:shareid", v1.PutPersonWrite)
v1PersonGroup.GET("/image/thumbnail/:shareid", v1.GetPersonImageThumbnail)
v1BatchGroup.DELETE("", v1.DeleteFile) //file/delete
v1BatchGroup.DELETE("/:id/task", v1.DeleteOperateFileOrDir)
v1BatchGroup.POST("/task", v1.PostOperateFileOrDir) //file/operate
v1BatchGroup.GET("", v1.GetDownloadFile)
}
v1ImageGroup := v1Group.Group("/image")
v1ImageGroup.Use()
{
v1ImageGroup.GET("", v1.GetFileImage)
}
v1DisksGroup := v1Group.Group("/disks")
v1DisksGroup.Use()
{
//v1DiskGroup.GET("/check", v1.GetDiskCheck) //delete
//v1DisksGroup.GET("", v1.GetDiskInfo)
//v1DisksGroup.POST("", v1.PostMountDisk)
v1DisksGroup.GET("", v1.GetDiskList)
// //format storage
// v1DiskGroup.POST("/format", v1.PostDiskFormat)
// //mount SATA disk
// v1DiskGroup.POST("/mount", v1.PostMountDisk)
// //umount sata disk
// v1DiskGroup.POST("/umount", v1.PostDiskUmount)
//v1DiskGroup.GET("/type", v1.FormatDiskType)//delete
v1DisksGroup.DELETE("/part", v1.RemovePartition) //disk/delpart
}
v1StorageGroup := v1Group.Group("/storage")
v1StorageGroup.Use()
{
v1StorageGroup.POST("", v1.PostDiskAddPartition)
v1StorageGroup.PUT("", v1.PostDiskFormat)
v1StorageGroup.DELETE("", v1.PostDiskUmount)
}
v1Group.GET("/sync/config", v1.GetSyncConfig)
}
return r
}

View file

@ -3,7 +3,6 @@ package v1
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"github.com/IceWhaleTech/CasaOS/model"
@ -37,10 +36,14 @@ func AppList(c *gin.Context) {
categoryId := c.DefaultQuery("category_id", "0")
key := c.DefaultQuery("key", "")
if len(index) == 0 || len(size) == 0 || len(t) == 0 || len(categoryId) == 0 {
c.JSON(http.StatusOK, &model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, &model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
collection, err := service.MyService.Casa().GetServerList(index, size, t, categoryId, key)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
collection := service.MyService.Casa().GetServerList(index, size, t, categoryId, key)
// for i := 0; i < len(recommend); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
// if ct != nil {
@ -64,7 +67,7 @@ func AppList(c *gin.Context) {
data["list"] = collection.List
data["community"] = collection.Community
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary 获取一个可用端口
@ -83,7 +86,8 @@ func GetPort(c *gin.Context) {
p, _ = port2.GetAvailablePort(t)
ok = !port2.IsPortAvailable(p, t)
}
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
// @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: p})
}
// @Summary 检查端口是否可用
@ -98,7 +102,7 @@ func GetPort(c *gin.Context) {
func PortCheck(c *gin.Context) {
p, _ := strconv.Atoi(c.Param("port"))
t := c.DefaultQuery("type", "tcp")
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port2.IsPortAvailable(p, t)})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: port2.IsPortAvailable(p, t)})
}
// @Summary 我的应用列表
@ -117,10 +121,10 @@ func MyAppList(c *gin.Context) {
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
data := make(map[string]interface{}, 2)
data["list"] = list
data["local"] = unTranslation
data["casaos_apps"] = list
data["local_apps"] = unTranslation
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary my app hardware usage list
@ -132,7 +136,7 @@ func MyAppList(c *gin.Context) {
// @Router /app/usage [get]
func AppUsageList(c *gin.Context) {
list := service.MyService.App().GetHardwareUsage()
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary 应用详情
@ -147,7 +151,11 @@ func AppInfo(c *gin.Context) {
id := c.Param("id")
language := c.GetHeader("Language")
info := service.MyService.Casa().GetServerAppInfo(id, "", language)
info, err := service.MyService.Casa().GetServerAppInfo(id, "", language)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
if info.NetworkModel != "host" {
for i := 0; i < len(info.Ports); i++ {
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {
@ -214,7 +222,7 @@ func AppInfo(c *gin.Context) {
info.MaxMemory = (service.MyService.System().GetMemInfo()["total"]).(uint64) >> 20
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info})
}
// @Summary 获取远程分类列表
@ -225,7 +233,11 @@ func AppInfo(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /app/category [get]
func CategoryList(c *gin.Context) {
list := service.MyService.Casa().GetServerCategoryList()
list, err := service.MyService.Casa().GetServerCategoryList()
if err != nil {
c.JSON(common_err.SERVICE_ERROR, &model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
var count uint = 0
for _, category := range list {
count += category.Count
@ -234,7 +246,7 @@ func CategoryList(c *gin.Context) {
rear := append([]model.CategoryList{}, list[0:]...)
list = append(list[:0], model.CategoryList{Count: count, Name: "All", Font: "apps"})
list = append(list, rear...)
c.JSON(http.StatusOK, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
c.JSON(common_err.SUCCESS, &model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary 分享该应用配置
@ -247,5 +259,5 @@ func CategoryList(c *gin.Context) {
func ShareAppFile(c *gin.Context) {
str, _ := ioutil.ReadAll(c.Request.Body)
content := service.MyService.Casa().ShareAppFile(str)
c.JSON(http.StatusOK, json.RawMessage(content))
c.JSON(common_err.SUCCESS, json.RawMessage(content))
}

View file

@ -9,8 +9,9 @@ import (
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
@ -28,7 +29,42 @@ var diskMap = make(map[string]string)
// @Success 200 {string} string "ok"
// @Router /disk/list [get]
func GetDiskList(c *gin.Context) {
path := c.Query("path")
if len(path) > 0 {
m := service.MyService.Disk().GetDiskInfo(path)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
return
}
t := c.DefaultQuery("type", "")
list := service.MyService.Disk().LSBLK(false)
if t == "usb" {
data := []model.DriveUSB{}
for _, v := range list {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
data = append(data, temp)
}
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
return
}
dbList := service.MyService.Disk().GetSerialAll()
part := make(map[string]int64, len(dbList))
for _, v := range dbList {
@ -154,7 +190,7 @@ func GetDiskList(c *gin.Context) {
data["storage"] = storage
data["avail"] = avail
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary get disk list
@ -191,49 +227,6 @@ func GetDiskInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m})
}
// @Summary format storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "e.g. /dev/sda1"
// @Param pwd formData string true "user password"
// @Param volume formData string true "mount point"
// @Success 200 {string} string "ok"
// @Router /disk/format [post]
func PostDiskFormat(c *gin.Context) {
path := c.PostForm("path")
t := "ext4"
pwd := c.PostForm("pwd")
volume := c.PostForm("volume")
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if len(path) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
diskMap[path] = "busying"
service.MyService.Disk().UmountPointAndRemoveDir(path)
format := service.MyService.Disk().FormatDisk(path, t)
if len(format) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
delete(diskMap, path)
return
}
service.MyService.Disk().MountDisk(path, volume)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 获取支持的格式
// @Produce application/json
// @Accept application/json
@ -256,15 +249,17 @@ func FormatDiskType(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /disk/delpart [delete]
func RemovePartition(c *gin.Context) {
path := c.PostForm("path")
js := make(map[string]string)
c.ShouldBind(&js)
path := js["path"]
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
}
var p = path[:len(path)-1]
var n = path[len(path)-1:]
service.MyService.Disk().DelPartition(p, n)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary add storage
@ -280,32 +275,40 @@ func RemovePartition(c *gin.Context) {
// @Router /disk/storage [post]
func PostDiskAddPartition(c *gin.Context) {
name := c.PostForm("name")
path := c.PostForm("path")
format, _ := strconv.ParseBool(c.PostForm("format"))
js := make(map[string]interface{})
c.ShouldBind(&js)
path := js["path"].(string)
name := js["name"].(string)
format := js["format"].(bool)
if len(name) == 0 || len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
if !file.CheckNotExist("/DATA/" + name) {
// /mnt/name exist
c.JSON(http.StatusOK, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)})
return
}
diskMap[path] = "busying"
currentDisk := service.MyService.Disk().GetDiskInfo(path)
if !format {
if len(currentDisk.Children) != 1 || !(len(currentDisk.Children) > 0 && currentDisk.Children[0].FsType == "ext4") {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)})
delete(diskMap, path)
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)})
return
}
} else {
// format := service.MyService.Disk().FormatDisk(path+"1", "ext4")
// if len(format) == 0 {
// delete(diskMap, path)
// c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
// return
// }
service.MyService.Disk().AddPartition(path)
}
@ -321,7 +324,7 @@ func PostDiskAddPartition(c *gin.Context) {
}
currentDisk = service.MyService.Disk().GetDiskInfo(path)
if len(currentDisk.Children) != 1 {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)})
return
}
@ -340,47 +343,61 @@ func PostDiskAddPartition(c *gin.Context) {
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
//send notify to client
msg := notify.StorageMessage{}
msg.Action = "ADDED"
msg.Path = currentDisk.Children[0].Path
msg.Volume = mountPath
msg.Size = currentDisk.Children[0].Size
msg.Type = currentDisk.Children[0].Tran
service.MyService.Notify().SendStorageBySocket(msg)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary add mount point
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "for example: /dev/sda1"
// @Param serial formData string true "disk id"
// @Param pwd formData string true "user password"
// @Param volume formData string true "mount point"
// @Success 200 {string} string "ok"
// @Router /disk/mount [post]
func PostMountDisk(c *gin.Context) {
// for example: path=/dev/sda1
path := c.PostForm("path")
serial := c.PostForm("serial")
mountPath := "/DATA/volume"
var list = service.MyService.Disk().GetSerialAll()
var pathMapList = make(map[string]string, len(list))
for _, v := range list {
pathMapList[v.MountPoint] = "1"
// @Router /disk/format [post]
func PostDiskFormat(c *gin.Context) {
id := c.GetHeader("user_id")
js := make(map[string]string)
c.ShouldBind(&js)
path := js["path"]
t := "ext4"
pwd := js["password"]
volume := js["volume"]
user := service.MyService.User().GetUserAllInfoById(id)
if user.Id == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if encryption.GetMD5ByStr(pwd) != user.Password {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
for i := 0; i < len(list)+1; i++ {
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
mountPath = mountPath + strconv.Itoa(i)
break
if len(path) == 0 || len(t) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
//mount dir
service.MyService.Disk().MountDisk(path, mountPath)
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path
m.UUID = serial
m.State = 0
//service.MyService.Disk().SaveMountPoint(m)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
diskMap[path] = "busying"
service.MyService.Disk().UmountPointAndRemoveDir(path)
format := service.MyService.Disk().FormatDisk(path, t)
if len(format) == 0 {
delete(diskMap, path)
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)})
return
}
service.MyService.Disk().MountDisk(path, volume)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary remove mount point
@ -394,22 +411,30 @@ func PostMountDisk(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /disk/umount [post]
func PostDiskUmount(c *gin.Context) {
id := c.GetHeader("user_id")
js := make(map[string]string)
c.ShouldBind(&js)
path := c.PostForm("path")
mountPoint := c.PostForm("volume")
pwd := c.PostForm("pwd")
path := js["path"]
mountPoint := js["volume"]
pwd := js["password"]
if len(path) == 0 || len(mountPoint) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
user := service.MyService.User().GetUserAllInfoById(id)
if user.Id == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if encryption.GetMD5ByStr(pwd) != user.Password {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)})
return
}
@ -417,7 +442,16 @@ func PostDiskUmount(c *gin.Context) {
//delete data
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
service.MyService.Disk().RemoveLSBLKCache()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
//send notify to client
msg := notify.StorageMessage{}
msg.Action = "REMOVED"
msg.Path = path
msg.Volume = mountPoint
msg.Size = 0
msg.Type = ""
service.MyService.Notify().SendStorageBySocket(msg)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary confirm delete disk
@ -455,45 +489,10 @@ func GetDiskCheck(c *gin.Context) {
for _, v := range dbList {
if _, ok := mapList[v.UUID]; !ok {
//disk undefind
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: "disk undefind"})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "disk undefind"})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary check mount point
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/usb [get]
func GetUSBList(c *gin.Context) {
list := service.MyService.Disk().LSBLK(false)
data := []model.DriveUSB{}
for _, v := range list {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
data = append(data, temp)
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}

View file

@ -4,6 +4,7 @@ import (
"bytes"
json2 "encoding/json"
"net/http"
"os/exec"
"path/filepath"
"strconv"
"strings"
@ -15,6 +16,7 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/docker"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
"github.com/IceWhaleTech/CasaOS/service"
@ -25,6 +27,7 @@ import (
"github.com/gorilla/websocket"
"github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
"golang.org/x/crypto/ssh"
)
@ -41,14 +44,14 @@ func DockerTerminal(c *gin.Context) {
row := c.DefaultQuery("rows", "30")
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
defer conn.Close()
container := c.Param("id")
hr, err := service.Exec(container, row, col)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
// 关闭I/O流
@ -63,14 +66,41 @@ func DockerTerminal(c *gin.Context) {
docker.WsReaderCopy(conn, hr.Conn)
}
//打开本机的ssh接口
func WsSsh(c *gin.Context) {
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
func PostSshLogin(c *gin.Context) {
j := make(map[string]string)
c.ShouldBind(&j)
userName := j["username"]
password := j["password"]
port := j["port"]
if userName == "" || password == "" || port == "" {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS), Data: "Username or password or port is empty"})
return
}
_, err := docker.NewSshClient(userName, password, port)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: "Please check if the username and port are correct, and make sure that ssh server is installed."})
loger.Error("connect ssh error", zap.Any("error", err))
return
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
func WsSsh(c *gin.Context) {
_, e := exec.LookPath("ssh")
if e != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "ssh server not found"})
return
}
userName := c.Query("username")
password := c.Query("password")
port := c.Query("port")
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
var logBuff = new(bytes.Buffer)
quitChan := make(chan bool, 3)
user := ""
password := ""
// user := ""
// password := ""
var login int = 1
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
@ -78,14 +108,16 @@ func WsSsh(c *gin.Context) {
for login != 0 {
var err error
wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
user = docker.ReceiveWsMsgUser(wsConn, logBuff)
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
client, err = docker.NewSshClient(user, password)
if userName == "" || password == "" || port == "" {
wsConn.WriteMessage(websocket.TextMessage, []byte("username or password or port is empty"))
}
// wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
// user = docker.ReceiveWsMsgUser(wsConn, logBuff)
// wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
// wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
// password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
// wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
client, err = docker.NewSshClient(userName, password, port)
if err != nil && client == nil {
wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
@ -110,25 +142,6 @@ func WsSsh(c *gin.Context) {
}
//安装进度推送
func SpeedPush(c *gin.Context) {
//token := c.Query("token")
//if len(token) == 0 || token != config.UserInfo.Token {
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR_AUTH_TOKEN, Message: common_err.GetMsg(common_err.ERROR_AUTH_TOKEN)})
// return
//}
//ws, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
//defer ws.Close()
//
//for {
// select {
// case msg := <-WSMSG:
// ws.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintln(msg)))
// }
//}
}
// @Summary 安装app(该接口需要post json数据)
// @Produce application/json
// @Accept application/json
@ -144,7 +157,7 @@ func SpeedPush(c *gin.Context) {
func InstallApp(c *gin.Context) {
var appInfo model.ServerAppList
m := model.CustomizationPostData{}
c.BindJSON(&m)
c.ShouldBind(&m)
const CUSTOM = "custom"
var dockerImage string
@ -154,19 +167,22 @@ func InstallApp(c *gin.Context) {
if len(m.Protocol) == 0 {
m.Protocol = "http"
}
if m.Origin != "custom" {
oldName := m.Label
m.ContainerName = strings.Replace(m.Label, " ", "_", -1)
if m.Origin != CUSTOM {
oldName := m.ContainerName
oldLabel := m.Label
for i := 0; true; i++ {
if i != 0 {
m.Label = oldName + "-" + strconv.Itoa(i)
m.ContainerName = oldName + "-" + strconv.Itoa(i)
m.Label = oldLabel + "-" + strconv.Itoa(i)
}
if _, err := service.MyService.Docker().DockerListByName(m.Label); err != nil {
if _, err := service.MyService.Docker().DockerListByName(m.ContainerName); err != nil {
break
}
}
} else {
if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR_APP_NAME_EXIST, Message: common_err.GetMsg(common_err.ERROR_APP_NAME_EXIST)})
if _, err := service.MyService.Docker().DockerListByName(m.ContainerName); err == nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.ERROR_APP_NAME_EXIST, Message: common_err.GetMsg(common_err.ERROR_APP_NAME_EXIST)})
return
}
@ -177,7 +193,7 @@ func InstallApp(c *gin.Context) {
//c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
portMap, _ := strconv.Atoi(m.PortMap)
if !port2.IsPortAvailable(portMap, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + m.PortMap})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + m.PortMap})
return
}
}
@ -199,33 +215,33 @@ func InstallApp(c *gin.Context) {
if u.Protocol == "udp" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "tcp" {
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "both" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
}
}
if m.Origin == "custom" {
if m.Origin == CUSTOM {
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: common_err.DEVICE_NOT_EXIST, Message: device.Path + "," + common_err.GetMsg(common_err.DEVICE_NOT_EXIST)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DEVICE_NOT_EXIST, Message: device.Path + "," + common_err.GetMsg(common_err.DEVICE_NOT_EXIST)})
return
}
@ -263,7 +279,7 @@ func InstallApp(c *gin.Context) {
// installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
// installLog.Id = uuid.NewV4().String()
// service.MyService.Notify().AddLog(installLog)
if m.Origin != "custom" {
if m.Origin != CUSTOM {
for _, plugin := range appInfo.Plugins {
if plugin == "mysql" {
mid := uuid.NewV4().String()
@ -349,7 +365,7 @@ func InstallApp(c *gin.Context) {
// echo -e "hellow\nworld" >>
//step启动容器
err = service.MyService.Docker().DockerContainerStart(m.Label)
err = service.MyService.Docker().DockerContainerStart(m.ContainerName)
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
notify := notify.Application{}
@ -372,7 +388,7 @@ func InstallApp(c *gin.Context) {
}
//step: 启动成功 检查容器状态确认启动成功
container, err := service.MyService.Docker().DockerContainerInfo(m.Label)
container, err := service.MyService.Docker().DockerContainerInfo(m.ContainerName)
if err != nil && container.ContainerJSONBase.State.Running {
notify := notify.Application{}
notify.Icon = m.Icon
@ -405,7 +421,7 @@ func InstallApp(c *gin.Context) {
}()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m.Label})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m.Label})
}
@ -426,7 +442,7 @@ func InstallApp(c *gin.Context) {
// // appInfo := service.MyService.App().GetServerAppInfo(appId)
//
// m := model.CustomizationPostData{}
// c.BindJSON(&m)
// c.ShouldBind(&m)
// //检查端口
// if len(m.PortMap) == 0 || m.PortMap == "0" {
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
@ -603,27 +619,27 @@ func UnInstallApp(c *gin.Context) {
appId := c.Param("id")
if len(appId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
//info := service.MyService.App().GetUninstallInfo(appId)
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
//step停止容器
err = service.MyService.Docker().DockerContainerStop(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
return
}
err = service.MyService.Docker().DockerContainerRemove(appId, false)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.UNINSTALL_APP_ERROR, Message: common_err.GetMsg(common_err.UNINSTALL_APP_ERROR), Data: err.Error()})
return
}
@ -688,7 +704,7 @@ func UnInstallApp(c *gin.Context) {
notify.Success = true
notify.Finished = true
service.MyService.Notify().SendUninstallAppBySocket(notify)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
@ -703,26 +719,35 @@ func UnInstallApp(c *gin.Context) {
// @Router /app/state/{id} [put]
func ChangAppState(c *gin.Context) {
appId := c.Param("id")
state := c.DefaultPostForm("state", "stop")
js := make(map[string]string)
c.ShouldBind(&js)
state := js["state"]
if len(appId) == 0 || len(state) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
var err error
if state == "stop" {
err = service.MyService.Docker().DockerContainerStop(appId)
} else if state == "start" {
if state == "start" {
err = service.MyService.Docker().DockerContainerStart(appId)
} else if state == "restart" {
service.MyService.Docker().DockerContainerStop(appId)
err = service.MyService.Docker().DockerContainerStart(appId)
} else {
err = service.MyService.Docker().DockerContainerStop(appId)
}
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
info, err := service.MyService.App().GetContainerInfo(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info.State})
// @tiger - 用 {'state': ...} 来体现出参上下文
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: info.State})
}
// @Summary 查看容器日志
@ -736,7 +761,7 @@ func ChangAppState(c *gin.Context) {
func ContainerLog(c *gin.Context) {
appId := c.Param("id")
log, _ := service.MyService.Docker().DockerContainerLog(appId)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: log})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: log})
}
// @Summary 获取容器状态
@ -750,10 +775,10 @@ func ContainerLog(c *gin.Context) {
// @Router /app/state/{id} [get]
func GetContainerState(c *gin.Context) {
id := c.Param("id")
t := c.DefaultQuery("type", "0")
//t := c.DefaultQuery("type", "0")
containerInfo, e := service.MyService.App().GetSimpleContainerInfo(id)
if e != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: e.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: e.Error()})
return
}
@ -761,12 +786,12 @@ func GetContainerState(c *gin.Context) {
data["state"] = containerInfo.State
if t == "1" {
appInfo := service.MyService.App().GetAppDBInfo(id)
data["app"] = appInfo
}
// if t == "1" {
// appInfo := service.MyService.App().GetAppDBInfo(id)
// data["app"] = appInfo
// }
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary 更新设置
@ -786,10 +811,10 @@ func UpdateSetting(c *gin.Context) {
id := c.Param("id")
const CUSTOM = "custom"
m := model.CustomizationPostData{}
c.BindJSON(&m)
c.ShouldBind(&m)
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
//var cpd model.CustomizationPostData
@ -809,7 +834,7 @@ func UpdateSetting(c *gin.Context) {
portMap, _ := strconv.Atoi(m.PortMap)
if !port2.IsPortAvailable(portMap, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + m.PortMap})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + m.PortMap})
return
}
@ -819,28 +844,28 @@ func UpdateSetting(c *gin.Context) {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "tcp" {
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
} else if u.Protocol == "both" {
t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: "Duplicate port:" + u.CommendPort})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: "Duplicate port:" + u.CommendPort})
return
}
}
@ -851,9 +876,9 @@ func UpdateSetting(c *gin.Context) {
containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m)
if err != nil {
service.MyService.Docker().DockerContainerUpdateName(m.Label, id)
service.MyService.Docker().DockerContainerUpdateName(m.ContainerName, id)
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
// echo -e "hellow\nworld" >>
@ -862,7 +887,7 @@ func UpdateSetting(c *gin.Context) {
err = service.MyService.Docker().DockerContainerStart(containerId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
service.MyService.Docker().DockerContainerRemove(id, true)
@ -933,7 +958,7 @@ func UpdateSetting(c *gin.Context) {
//service.MyService.App().UpdateApp(appInfo)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary update app version
@ -948,20 +973,20 @@ func PutAppUpdate(c *gin.Context) {
id := c.Param("id")
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
inspect, err := service.MyService.Docker().DockerContainerInfo(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
imageLatest := strings.Split(inspect.Config.Image, ":")[0] + ":latest"
err = service.MyService.Docker().DockerPullImage(imageLatest, "", "")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
@ -974,7 +999,7 @@ func PutAppUpdate(c *gin.Context) {
if err != nil {
service.MyService.Docker().DockerContainerUpdateName(inspect.Name, id)
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
@ -982,13 +1007,13 @@ func PutAppUpdate(c *gin.Context) {
err = service.MyService.Docker().DockerContainerStart(containerId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
service.MyService.Docker().DockerContainerRemove(id, true)
delete(service.NewVersionApp, id)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 获取容器详情
@ -1001,6 +1026,8 @@ func PutAppUpdate(c *gin.Context) {
// @Router /app/info/{id} [get]
func ContainerInfo(c *gin.Context) {
appId := c.Param("id")
// @tiger - 作为最佳实践,不应该直接把数据库的信息返回,来避免未来数据库结构上的迭代带来的新字段
appInfo := service.MyService.App().GetAppDBInfo(appId)
containerInfo, _ := service.MyService.Docker().DockerContainerStats(appId)
var cpuModel = "arm"
@ -1015,44 +1042,34 @@ func ContainerInfo(c *gin.Context) {
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
//todo 需要自定义错误
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
con := struct {
Status string `json:"status"`
StartedAt string `json:"started_at"`
CPUShares int64 `json:"cpu_shares"`
Memory int64 `json:"memory"`
Restart string `json:"restart"`
Memory int64 `json:"total_memory"` // @tiger - 改成 total_memory方便以后增加 free_memory 之类的字段
Restart string `json:"restart_policy"` // @tiger - 改成 restart_policy?
}{Status: info.State.Status, StartedAt: info.State.StartedAt, CPUShares: info.HostConfig.CPUShares, Memory: info.HostConfig.Memory >> 20, Restart: info.HostConfig.RestartPolicy.Name}
data := make(map[string]interface{}, 5)
data["app"] = appInfo
data["cpu"] = cpuModel
data["memory"] = service.MyService.System().GetMemInfo()["total"]
data["app"] = appInfo // @tiget - 最佳实践是,返回 appid然后具体的 app 信息由前端另行获取
data["cpu"] = cpuModel // @tiger - 改成 arch
data["memory"] = service.MyService.System().GetMemInfo()["total"] // @tiger - 改成 total_memory方便以后增加 free_memory 之类的字段
data["container"] = json2.RawMessage(containerInfo)
data["info"] = con
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary 获取安装所需要的数据
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/install/config [get]
func GetDockerInstallConfig(c *gin.Context) {
func GetDockerNetworks(c *gin.Context) {
networks := service.MyService.Docker().DockerNetworkModelList()
data := make(map[string]interface{}, 2)
list := []map[string]string{}
for _, network := range networks {
if network.Driver != "null" {
list = append(list, map[string]string{"name": network.Name, "driver": network.Driver, "id": network.ID})
}
}
data["networks"] = list
data["memory"] = service.MyService.System().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary 获取依赖数据
@ -1069,7 +1086,6 @@ func ContainerRelyInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: appInfo})
}
// @Summary 获取可更新数据
// @Produce application/json
// @Accept application/json
// @Tags app
@ -1083,7 +1099,7 @@ func ContainerUpdateInfo(c *gin.Context) {
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: err.Error()})
return
}
var port model.PortArray
@ -1161,7 +1177,7 @@ func ContainerUpdateInfo(c *gin.Context) {
}
m.NetworkModel = string(info.HostConfig.NetworkMode)
m.Description = info.Config.Labels["desc"]
m.Label = strings.ReplaceAll(info.Name, "/", "")
m.ContainerName = strings.ReplaceAll(info.Name, "/", "")
m.PortMap = info.Config.Labels["web"]
m.Devices = driver
m.Envs = envs
@ -1181,6 +1197,11 @@ func ContainerUpdateInfo(c *gin.Context) {
m.Cmd = info.Config.Cmd
m.HostName = info.Config.Hostname
m.Privileged = info.HostConfig.Privileged
name := info.Config.Labels["name"]
if len(name) == 0 {
name = strings.ReplaceAll(info.Name, "/", "")
}
m.Label = name
m.Protocol = info.Config.Labels["protocol"]
if m.Protocol == "" {

View file

@ -1,9 +1,6 @@
package v1
import (
"bufio"
"encoding/csv"
"fmt"
"io"
"io/ioutil"
"log"
@ -26,32 +23,6 @@ import (
uuid "github.com/satori/go.uuid"
)
func downloadReadFile(c *gin.Context) {
//http下载地址 csv
csvFileUrl := c.PostForm("file_name")
res, err := http.Get(csvFileUrl)
if err != nil {
c.String(400, err.Error())
return
}
defer res.Body.Close()
//读取csv
reader := csv.NewReader(bufio.NewReader(res.Body))
for {
line, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
c.String(400, err.Error())
return
}
//line 就是每一行的内容
fmt.Println(line)
//line[0] 就是第几列
fmt.Println(line[0])
}
}
// @Summary 读取文件
// @Produce application/json
// @Accept application/json
@ -63,14 +34,14 @@ func downloadReadFile(c *gin.Context) {
func GetFilerContent(c *gin.Context) {
filePath := c.Query("path")
if len(filePath) == 0 {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
return
}
if !file.Exists(filePath) {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
})
@ -79,7 +50,7 @@ func GetFilerContent(c *gin.Context) {
//文件读取任务是将文件内容读取到内存中。
info, err := ioutil.ReadFile(filePath)
if err != nil {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_READ_ERROR,
Message: common_err.GetMsg(common_err.FILE_READ_ERROR),
Data: err.Error(),
@ -88,8 +59,7 @@ func GetFilerContent(c *gin.Context) {
}
result := string(info)
//返回结果
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.SUCCESS, model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: result,
@ -121,18 +91,18 @@ func GetLocalFile(c *gin.Context) {
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param t query string false "Compression format" Enums(zip,tar,targz)
// @Param format query string false "Compression format" Enums(zip,tar,targz)
// @Param files query string true "file list eg: filename1,filename2,filename3 "
// @Success 200 {string} string "ok"
// @Router /file/download [get]
func GetDownloadFile(c *gin.Context) {
t := c.Query("t")
t := c.Query("format")
files := c.Query("files")
if len(files) == 0 {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
@ -141,7 +111,7 @@ func GetDownloadFile(c *gin.Context) {
list := strings.Split(files, ",")
for _, v := range list {
if !file.Exists(v) {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
})
@ -179,7 +149,7 @@ func GetDownloadFile(c *gin.Context) {
extension, ar, err := file.GetCompressionAlgorithm(t)
if err != nil {
c.JSON(http.StatusOK, model.Result{
c.JSON(common_err.CLIENT_ERROR, model.Result{
Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
@ -188,9 +158,9 @@ func GetDownloadFile(c *gin.Context) {
err = ar.Create(c.Writer)
if err != nil {
c.JSON(http.StatusOK, model.Result{
Success: common_err.ERROR,
Message: common_err.GetMsg(common_err.ERROR),
c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.SERVICE_ERROR,
Message: common_err.GetMsg(common_err.SERVICE_ERROR),
Data: err.Error(),
})
return
@ -213,8 +183,22 @@ func GetDownloadFile(c *gin.Context) {
}
func GetDownloadSingleFile(c *gin.Context) {
filePath := c.Param("path")
fileTmp, _ := os.Open(filePath)
filePath := c.Query("path")
if len(filePath) == 0 {
c.JSON(service.ClientCount, model.Result{
Success: common_err.INVALID_PARAMS,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
return
}
fileTmp, err := os.Open(filePath)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{
Success: common_err.FILE_DOES_NOT_EXIST,
Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST),
})
return
}
defer fileTmp.Close()
fileName := path.Base(filePath)
@ -297,7 +281,7 @@ func DirPath(c *gin.Context) {
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: pathList})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: pathList})
}
// @Summary rename file or dir
@ -311,15 +295,15 @@ func DirPath(c *gin.Context) {
// @Router /file/rename [put]
func RenamePath(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
op := json["oldpath"]
np := json["newpath"]
c.ShouldBind(&json)
op := json["old_path"]
np := json["new_path"]
if len(op) == 0 || len(np) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
success, err := service.MyService.System().RenameFile(op, np)
c.JSON(http.StatusOK, model.Result{Success: success, Message: common_err.GetMsg(success), Data: err})
c.JSON(common_err.SUCCESS, model.Result{Success: success, Message: common_err.GetMsg(success), Data: err})
}
// @Summary create folder
@ -332,11 +316,11 @@ func RenamePath(c *gin.Context) {
// @Router /file/mkdir [post]
func MkdirAll(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
c.ShouldBind(&json)
path := json["path"]
var code int
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
// decodedPath, err := url.QueryUnescape(path)
@ -345,7 +329,7 @@ func MkdirAll(c *gin.Context) {
// return
// }
code, _ = service.MyService.System().MkdirAll(path)
c.JSON(http.StatusOK, model.Result{Success: code, Message: common_err.GetMsg(code)})
c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
}
// @Summary create file
@ -358,11 +342,11 @@ func MkdirAll(c *gin.Context) {
// @Router /file/create [post]
func PostCreateFile(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
c.ShouldBind(&json)
path := json["path"]
var code int
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
// decodedPath, err := url.QueryUnescape(path)
@ -371,7 +355,7 @@ func PostCreateFile(c *gin.Context) {
// return
// }
code, _ = service.MyService.System().CreateFile(path)
c.JSON(http.StatusOK, model.Result{Success: code, Message: common_err.GetMsg(code)})
c.JSON(common_err.SUCCESS, model.Result{Success: code, Message: common_err.GetMsg(code)})
}
// @Summary upload file
@ -452,7 +436,7 @@ func PostFileUpload(c *gin.Context) {
defer out.Close()
_, err := io.Copy(out, f)
if err != nil {
c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
} else {
@ -460,7 +444,7 @@ func PostFileUpload(c *gin.Context) {
defer out.Close()
_, err := io.Copy(out, f)
if err != nil {
c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
@ -468,7 +452,7 @@ func PostFileUpload(c *gin.Context) {
}
fileNum, err := ioutil.ReadDir(tempDir)
if err != nil {
c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
if totalChunks == len(fileNum) {
@ -476,7 +460,7 @@ func PostFileUpload(c *gin.Context) {
file.RMDir(tempDir)
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary copy or move file
@ -490,14 +474,14 @@ func PostFileUpload(c *gin.Context) {
func PostOperateFileOrDir(c *gin.Context) {
list := model.FileOperate{}
c.BindJSON(&list)
c.ShouldBind(&list)
if len(list.Item) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if list.To == list.Item[0].From[:strings.LastIndex(list.Item[0].From, "/")] {
c.JSON(http.StatusOK, model.Result{Success: common_err.SOURCE_DES_SAME, Message: common_err.GetMsg(common_err.SOURCE_DES_SAME)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SOURCE_DES_SAME, Message: common_err.GetMsg(common_err.SOURCE_DES_SAME)})
return
}
@ -526,7 +510,7 @@ func PostOperateFileOrDir(c *gin.Context) {
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary delete file
@ -540,9 +524,9 @@ func PostOperateFileOrDir(c *gin.Context) {
func DeleteFile(c *gin.Context) {
paths := []string{}
c.BindJSON(&paths)
c.ShouldBind(&paths)
if len(paths) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
// path := c.Query("path")
@ -552,12 +536,12 @@ func DeleteFile(c *gin.Context) {
for _, v := range paths {
err := os.RemoveAll(v)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary update file
@ -572,26 +556,26 @@ func DeleteFile(c *gin.Context) {
func PutFileContent(c *gin.Context) {
fi := model.FileUpdate{}
c.BindJSON(&fi)
c.ShouldBind(&fi)
// path := c.PostForm("path")
// content := c.PostForm("content")
if !file.Exists(fi.FilePath) {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
return
}
//err := os.Remove(path)
err := os.RemoveAll(fi.FilePath)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DELETE_ERROR, Message: common_err.GetMsg(common_err.FILE_DELETE_ERROR), Data: err})
return
}
err = file.CreateFileAndWriteContent(fi.FilePath, fi.FileContent)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary image thumbnail/original image
@ -607,13 +591,13 @@ func GetFileImage(c *gin.Context) {
t := c.Query("type")
path := c.Query("path")
if !file.Exists(path) {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
return
}
if t == "thumbnail" {
f, err := file.GetImage(path, 100, 0)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
c.Writer.WriteString(string(f))
@ -621,13 +605,13 @@ func GetFileImage(c *gin.Context) {
}
f, err := os.Open(path)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: err.Error()})
return
}
c.Writer.WriteString(string(data))
@ -652,5 +636,5 @@ func DeleteOperateFileOrDir(c *gin.Context) {
}
go service.MyService.Notify().SendFileOperateNotify(true)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}

View file

@ -1,804 +0,0 @@
package v1
import (
"bytes"
"encoding/base64"
"encoding/gob"
"encoding/json"
"io/ioutil"
"net"
"net/http"
"os"
"reflect"
"strconv"
"strings"
"time"
natType "github.com/Curtis-Milo/nat-type-identifier-go"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
)
// @Summary Retry the file that failed to download
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param uui path string true "download uuid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/refile/{uuid} [get]
func GetPersonReFile(c *gin.Context) {
uid := c.Param("uuid")
_, err := uuid.FromString(uid)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
task := service.MyService.Download().GetDownloadById(uid)
if reflect.DeepEqual(task, model2.PersonDownloadDBModel{}) {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_REMOTE_ERROR, Message: common_err.GetMsg(common_err.PERSON_REMOTE_ERROR)})
return
}
token := task.From
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_REMOTE_ERROR, Message: common_err.GetMsg(common_err.PERSON_REMOTE_ERROR)})
return
}
m := model.MessageModel{}
m.Data = task.Path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDOWNLOAD
m.UUId = uid
go service.Dial(m, false)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary download file
// @Produce application/json
// @Accept application/json
// @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 /person/file [get]
func GetPersonFile(c *gin.Context) {
path := c.Query("path")
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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if file.CheckNotExist(localPath) {
c.JSON(http.StatusOK, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_REMOTE_ERROR, Message: common_err.GetMsg(common_err.PERSON_REMOTE_ERROR)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_REMOTE_ERROR, Message: common_err.GetMsg(common_err.PERSON_REMOTE_ERROR)})
return
}
// task id
uuid := uuid.NewV4().String()
task := model2.PersonDownloadDBModel{}
task.UUID = uuid
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 = types.PERSONFILEDOWNLOAD
task.LocalPath = localPath
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_EXIST_DOWNLOAD, Message: common_err.GetMsg(common_err.PERSON_EXIST_DOWNLOAD)})
return
}
service.MyService.Download().AddDownloadTask(task)
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDOWNLOAD
m.UUId = uuid
go service.Dial(m, false)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary delete download file records
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param uuid path string true "download uuid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/file/{uuid} [delete]
func DeletePersonDownloadFile(c *gin.Context) {
id := c.Param("uuid")
_, err := uuid.FromString(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary Get file download list
// @Produce application/json
// @Accept application/json
// @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 {object} []model2.PersonDownloadDBModel
// @Router /person/list [get]
func GetPersonDownloadList(c *gin.Context) {
state := c.DefaultQuery("state", "")
list := service.MyService.Download().GetDownloadListByState(state, types.PERSONFILEDOWNLOAD)
//if it is downloading, it need to add 'already'
for i := 0; i < len(list); i++ {
if list[i].State == types.DOWNLOADING {
tempDir := config.AppInfo.TempPath + "/" + 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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary edit friend's remarks
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param remarks formData string true "remarks name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
friend.Mark = mark
service.MyService.Friend().EditFriendMark(friend)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary edit friend's
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param write formData bool true "write"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/write/{shareid} [put]
func PutPersonWrite(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
write, _ := strconv.ParseBool(c.PostForm("write"))
friend := model2.FriendModel{}
friend.Token = token
friend.Write = write
service.MyService.Friend().EditFriendMark(friend)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary image thumbnail
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param write formData bool true "write"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/image/thumbnail/{shareid} [get]
func GetPersonImageThumbnail(c *gin.Context) {
token := c.Param("shareid")
path := c.Query("path")
_, err := uuid.FromString(token)
if err != nil || len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONIMAGETHUMBNAIL
m.UUId = uuid
img, err := service.Dial(m, false)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
// var buf bytes.Buffer
//err = gob.NewEncoder(&buf).Encode(img.Data)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
var buf bytes.Buffer
err = gob.NewEncoder(&buf).Encode(img.Data)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
imageBuffer, _ := base64.StdEncoding.DecodeString(img.Data.(string))
c.Writer.WriteString(string(imageBuffer))
// c.String(http.StatusOK, "data:image/"+filesuffix+";base64,"+img.Data.(string))
//c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: img.Data.(string)})
}
// @Summary get my friend list
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @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 {
list[i].OnLine = true
if ip_helper.HasLocalIP(net.ParseIP(strings.Split(v, ":")[0])) {
list[i].LocalIP = strings.Split(v, ":")[0]
}
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary network type detection
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/detection [get]
func GetPersonDetection(c *gin.Context) {
// - Blocked
// - Open Internet
// - Full Cone
// - Symmetric UDP Firewall
// - Restric NAT
// - Restric Port NAT
// - Symmetric NAT
result, err := natType.GetDeterminedNatType(true, 5, "stun.l.google.com")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
//result := service.MyService.Person().GetPersionNetWorkTypeDetection()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: result})
}
// @Summary add friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if v == config.ServerInfo.Token {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_MYSELF, Message: common_err.GetMsg(common_err.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: common_err.PERSON_EXIST_FRIEND, Message: common_err.GetMsg(common_err.PERSON_EXIST_FRIEND)})
return
}
user := service.MyService.Casa().GetUserInfoByShareId(v)
if reflect.DeepEqual(user, model.UserInfo{}) {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_NOT_EXIST_USER, Message: common_err.GetMsg(common_err.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)
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = v
msg.UUId = uuid.NewV4().String()
service.Dial(msg, true)
friend := model2.FriendModel{}
friend.Token = v
friend.Avatar = user.Avatar
friend.Block = false
friend.State = types.FRIENDSTATEWAIT
friend.NickName = user.NickName
friend.Profile = user.Desc
friend.Version = user.Version
service.MyService.Friend().AddFriend(friend)
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary Get a list of directories
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param share_id query string true "Opponent share_id"
// @Param path query string true "dir path"
// @Security ApiKeyAuth
// @Success 200 {object} []model.Path
// @Router /person/directory [get]
func GetPersonDirectory(c *gin.Context) {
path := c.Query("path")
token := c.Query("share_id")
_, err := uuid.FromString(token)
if len(path) == 0 || err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_REMOTE_ERROR, Message: common_err.GetMsg(common_err.PERSON_REMOTE_ERROR)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDIRECTORY
m.UUId = uuid
result, err := service.Dial(m, false)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
dataModel := []model.Path{}
if uuid == m.UUId {
dataModelByte, _ := json.Marshal(result.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if file.CheckNotExist(downPath) {
c.JSON(http.StatusOK, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
var list []string
json.Unmarshal([]byte(share), &list)
if len(list) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
for _, v := range list {
if !file.Exists(v) {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: config.FileSettingInfo.ShareDir})
}
// @Summary Get the shareid
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/shareid [get]
func GetPersonShareId(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: config.ServerInfo.Token})
}
// @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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
friend.Block = block
service.MyService.Friend().EditFriendBlock(friend)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
service.MyService.Friend().DeleteFriend(friend)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary Get public person
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/public [get]
func GetPersonPublic(c *gin.Context) {
list := service.MyService.Casa().GetPersonPublic()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary upload file to friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Param path formData string true "Destination path"
// @Param local_path formData string true "Full path of the file to be uploaded"
// @Success 200 {string} string "ok"
// @Router /person/file/{shareid} [post]
func PostPersonFile(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
path := c.PostForm("path")
localPath := c.PostForm("local_path")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if !file.Exists(localPath) {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONUPLOAD
m.UUId = uuid
go service.UDPSendData(m, localPath)
f, _ := os.Stat(localPath)
task := model2.PersonDownloadDBModel{}
task.UUID = uuid
task.Name = f.Name()
task.Length = 0
task.From = token
task.Path = path
task.Size = f.Size()
task.State = types.DOWNLOADFINISHED
task.Created = time.Now().Unix()
task.Type = types.PERSONFILEUPLOAD
task.LocalPath = localPath
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.PERSON_EXIST_DOWNLOAD, Message: common_err.GetMsg(common_err.PERSON_EXIST_DOWNLOAD)})
return
}
service.MyService.Download().AddDownloadTask(task)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary agree add friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/friend/{shareid} [put]
func PutPersonAgreeFriend(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: token})
if user.State != types.FRIENDSTATEREQUEST {
c.JSON(http.StatusOK, model.Result{Success: common_err.COMMAND_ERROR_INVALID_OPERATION, Message: common_err.GetMsg(common_err.COMMAND_ERROR_INVALID_OPERATION)})
return
}
service.MyService.Friend().AgreeFrined(user.Token)
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = ""
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONAGREEFRIEND
m.UUId = uuid
go service.Dial(m, true)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// // @Summary upload file
// // @Produce application/json
// // @Accept multipart/form-data
// // @Tags person
// // @Security ApiKeyAuth
// // @Param path formData string false "file path"
// // @Param file formData file true "file"
// // @Success 200 {string} string "ok"
// // @Router /person/upload/{shareid} [get]
// func GetPersonFileUpload(c *gin.Context) {
// token := c.Param("shareid")
// _, err := uuid.FromString(token)
// path := c.Query("path")
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
// relative := c.Query("relativePath")
// fileName := c.Query("filename")
// chunkNumber := c.Query("chunkNumber")
// totalChunks, _ := strconv.Atoi(c.DefaultQuery("totalChunks", "0"))
// dirPath := ""
// hash := file.GetHashByContent([]byte(fileName))
// tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
// if fileName != relative {
// dirPath = strings.TrimSuffix(relative, fileName)
// tempDir += dirPath
// file.MkDir(path + "/" + dirPath)
// }
// tempDir += chunkNumber
// if !file.CheckNotExist(tempDir) {
// c.JSON(200, model.Result{Success: 200, Message: common_err.GetMsg(common_err.FILE_ALREADY_EXISTS)})
// return
// }
// c.JSON(204, model.Result{Success: 204, Message: common_err.GetMsg(common_err.SUCCESS)})
// }
// // @Summary upload file
// // @Produce application/json
// // @Accept multipart/form-data
// // @Tags person
// // @Security ApiKeyAuth
// // @Param path formData string false "file path"
// // @Param file formData file true "file"
// // @Success 200 {string} string "ok"
// // @Router /person/upload [post]
// func PostPersonFileUpload(c *gin.Context) {
// token := c.Param("shareid")
// _, err := uuid.FromString(token)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
// f, _, _ := c.Request.FormFile("file")
// relative := c.PostForm("relativePath")
// fileName := c.PostForm("filename")
// totalChunks, _ := strconv.Atoi(c.DefaultPostForm("totalChunks", "0"))
// chunkNumber := c.PostForm("chunkNumber")
// dirPath := ""
// path := c.PostForm("path")
// hash := file.GetHashByContent([]byte(fileName))
// if len(path) == 0 {
// c.JSON(common_err.INVALID_PARAMS, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
// return
// }
// tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
// if fileName != relative {
// dirPath = strings.TrimSuffix(relative, fileName)
// tempDir += dirPath
// file.MkDir(path + "/" + dirPath)
// }
// path += "/" + relative
// if !file.CheckNotExist(tempDir + chunkNumber) {
// file.RMDir(tempDir + chunkNumber)
// }
// if totalChunks > 1 {
// file.IsNotExistMkDir(tempDir)
// out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
// defer out.Close()
// _, err := io.Copy(out, f)
// if err != nil {
// c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
// return
// }
// } else {
// out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
// defer out.Close()
// _, err := io.Copy(out, f)
// if err != nil {
// c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
// return
// }
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
// return
// }
// fileNum, err := ioutil.ReadDir(tempDir)
// if err != nil {
// c.JSON(common_err.ERROR, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
// return
// }
// if totalChunks == len(fileNum) {
// file.RMDir(tempDir)
// }
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
// }

View file

@ -1,107 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-15 14:30:05
* @FilePath: /CasaOS/route/v1/shortcuts.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package v1
import (
"net/http"
"net/url"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin"
)
// @Summary 获取短链列表
// @Produce application/json
// @Accept application/json
// @Tags shortcuts
// @Param username formData string true "User name"
// @Param pwd formData string true "password"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /shortcuts/list [get]
func GetShortcutsList(c *gin.Context) {
list := service.MyService.Shortcuts().GetList()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: list})
}
// @Summary 添加shortcuts
// @Produce application/json
// @Accept application/json
// @Tags shortcuts
// @Param title formData string true "title"
// @Param url formData string true "url"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /shortcuts/add [post]
func PostShortcutsAdd(c *gin.Context) {
var m model2.ShortcutsDBModel
c.BindJSON(&m)
if len(m.Url) == 0 || len(m.Title) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
u, err := url.Parse(m.Url)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.SHORTCUTS_URL_ERROR, Message: common_err.GetMsg(common_err.SHORTCUTS_URL_ERROR), Data: err.Error()})
return
}
m.Icon = "https://api.faviconkit.com/" + u.Host + "/57"
service.MyService.Shortcuts().AddData(m)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 删除shortcuts
// @Produce application/json
// @Accept application/json
// @Tags shortcuts
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /shortcuts/del/{id} [post]
func DeleteShortcutsDelete(c *gin.Context) {
id := c.Param("id")
service.MyService.Shortcuts().DeleteData(id)
c.JSON(http.StatusOK, model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: "",
})
}
// @Summary 编辑shortcuts
// @Produce application/json
// @Accept application/json
// @Tags shortcuts
// @Param title formData string true "title"
// @Param url formData string true "url"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /shortcuts/edit [put]
func PutShortcutsEdit(c *gin.Context) {
var m model2.ShortcutsDBModel
c.BindJSON(&m)
if len(m.Url) == 0 || len(m.Title) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
u, err := url.Parse(m.Url)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.SHORTCUTS_URL_ERROR, Message: common_err.GetMsg(common_err.SHORTCUTS_URL_ERROR), Data: err.Error()})
return
}
m.Icon = "https://api.faviconkit.com/" + u.Host + "/57"
service.MyService.Shortcuts().EditData(m)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: ""})
}

17
route/v1/storage.go Normal file
View file

@ -0,0 +1,17 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-11 16:02:29
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-11 16:02:55
* @FilePath: /CasaOS/route/v1/storage.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package v1
import "github.com/gin-gonic/gin"
func GetStorageList(c *gin.Context) {
}

View file

@ -1,27 +0,0 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-11-08 18:02:02
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-21 19:13:59
* @FilePath: /CasaOS/route/v1/sync.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package v1
import (
"net/http"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/gin-gonic/gin"
)
func GetSyncConfig(c *gin.Context) {
data := make(map[string]string)
data["key"] = config.SystemConfigInfo.SyncKey
data["port"] = config.SystemConfigInfo.SyncPort
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}

View file

@ -1,7 +1,6 @@
package v1
import (
"encoding/json"
"fmt"
"net/http"
"os"
@ -21,7 +20,6 @@ import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
)
@ -45,10 +43,10 @@ func GetSystemCheckVersion(c *gin.Context) {
service.MyService.Notify().AddLog(installLog)
}
data := make(map[string]interface{}, 3)
data["is_need"] = need
data["need_update"] = need
data["version"] = version
data["current_version"] = types.CURRENTVERSION
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary 系统信息
@ -63,12 +61,7 @@ func SystemUpdate(c *gin.Context) {
if need {
service.MyService.System().UpdateSystemVersion(version.Version)
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
//Get system config
func GetSystemConfig(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: ""})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary get logs
@ -80,86 +73,29 @@ func GetSystemConfig(c *gin.Context) {
// @Router /sys/error/logs [get]
func GetCasaOSErrorLogs(c *gin.Context) {
line, _ := strconv.Atoi(c.DefaultQuery("line", "100"))
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
}
// @Summary 修改配置文件
// @Produce application/json
// @Accept multipart/form-data
// @Tags sys
// @Param config formData string true "config json string"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/changhead [post]
func PostSetSystemConfig(c *gin.Context) {
buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf)
service.MyService.System().UpSystemConfig(string(buf[0:n]), "")
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: json.RawMessage(config.SystemConfigInfo.ConfigStr),
})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
}
//系统配置
func GetSystemConfigDebug(c *gin.Context) {
array := service.MyService.System().GetSystemConfigDebug()
disk := service.MyService.System().GetDiskInfo()
sys := service.MyService.System().GetSysInfo()
//todo 准备sync需要显示的数据(镜像,容器)
var systemAppStatus string
images := service.MyService.Docker().IsExistImage("linuxserver/syncthing")
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
list := service.MyService.App().GetSystemAppList()
for _, v := range list {
systemAppStatus += v.Image + ",\n\t"
}
systemAppStatus += "Sync Key length: " + strconv.Itoa(len(config.SystemConfigInfo.SyncKey))
version := service.MyService.Casa().GetCasaosVersion()
var bugContent string = fmt.Sprintf(`
- OS: %s
- CasaOS Version: %s
- Disk Total: %v
- Disk Used: %v
- Sync State: %s
- System Info: %s
- Remote Version: %s
- Browser: $Browser$
- Version: $Version$
`, sys.OS, types.CURRENTVERSION, disk.Total>>20, disk.Used>>20, systemAppStatus, array)
`, sys.OS, types.CURRENTVERSION, disk.Total>>20, disk.Used>>20, array, version.Version)
// array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: bugContent})
}
//widget配置
func GetWidgetConfig(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json.RawMessage(config.SystemConfigInfo.WidgetList)})
}
// @Summary 修改组件配置文件
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/widget/config [post]
func PostSetWidgetConfig(c *gin.Context) {
buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf)
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: json.RawMessage(config.SystemConfigInfo.WidgetList),
})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: bugContent})
}
// @Summary get casaos server port
@ -170,7 +106,7 @@ func PostSetWidgetConfig(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /sys/port [get]
func GetCasaOSPort(c *gin.Context) {
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -188,13 +124,13 @@ func GetCasaOSPort(c *gin.Context) {
// @Router /sys/port [put]
func PutCasaOSPort(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
c.ShouldBind(&json)
portStr := json["port"]
port, err := strconv.Atoi(portStr)
if err != nil {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{
Success: common_err.ERROR,
Success: common_err.SERVICE_ERROR,
Message: err.Error(),
})
return
@ -202,7 +138,7 @@ func PutCasaOSPort(c *gin.Context) {
isAvailable := port2.IsPortAvailable(port, "tcp")
if !isAvailable {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{
Success: common_err.PORT_IS_OCCUPIED,
Message: common_err.GetMsg(common_err.PORT_IS_OCCUPIED),
@ -210,40 +146,13 @@ func PutCasaOSPort(c *gin.Context) {
return
}
service.MyService.System().UpSystemPort(strconv.Itoa(port))
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
})
}
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/init/check [get]
func GetSystemInitCheck(c *gin.Context) {
data := make(map[string]interface{}, 2)
if service.MyService.User().GetUserCount() > 0 {
data["initialized"] = true
data["key"] = ""
} else {
key := uuid.NewV4().String()
service.UserRegisterHash[key] = key
data["key"] = key
data["initialized"] = false
}
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}
// @Summary active killing casaos
// @Produce application/json
// @Accept application/json
@ -263,7 +172,9 @@ func PostKillCasaOS(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /sys/usb/off [put]
func PutSystemUSBAutoMount(c *gin.Context) {
status := c.Param("status")
js := make(map[string]string)
c.ShouldBind(&js)
status := js["status"]
if status == "on" {
service.MyService.System().UpdateUSBAutoMount("True")
service.MyService.System().ExecUSBAutoMountShell("True")
@ -272,7 +183,7 @@ func PutSystemUSBAutoMount(c *gin.Context) {
service.MyService.System().ExecUSBAutoMountShell("False")
}
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -292,7 +203,7 @@ func GetSystemUSBAutoMount(c *gin.Context) {
state = "False"
}
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -300,6 +211,40 @@ func GetSystemUSBAutoMount(c *gin.Context) {
})
}
func GetSystemAppsStatus(c *gin.Context) {
systemAppList := service.MyService.App().GetSystemAppList()
appList := []model2.MyAppList{}
for _, v := range systemAppList {
name := strings.ReplaceAll(v.Names[0], "/", "")
if len(v.Labels["name"]) > 0 {
name = v.Labels["name"]
}
appList = append(appList, model2.MyAppList{
Name: name,
Icon: v.Labels["icon"],
State: v.State,
CustomId: v.Labels["custom_id"],
Id: v.ID,
Port: v.Labels["web"],
Index: v.Labels["index"],
//Order: m.Labels["order"],
Image: v.Image,
Latest: false,
//Type: m.Labels["origin"],
//Slogan: m.Slogan,
//Rely: m.Rely,
Host: v.Labels["host"],
Protocol: v.Labels["protocol"],
})
}
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: appList,
})
}
// @Summary get system hardware info
// @Produce application/json
// @Accept application/json
@ -311,7 +256,7 @@ func GetSystemHardwareInfo(c *gin.Context) {
data := make(map[string]string, 1)
data["drive_model"] = service.MyService.System().GetDeviceTree()
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -454,7 +399,7 @@ func GetSystemUtilization(c *gin.Context) {
data["net"] = newNet
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
// @Summary Get notification port
@ -466,11 +411,11 @@ func GetSystemUtilization(c *gin.Context) {
// @Router /sys/socket/port [get]
func GetSystemSocketPort(c *gin.Context) {
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: config.ServerInfo.SocketPort,
Data: config.ServerInfo.SocketPort, // @tiger 这里最好封装成 {'port': ...} 的形式,来体现出参的上下文
})
}
@ -540,26 +485,3 @@ func GetSystemNetInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: newNet})
}
//********************************************* Soon to be removed ***********************************************
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /guide/check [get]
func GetGuideCheck(c *gin.Context) {
initUser := true
if service.MyService.User().GetUserCount() > 0 {
initUser = false
}
data := make(map[string]interface{}, 1)
data["need_init_user"] = initUser
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}

View file

@ -10,15 +10,17 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/system_model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/common_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
uuid "github.com/satori/go.uuid"
"github.com/tidwall/gjson"
"github.com/IceWhaleTech/CasaOS/service"
@ -29,46 +31,47 @@ import (
// @Router /user/register/ [post]
func PostUserRegister(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
username := json["user_name"]
c.ShouldBind(&json)
username := json["username"]
pwd := json["password"]
key := c.Param("key")
key := json["key"]
if _, ok := service.UserRegisterHash[key]; !ok {
c.JSON(http.StatusOK,
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.KEY_NOT_EXIST, Message: common_err.GetMsg(common_err.KEY_NOT_EXIST)})
return
}
if len(username) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if len(pwd) < 6 {
c.JSON(http.StatusOK,
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.PWD_IS_TOO_SIMPLE, Message: common_err.GetMsg(common_err.PWD_IS_TOO_SIMPLE)})
return
}
oldUser := service.MyService.User().GetUserInfoByUserName(username)
if oldUser.Id > 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.USER_EXIST, Message: common_err.GetMsg(common_err.USER_EXIST)})
return
}
user := model2.UserDBModel{}
user.UserName = username
user.Password = encryption.GetMD5ByStr(config.UserInfo.PWD)
user.Username = username
user.Password = encryption.GetMD5ByStr(pwd)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
file.MkDir(config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id))
delete(service.UserRegisterHash, key)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
@ -82,44 +85,43 @@ func PostUserRegister(c *gin.Context) {
// @Router /user/login [post]
func PostUserLogin(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
c.ShouldBind(&json)
username := json["username"]
pwd := json["pwd"]
password := json["password"]
//check params is empty
if len(username) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK,
if len(username) == 0 || len(password) == 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{
Success: common_err.ERROR,
Success: common_err.CLIENT_ERROR,
Message: common_err.GetMsg(common_err.INVALID_PARAMS),
})
return
}
user := service.MyService.User().GetUserAllInfoByName(username)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if user.Password != encryption.GetMD5ByStr(pwd) {
c.JSON(http.StatusOK,
if user.Password != encryption.GetMD5ByStr(password) {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)})
return
}
token := system_model.VerifyInformation{}
token.AccessToken = jwt.GetAccessToken(user.Username, user.Password, user.Id)
token.RefreshToken = jwt.GetRefreshToken(user.Username, user.Password, user.Id)
token.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
data := make(map[string]interface{}, 2)
user.Password = ""
// token := system_model.VerifyInformation{}
// token.AccessToken = jwt.GetAccessToken(user.UserName, user.Password, user.Id)
// token.RefreshToken = jwt.GetRefreshToken(user.UserName, user.Password, user.Id)
// token.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
// data := make(map[string]interface{}, 2)
// data["token"] = token
// data["user"] = user
data := make(map[string]interface{}, 3)
data["token"] = jwt.GetToken(username, pwd)
data["version"] = types.CURRENTVERSION
data["token"] = token
// TODO:1 Database fields cannot be external
data["user"] = user
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -139,14 +141,14 @@ func PutUserAvatar(c *gin.Context) {
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
f, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusOK,
model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
return
}
if len(user.Avatar) > 0 {
@ -165,22 +167,6 @@ func PutUserAvatar(c *gin.Context) {
})
}
/**
* @description: get user avatar by user id
* @param {query} id string user id
* @method: GET
*/
func GetUserAvatar(c *gin.Context) {
id := c.Param("id")
user := service.MyService.User().GetUserInfoById(id)
path := "default.png"
if user.Id > 0 {
path = user.Avatar
}
c.File(path)
}
// @Summary edit user name
// @Produce application/json
// @Accept application/json
@ -189,27 +175,42 @@ func GetUserAvatar(c *gin.Context) {
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/name/:id [put]
func PutUserName(c *gin.Context) {
//id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
//userName := json["user_name"]
username := json["username"]
id := json["user_id"]
if len(username) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
return
}
func PutUserInfo(c *gin.Context) {
id := c.GetHeader("user_id")
json := model2.UserDBModel{}
c.ShouldBind(&json)
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.UserName = username
service.MyService.User().UpdateUser(user)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
if len(json.Username) > 0 {
u := service.MyService.User().GetUserInfoByUserName(json.Username)
if u.Id > 0 {
c.JSON(common_err.CLIENT_ERROR,
model.Result{Success: common_err.USER_EXIST, Message: common_err.GetMsg(common_err.USER_EXIST)})
return
}
}
if len(json.Email) == 0 {
json.Email = user.Email
}
if len(json.Avatar) == 0 {
json.Avatar = user.Avatar
}
if len(json.Role) == 0 {
json.Role = user.Role
}
if len(json.Description) == 0 {
json.Description = user.Description
}
if len(json.Nickname) == 0 {
json.Nickname = user.Nickname
}
service.MyService.User().UpdateUser(json)
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json})
}
// @Summary edit user password
@ -219,31 +220,30 @@ func PutUserName(c *gin.Context) {
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/password/:id [put]
func PutUserPwd(c *gin.Context) {
//id := c.GetHeader("user_id")
func PutUserPassword(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
oldPwd := json["old_pwd"]
pwd := json["pwd"]
id := json["user_id"]
c.ShouldBind(&json)
oldPwd := json["old_password"]
pwd := json["password"]
if len(oldPwd) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserAllInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if user.Password != encryption.GetMD5ByStr(oldPwd) {
c.JSON(http.StatusOK, model.Result{Success: common_err.PWD_INVALID_OLD, Message: common_err.GetMsg(common_err.PWD_INVALID_OLD)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID_OLD, Message: common_err.GetMsg(common_err.PWD_INVALID_OLD)})
return
}
user.Password = encryption.GetMD5ByStr(pwd)
service.MyService.User().UpdateUserPassword(user)
user.Password = ""
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @Summary edit user nick
@ -256,12 +256,11 @@ func PutUserPwd(c *gin.Context) {
// @Router /user/nick [put]
func PutUserNick(c *gin.Context) {
//id := c.GetHeader("user_id")
id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
nickName := json["nick_name"]
id := json["user_id"]
if len(nickName) == 0 {
c.ShouldBind(&json)
Nickname := json["nick_name"]
if len(Nickname) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
@ -271,10 +270,8 @@ func PutUserNick(c *gin.Context) {
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
user.NickName = nickName
user.Nickname = Nickname
service.MyService.User().UpdateUser(user)
//TODO:person remove together
go service.MyService.Casa().PushUserInfo()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
@ -287,10 +284,9 @@ func PutUserNick(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /user/desc [put]
func PutUserDesc(c *gin.Context) {
// id := c.GetHeader("user_id")
id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
id := json["user_id"]
c.ShouldBind(&json)
desc := json["description"]
if len(desc) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
@ -309,39 +305,6 @@ func PutUserDesc(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @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) {
json := make(map[string]string)
c.BindJSON(&json)
desc := json["description"]
nickName := json["nick_name"]
id := json["user_id"]
if len(desc) == 0 || len(nickName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
//user_service.SetUser("", "", "", "", desc, nickName)
user.NickName = nickName
user.Description = desc
service.MyService.User().UpdateUser(user)
go service.MyService.Casa().PushUserInfo()
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
}
// @Summary get user info
// @Produce application/json
// @Accept application/json
@ -349,51 +312,10 @@ func PostUserPersonInfo(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /user/info/:id [get]
func GetUserInfo(c *gin.Context) {
//id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
//*****
var u = make(map[string]string, 5)
u["user_name"] = user.UserName
u["head"] = user.Avatar
u["email"] = user.Email
u["description"] = user.NickName
u["nick_name"] = user.NickName
u["id"] = strconv.Itoa(user.Id)
//**
c.JSON(http.StatusOK,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: u,
})
}
// @Summary get user info
// @Produce application/json
// @Accept application/json
// @Tags user
// @Success 200 {string} string "ok"
// @Router /user/info [get]
func GetUserInfoByUserName(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
userName := json["user_name"]
if len(userName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoByUserName(userName)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
//**
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -401,29 +323,46 @@ func GetUserInfoByUserName(c *gin.Context) {
})
}
// @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: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: config.ServerInfo.Token})
/**
* @description:
* @param {*gin.Context} c
* @param {string} Username
* @return {*}
* @method:
* @router:
*/
func GetUserInfoByUsername(c *gin.Context) {
username := c.Param("username")
if len(username) == 0 {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoByUserName(username)
if user.Id == 0 {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: user,
})
}
/**
* @description: get all user name
* @description: get all Usernames
* @method:GET
* @router:/user/all/name
*/
func GetUserAllUserName(c *gin.Context) {
func GetUserAllUsername(c *gin.Context) {
users := service.MyService.User().GetAllUserName()
names := []string{}
for _, v := range users {
names = append(names, v.UserName)
names = append(names, v.Username)
}
c.JSON(http.StatusOK,
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
@ -440,25 +379,26 @@ func GetUserAllUserName(c *gin.Context) {
func GetUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
//id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
// user := service.MyService.User().GetUserInfoByUserName(userName)
// user := service.MyService.User().GetUserInfoByUsername(Username)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
filePath := config.AppInfo.UserDataPath + "/" + id + "/" + name + ".json"
data := file.ReadFullFile(filePath)
if !gjson.ValidBytes(data) {
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: string(data)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: string(data)})
return
}
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
}
/**
@ -468,16 +408,16 @@ func GetUserCustomConf(c *gin.Context) {
* @router:/user/custom/:key
*/
func PostUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
//id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
@ -485,7 +425,7 @@ func PostUserCustomConf(c *gin.Context) {
filePath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id)
file.WriteToPath(data, filePath, name+".json")
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: json2.RawMessage(string(data))})
}
/**
@ -497,20 +437,23 @@ func PostUserCustomConf(c *gin.Context) {
func DeleteUserCustomConf(c *gin.Context) {
name := c.Param("key")
if len(name) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
//id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK,
c.JSON(common_err.SERVICE_ERROR,
model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
filePath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + name + ".json"
os.Remove(filePath)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
err := os.Remove(filePath)
if err != nil {
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR)})
return
}
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
/**
@ -522,19 +465,18 @@ func DeleteUserCustomConf(c *gin.Context) {
func DeleteUser(c *gin.Context) {
id := c.Param("id")
service.MyService.User().DeleteUserById(id)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id})
}
/**
* @description:update user image
* @method:POST
* @router:/user/file/image/:key
* @router:/user/current/image/:key
*/
func PostUserFileImage(c *gin.Context) {
//id := c.GetHeader("user_id")
id := c.Param("id")
func PutUserImage(c *gin.Context) {
id := c.GetHeader("user_id")
json := make(map[string]string)
c.BindJSON(&json)
c.ShouldBind(&json)
path := json["path"]
key := c.Param("key")
@ -571,50 +513,57 @@ func PostUserFileImage(c *gin.Context) {
data := make(map[string]string, 3)
data["path"] = filePath
data["file_name"] = key + ext
data["online_path"] = "/v1/user/image?path=" + filePath
data["online_path"] = "/v1/users/image?path=" + filePath
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
/**
* @description:create or update user's custom image
* @param {formData} file file "a file to be uploaded"
* @param {path} key string "file name"
* @method:POST
* @router:/user/upload/image/:key
* @description:
* @param {*gin.Context} c
* @param {file} file
* @param {string} key
* @param {string} type:avatar,background
* @return {*}
* @method:
* @router:
*/
func PostUserUploadImage(c *gin.Context) {
//id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
f, err := c.FormFile("file")
key := c.Param("key")
t := c.PostForm("type")
if len(key) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.CLIENT_ERROR, Message: common_err.GetMsg(common_err.CLIENT_ERROR), Data: err.Error()})
return
}
_, err = file.GetImageExtByName(f.Filename)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: common_err.NOT_IMAGE, Message: common_err.GetMsg(common_err.NOT_IMAGE)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NOT_IMAGE, Message: common_err.GetMsg(common_err.NOT_IMAGE)})
return
}
ext := filepath.Ext(f.Filename)
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if t == "avatar" {
key = "avatar"
}
path := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id) + "/" + key + ext
c.SaveUploadedFile(f, path)
data := make(map[string]string, 3)
data["path"] = path
data["file_name"] = key + ext
data["online_path"] = "/v1/user/image?path=" + path
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
data["online_path"] = "/v1/users/image?path=" + path
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data})
}
/**
@ -641,95 +590,94 @@ func GetUserImage(c *gin.Context) {
defer fileTmp.Close()
fileName := path.Base(filePath)
// @tiger - RESTful 规范下不应该返回文件本身内容而是返回文件的静态URL由前端去解析
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.File(filePath)
}
func DeleteUserImage(c *gin.Context) {
// id := c.GetHeader("user_id")
id := c.Param("id")
id := c.GetHeader("user_id")
path := c.Query("path")
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
}
user := service.MyService.User().GetUserInfoById(id)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)})
return
}
if !file.Exists(path) {
c.JSON(http.StatusOK, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FILE_DOES_NOT_EXIST, Message: common_err.GetMsg(common_err.FILE_DOES_NOT_EXIST)})
return
}
if !strings.Contains(path, config.AppInfo.UserDataPath+"/"+strconv.Itoa(user.Id)) {
c.JSON(http.StatusOK, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)})
return
}
os.Remove(path)
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
////refresh token
// func PostUserRefreshToken(c *gin.Context) {
// json := make(map[string]string)
// c.BindJSON(&json)
// refresh := json["refresh_token"]
// claims, err := jwt.ParseToken(refresh)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE), Data: err.Error()})
// return
// }
// if claims.VerifyExpiresAt(time.Now(), true) || claims.VerifyIssuer("refresh", true) {
// c.JSON(http.StatusOK, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE)})
// return
// }
// newToken := jwt.GetAccessToken(claims.UserName, claims.PassWord, claims.Id)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR), Data: err.Error()})
// return
// }
// verifyInfo := system_model.VerifyInformation{}
// verifyInfo.AccessToken = newToken
// verifyInfo.RefreshToken = jwt.GetRefreshToken(claims.UserName, claims.PassWord, claims.Id)
// verifyInfo.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
/**
* @description:
* @param {*gin.Context} c
* @param {string} refresh_token
* @return {*}
* @method:
* @router:
*/
func PostUserRefreshToken(c *gin.Context) {
js := make(map[string]string)
c.ShouldBind(&js)
refresh := js["refresh_token"]
claims, err := jwt.ParseToken(refresh, true)
if err != nil {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE), Data: err.Error()})
return
}
if !claims.VerifyExpiresAt(time.Now(), true) || !claims.VerifyIssuer("refresh", true) {
c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.VERIFICATION_FAILURE, Message: common_err.GetMsg(common_err.VERIFICATION_FAILURE)})
return
}
newToken := jwt.GetAccessToken(claims.Username, claims.PassWord, claims.Id)
verifyInfo := system_model.VerifyInformation{}
verifyInfo.AccessToken = newToken
verifyInfo.RefreshToken = jwt.GetRefreshToken(claims.Username, claims.PassWord, claims.Id)
verifyInfo.ExpiresAt = time.Now().Add(3 * time.Hour * time.Duration(1)).Unix()
// c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: verifyInfo})
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: verifyInfo})
// }
}
//******** soon to be removed ********
func DeleteUserAll(c *gin.Context) {
service.MyService.User().DeleteAllUser()
c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)})
}
// @Summary 设置用户名和密码
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param username formData string true "User name"
// @Param pwd formData string true "password"
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/setusernamepwd [post]
func Set_Name_Pwd(c *gin.Context) {
json := make(map[string]string)
c.BindJSON(&json)
username := json["username"]
pwd := json["pwd"]
if service.MyService.User().GetUserCount() > 0 || len(username) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK,
model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.INVALID_PARAMS)})
return
// @Router /sys/init/check [get]
func GetUserStatus(c *gin.Context) {
data := make(map[string]interface{}, 2)
if service.MyService.User().GetUserCount() > 0 {
data["initialized"] = true
data["key"] = ""
} else {
key := uuid.NewV4().String()
service.UserRegisterHash[key] = key
data["key"] = key
data["initialized"] = false
}
user := model2.UserDBModel{}
user.UserName = username
user.Password = encryption.GetMD5ByStr(pwd)
user.Role = "admin"
user = service.MyService.User().CreateUser(user)
if user.Id == 0 {
c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR, Message: common_err.GetMsg(common_err.ERROR)})
return
}
file.MkDir(config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id))
c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: user})
c.JSON(common_err.SUCCESS,
model.Result{
Success: common_err.SUCCESS,
Message: common_err.GetMsg(common_err.SUCCESS),
Data: data,
})
}

View file

@ -30,13 +30,13 @@ type AppService interface {
SaveContainer(m model2.AppListDBModel)
GetUninstallInfo(id string) model2.AppListDBModel
DeleteApp(id string)
GetContainerInfo(name string) (types.Container, error)
GetContainerInfo(id string) (types.Container, error)
GetAppDBInfo(id string) model2.AppListDBModel
UpdateApp(m model2.AppListDBModel)
GetSimpleContainerInfo(name string) (types.Container, error)
GetSimpleContainerInfo(id string) (types.Container, error)
DelAppConfigDir(path string)
GetSystemAppList() []types.Container
GetHardwareUsageSteam()
GetHardwareUsageStream()
GetHardwareUsage() []model.DockerStatsModel
GetAppStats(id string) string
GetAllDBApps() []model2.AppListDBModel
@ -156,13 +156,23 @@ func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppLi
for _, m := range containers {
if m.Labels["casaos"] == "casaos" {
if m.Labels["origin"] == "system" {
continue
}
_, newVersion := NewVersionApp[m.ID]
name := strings.ReplaceAll(m.Names[0], "/", "")
icon := m.Labels["icon"]
if len(m.Labels["name"]) > 0 {
name = m.Labels["name"]
}
if m.Labels["origin"] == "system" {
name = strings.Split(m.Image, ":")[0]
if len(strings.Split(name, "/")) > 1 {
icon = "https://icon.casaos.io/main/all/" + strings.Split(name, "/")[1] + ".png"
}
}
list = append(list, model2.MyAppList{
Name: strings.ReplaceAll(m.Names[0], "/", ""),
Icon: m.Labels["icon"],
Name: name,
Icon: icon,
State: m.State,
CustomId: m.Labels["custom_id"],
Id: m.ID,
@ -170,8 +180,8 @@ func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppLi
Index: m.Labels["index"],
//Order: m.Labels["order"],
Image: m.Image,
NewVersion: newVersion,
Type: m.Labels["origin"],
Latest: newVersion,
//Type: m.Labels["origin"],
//Slogan: m.Slogan,
//Rely: m.Rely,
Host: m.Labels["host"],
@ -185,7 +195,7 @@ func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppLi
CustomId: m.ID,
Id: m.ID,
Port: "",
NewVersion: false,
Latest: false,
Host: "",
Protocol: "",
Image: m.Image,
@ -274,14 +284,14 @@ func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
}
//获取我的应用列表
func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
func (a *appStruct) GetContainerInfo(id string) (types.Container, error) {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
loger.Error("Failed to init client", zap.Any("err", err))
}
filters := filters.NewArgs()
filters.Add("name", name)
filters.Add("id", id)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
@ -294,7 +304,7 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
}
func (a *appStruct) GetSimpleContainerInfo(name string) (types.Container, error) {
func (a *appStruct) GetSimpleContainerInfo(id string) (types.Container, error) {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
@ -302,7 +312,7 @@ func (a *appStruct) GetSimpleContainerInfo(name string) (types.Container, error)
}
defer cli.Close()
filters := filters.NewArgs()
filters.Add("name", name)
filters.Add("id", id)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
return types.Container{}, err
@ -366,12 +376,12 @@ func (a *appStruct) GetAppStats(id string) string {
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
steam := true
stream := true
for !isFinish {
if steam {
steam = false
if stream {
stream = false
go func() {
a.GetHardwareUsageSteam()
a.GetHardwareUsageStream()
}()
}
runtime.Gosched()
@ -386,7 +396,7 @@ func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
}
func (a *appStruct) GetHardwareUsageSteam() {
func (a *appStruct) GetHardwareUsageStream() {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
@ -400,20 +410,26 @@ func (a *appStruct) GetHardwareUsageSteam() {
fts := filters.NewArgs()
fts.Add("label", "casaos=casaos")
//fts.Add("status", "running")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
}
for i := 0; i < 100; i++ {
if i%10 == 0 {
containers, err = cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
continue
}
}
if config.CasaOSGlobalVariables.AppChange {
config.CasaOSGlobalVariables.AppChange = false
dataStats.Range(func(key, value interface{}) bool {
dataStats.Delete(key)
return true
})
}
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
}
var temp sync.Map
var wg sync.WaitGroup
for _, v := range containers {
@ -435,12 +451,14 @@ func (a *appStruct) GetHardwareUsageSteam() {
m, _ := dataStats.Load(v.ID)
dockerStats := model.DockerStatsModel{}
if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data
dockerStats.Previous = m.(model.DockerStatsModel).Data
}
dockerStats.Data = data
dockerStats.Icon = v.Labels["icon"]
dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "")
// @tiger - 不建议直接把依赖的数据结构封装返回。
// 如果依赖的数据结构有变化,应该在这里适配或者保存,这样更加对客户端负责
temp.Store(v.ID, dockerStats)
if i == 99 {
stats.Body.Close()

View file

@ -14,24 +14,19 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
"go.uber.org/zap"
)
type CasaService interface {
GetServerList(index, size, tp, categoryId, key string) model.ServerAppListCollection
GetServerCategoryList() []model.CategoryList
GetServerAppInfo(id, t string, language string) model.ServerAppList
GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error)
GetServerCategoryList() (list []model.CategoryList, err error)
GetServerAppInfo(id, t string, language string) (model.ServerAppList, error)
ShareAppFile(body []byte) string
PushHeart(id, t string, language string)
PushConnectionStatus(uuid, err string, from, to, event string)
PushUserInfo()
GetUserInfoByShareId(shareId string) model.UserInfo
GetPersonPublic() (list []model.FriendsModel)
GetCasaosVersion() model.Version
AsyncGetServerList() (collection model.ServerAppListCollection)
AsyncGetServerCategoryList() []model.CategoryList
AsyncGetServerList() (collection model.ServerAppListCollection, err error)
AsyncGetServerCategoryList() ([]model.CategoryList, error)
}
type casaService struct {
@ -46,7 +41,7 @@ func (o *casaService) ShareAppFile(body []byte) string {
return content
}
func (o *casaService) GetServerList(index, size, tp, categoryId, key string) model.ServerAppListCollection {
func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (model.ServerAppListCollection, error) {
keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, "en")
collection := model.ServerAppListCollection{}
@ -54,7 +49,7 @@ func (o *casaService) GetServerList(index, size, tp, categoryId, key string) mod
res, ok := result.(string)
if ok {
json2.Unmarshal([]byte(res), &collection)
return collection
return collection, nil
}
}
@ -63,7 +58,10 @@ func (o *casaService) GetServerList(index, size, tp, categoryId, key string) mod
err := json2.Unmarshal(collectionStr, &collection)
if err != nil {
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(collectionStr)))
collection = o.AsyncGetServerList()
collection, err = o.AsyncGetServerList()
if err != nil {
return collection, err
}
}
go o.AsyncGetServerList()
@ -122,20 +120,20 @@ func (o *casaService) GetServerList(index, size, tp, categoryId, key string) mod
Cache.Set(keyName, string(by), time.Minute*10)
}
return collection
return collection, nil
}
func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollection) {
func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollection, err error) {
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_list.json")
err := json2.Unmarshal(results, &collection)
err = json2.Unmarshal(results, &collection)
if err != nil {
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
}
if collection.Version == o.GetCasaosVersion().Version {
return collection
return collection, err
}
head := make(map[string]string)
@ -187,33 +185,36 @@ func (o *casaService) AsyncGetServerList() (collection model.ServerAppListCollec
// return list
// }
func (o *casaService) GetServerCategoryList() (list []model.CategoryList) {
func (o *casaService) GetServerCategoryList() (list []model.CategoryList, err error) {
category := model.ServerCategoryList{}
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json")
err := json2.Unmarshal(results, &category)
err = json2.Unmarshal(results, &category)
if err != nil {
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
return o.AsyncGetServerCategoryList()
}
go o.AsyncGetServerCategoryList()
return category.Item
return category.Item, err
}
func (o *casaService) AsyncGetServerCategoryList() []model.CategoryList {
func (o *casaService) AsyncGetServerCategoryList() ([]model.CategoryList, error) {
list := model.ServerCategoryList{}
results := file.ReadFullFile(config.AppInfo.DBPath + "/app_category.json")
err := json2.Unmarshal(results, &list)
if err != nil {
loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
}
} else {
if list.Version == o.GetCasaosVersion().Version {
return nil
return list.Item, nil
}
}
item := []model.CategoryList{}
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
if len(listS) == 0 {
return item, errors.New("server error")
}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &item)
if len(item) > 0 {
list.Version = o.GetCasaosVersion().Version
@ -224,10 +225,10 @@ func (o *casaService) AsyncGetServerCategoryList() []model.CategoryList {
}
file.WriteToPath(by, config.AppInfo.DBPath, "app_category.json")
}
return item
return item, nil
}
func (o *casaService) GetServerAppInfo(id, t string, language string) model.ServerAppList {
func (o *casaService) GetServerAppInfo(id, t string, language string) (model.ServerAppList, error) {
head := make(map[string]string)
@ -235,9 +236,12 @@ func (o *casaService) GetServerAppInfo(id, t string, language string) model.Serv
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t+"&language="+language, head)
info := model.ServerAppList{}
if infoS == "" {
return info, errors.New("server error")
}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
return info
return info, nil
}
func GetToken() string {
t := make(chan string)
@ -289,86 +293,6 @@ func (o *casaService) GetCasaosVersion() model.Version {
return version
}
func (o *casaService) PushHeart(id, t string, language string) {
m := model.CasaOSHeart{}
m.UuId = id
m.Type = t
b, _ := json.Marshal(m)
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/heart", b, "application/json", head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
}
func (o *casaService) PushConnectionStatus(uuid, err string, from, to, event string) {
m := model.ConnectionStatus{}
m.UUId = uuid
m.Error = err
m.From = from
m.To = to
m.Event = event
b, _ := json.Marshal(m)
head := make(map[string]string)
head["Authorization"] = GetToken()
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{}
}

View file

@ -540,6 +540,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, m model.Customi
config.Labels["show_env"] = strings.Join(showENV, ",")
config.Labels["protocol"] = m.Protocol
config.Labels["host"] = m.Host
config.Labels["name"] = m.Label
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(m.NetworkModel), Privileged: m.Privileged, CapAdd: m.CapAdd}
//if net != "host" {
config.ExposedPorts = ports
@ -551,7 +552,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, m model.Customi
hostConfig,
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{m.NetworkModel: {NetworkID: "", Aliases: []string{}}}},
nil,
m.Label)
m.ContainerName)
if err != nil {
return "", err
}

View file

@ -1,33 +0,0 @@
package service
import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type DownRecordService interface {
AddDownRecord(m model2.PersonDownRecordDBModel)
GetDownloadListByFrom(id string) []model2.PersonDownRecordDBModel
GetDownloadListByPath(path string) (list []model2.PersonDownRecordDBModel)
}
type downRecordService struct {
db *gorm.DB
}
func (d *downRecordService) AddDownRecord(m model2.PersonDownRecordDBModel) {
d.db.Create(&m)
}
func (d *downRecordService) GetDownloadListByFrom(id string) []model2.PersonDownRecordDBModel {
var m []model2.PersonDownRecordDBModel
d.db.Model(m).Where("from = ?", id).Find(&m)
return m
}
func (d *downRecordService) GetDownloadListByPath(path string) (list []model2.PersonDownRecordDBModel) {
d.db.Where("path = ?", path).Find(&list)
return
}
func NewDownRecordService(db *gorm.DB) DownRecordService {
return &downRecordService{db: db}
}

View file

@ -1,66 +0,0 @@
package service
import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type DownloadService interface {
AddDownloadTask(m model2.PersonDownloadDBModel) //添加下载任务
EditDownloadState(m model2.PersonDownloadDBModel) //只修改状态
SaveDownload(m model2.PersonDownloadDBModel)
DelDownload(uuid string)
GetDownloadById(uuid string) model2.PersonDownloadDBModel
GetDownloadListByState(state string, t int) []model2.PersonDownloadDBModel
SetDownloadError(m model2.PersonDownloadDBModel)
GetDownloadListByPath(m model2.PersonDownloadDBModel) int
}
type downloadService struct {
db *gorm.DB
}
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.PersonDownloadDBModel) {
d.db.Model(&m).Where("uuid = ?", m.UUID).Update("state", m.State)
}
//failed during download
func (d *downloadService) SetDownloadError(m model2.PersonDownloadDBModel) {
d.db.Model(&m).Updates(m)
}
func (d *downloadService) DelDownload(uuid string) {
var m model2.PersonDownloadDBModel
d.db.Where("uuid = ?", uuid).Delete(&m)
}
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, t int) (list []model2.PersonDownloadDBModel) {
if len(state) == 0 {
d.db.Where("type = ?", t).Find(&list)
} else {
d.db.Where("state = ? AND type= ?", state, t).Find(&list)
}
return
}
func (d *downloadService) SaveDownload(m model2.PersonDownloadDBModel) {
d.db.Save(&m)
}
func NewDownloadService(db *gorm.DB) DownloadService {
return &downloadService{db: db}
}

View file

@ -1,155 +0,0 @@
package service
import (
"context"
"fmt"
"net"
"reflect"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
)
type FriendService interface {
AddFriend(m model2.FriendModel)
DeleteFriend(m model2.FriendModel)
EditFriendMark(m model2.FriendModel)
EditFriendWrite(m model2.FriendModel)
EditFriendBlock(m model2.FriendModel)
GetFriendById(m model2.FriendModel) model2.FriendModel
GetFriendList() (list []model2.FriendModel)
GetFriendListRemote() (list []model2.FriendModel)
UpdateAddFriendType(m model2.FriendModel)
AgreeFrined(id string)
GetFriendByToken(token string) model2.FriendModel
UpdateOrCreate(m model2.FriendModel)
InternalInspection(ips []string, token string)
}
type friendService struct {
db *gorm.DB
}
func (p *friendService) AgreeFrined(id string) {
var m model2.FriendModel
p.db.Model(&m).Where("token = ?", id).Update("state", types.FRIENDSTATEDEFAULT)
}
func (p *friendService) AddFriend(m model2.FriendModel) {
p.db.Create(&m)
}
func (p *friendService) DeleteFriend(m model2.FriendModel) {
p.db.Where("token = ?", m.Token).Delete(&m)
}
func (p *friendService) EditFriendMark(m model2.FriendModel) {
p.db.Model(&m).Where("token = ?", m.Token).Update("mark", m.Mark)
}
func (p *friendService) EditFriendWrite(m model2.FriendModel) {
p.db.Model(&m).Where("token = ?", m.Token).Update("write", m.Write)
}
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", "profile", "token", "state", "mark", "block", "version").Find(&list)
return list
}
func (p *friendService) GetFriendListRemote() (list []model2.FriendModel) {
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Where("internal_ip == '' OR internal_ip is null").Find(&list)
return list
}
func (p *friendService) GetFriendListInternal() (list []model2.FriendModel) {
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Where("internal_ip != ''").Find(&list)
return list
}
func (p *friendService) UpdateOrCreate(m model2.FriendModel) {
friend := model2.FriendModel{}
p.db.Where("token = ?", m.Token).First(&friend)
if reflect.DeepEqual(friend, model2.FriendModel{}) {
p.db.Create(&m)
} else {
p.db.Model(&m).Updates(m)
}
}
func (p *friendService) UpdateAddFriendType(m model2.FriendModel) {
p.db.Model(&m).Updates(m)
}
func (p *friendService) GetFriendByToken(token string) model2.FriendModel {
var m model2.FriendModel
p.db.Model(&m).Where("token = ?", token).First(&m)
return m
}
func (p *friendService) InternalInspection(ips []string, token string) {
for _, v := range ips {
fmt.Println("开始遍历 ip:", v)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
dstAddr, err := net.ResolveUDPAddr("udp", v)
if err != nil {
fmt.Println("1", err.Error())
continue
}
port, err := strconv.Atoi(config.ServerInfo.UDPPort)
if err != nil {
fmt.Println("2", err)
continue
}
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: port}
ticket := token
session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
if err != nil {
fmt.Println("3", err, v)
continue
}
stream, err := session.OpenStreamSync(ctx)
if err != nil {
fmt.Println("4", err)
continue
}
uuid := uuid.NewV4().String()
SayHello(stream, token)
msg := model.MessageModel{
Type: types.PERSONPING,
Data: "",
From: config.ServerInfo.Token,
To: token,
UUId: uuid,
}
SendData(stream, msg)
go ReadContent(stream)
result := <-Message
fmt.Println("ping返回结果:", result, msg)
stream.Close()
if !reflect.DeepEqual(result, model.MessageModel{}) && result.Data.(string) == token && result.From == token {
fmt.Println("获取到正确的ip", v)
UDPAddressMap[result.From] = v
p.db.Model(&model2.FriendModel{}).Where("token = ?", token).Update("internal_ip", v)
return
}
}
}
func NewFriendService(db *gorm.DB) FriendService {
return &friendService{db: db}
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-30 17:33:21
* @LastEditTime: 2022-07-13 10:56:34
* @FilePath: /CasaOS/service/model/o_container.go
* @Description:
* @Website: https://www.casaos.io
@ -67,13 +67,12 @@ type MyAppList struct {
Index string `json:"index"`
//Order string `json:"order"`
Port string `json:"port"`
UpTime string `json:"up_time"`
Slogan string `json:"slogan"`
Type string `json:"type"`
//Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
Image string `json:"image"`
Volumes string `json:"volumes"`
NewVersion bool `json:"new_version"`
Latest bool `json:"latest"`
Host string `json:"host"`
Protocol string `json:"protocol"`
}

View file

@ -1,16 +0,0 @@
package model
type PersonDownRecordDBModel struct {
UUID string `gorm:"column:uuid;primary_key" json:"uuid"`
Name string `json:"name"` //file name
Type int `json:"type"`
Size int64 `json:"size"` //file size
Downloader string `json:"downloader"` //Error message
Path string `json:"path"`
Created int64 `gorm:"autoCreateTime" json:"created"`
Updated int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated"`
}
func (p *PersonDownRecordDBModel) TableName() string {
return "o_person_down_record"
}

View file

@ -1,24 +0,0 @@
package model
type PersonDownloadDBModel struct {
UUID string `gorm:"column:uuid;primary_key" json:"uuid"`
State int `json:"state"` //
Type int `json:"type"` //defult 0
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 *PersonDownloadDBModel) TableName() string {
return "o_person_download"
}

View file

@ -1,21 +0,0 @@
package model
type FriendModel struct {
State int `json:"state"`
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
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"` //Description
OnLine bool `json:"on_line" gorm:"-"`
Version int `json:"version"`
Write bool `json:"write"`
LocalIP string `json:"local_ip"`
}
func (p *FriendModel) TableName() string {
return "o_friend"
}

View file

@ -1,17 +0,0 @@
package model
import "time"
type ShortcutsDBModel struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
Title string `json:"title"`
Url string `json:"url"`
Icon string `json:"icon"`
Sort int `json:"sort"`
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
}
func (p *ShortcutsDBModel) TableName() string {
return "o_shortcuts"
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-23 15:43:07
* @LastEditTime: 2022-07-11 17:57:00
* @FilePath: /CasaOS/service/model/o_user.go
* @Description:
* @Website: https://www.casaos.io
@ -15,11 +15,11 @@ import "time"
//Soon to be removed
type UserDBModel struct {
Id int `gorm:"column:id;primary_key" json:"id"`
UserName string `json:"user_name"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
Role string `json:"role"`
Email string `json:"email"`
NickName string `json:"nick_name"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
Description string `json:"description"`
CreatedAt time.Time `gorm:"<-:create;autoCreateTime" json:"created_at,omitempty"`
@ -27,5 +27,5 @@ type UserDBModel struct {
}
func (p *UserDBModel) TableName() string {
return "o_user"
return "o_users"
}

View file

@ -33,16 +33,31 @@ type NotifyServer interface {
SendMemInfoBySocket(mem map[string]interface{})
SendUSBInfoBySocket(list []model2.DriveUSB)
SendDiskInfoBySocket(disk model2.Summary)
SendPersonStatusBySocket(status notify.Person)
SendFileOperateNotify(nowSend bool)
SendInstallAppBySocket(app notify.Application)
SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat)
SendStorageBySocket(message notify.StorageMessage)
}
type notifyServer struct {
db *gorm.DB
}
func (i *notifyServer) SendStorageBySocket(message notify.StorageMessage) {
body := make(map[string]interface{})
body["data"] = message
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "storage_status"
notify := notify.Message{}
notify.Path = "storage_status"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
body := make(map[string]interface{})
@ -224,22 +239,6 @@ func (i *notifyServer) SendFileOperateNotify(nowSend bool) {
}
func (i *notifyServer) SendPersonStatusBySocket(status notify.Person) {
body := make(map[string]interface{})
body["data"] = status
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "person_status"
notify := notify.Message{}
notify.Path = "person_status"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendDiskInfoBySocket(disk model2.Summary) {
body := make(map[string]interface{})
body["data"] = disk

View file

@ -1,482 +0,0 @@
package service
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"net"
"os"
"reflect"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
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"
"gorm.io/gorm"
)
type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error)
GetPersionNetWorkTypeDetection() string
}
type personService struct {
db *gorm.DB
}
var IpInfo model.PersionModel
var CancelList map[string]string
var InternalInspection map[string][]string
func PushIpInfo(token string) {
m := model.PersionModel{}
m.Ips = ip_helper.GetDeviceAllIP("")
m.Token = token
b, _ := json.Marshal(m)
if reflect.DeepEqual(IpInfo, m) {
return
}
head := make(map[string]string)
infoS := httper2.Post(config.ServerInfo.Handshake+"/v1/update", b, "application/json", head)
fmt.Println(infoS)
}
func (p *personService) GetPersionInfo(token string) (m model.PersionModel, err error) {
infoS := httper2.Get(config.ServerInfo.Handshake+"/v1/ips/"+token, nil)
err = json.Unmarshal([]byte(infoS), &m)
return
}
func (p *personService) GetPersionNetWorkTypeDetection() string {
data := make(chan string)
list := []string{"stun.l.google.com", "stun1.l.google.com", "stun2.l.google.com", "stun.sipgate.net"}
for _, v := range list {
go utils.GetNetWorkTypeDetection(data, v)
}
result := <-data
close(data)
return result
}
func NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db}
}
//=======================================================================================================================================================================
var StreamList map[string]quic.Stream
var ServiceMessage chan model.MessageModel
func UDPService() {
port := 0
if len(config.ServerInfo.UDPPort) > 0 {
port, _ = strconv.Atoi(config.ServerInfo.UDPPort)
if port != 0 && !port2.IsPortAvailable(port, "udp") {
port = 0
}
}
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: port}
var err error
UDPConn, err = net.ListenUDP("udp", srcAddr)
if err != nil {
fmt.Println(err)
}
listener, err := quic.Listen(UDPConn, quic_helper.GetGenerateTLSConfig(config.ServerInfo.Token), quic_helper.GetQUICConfig())
if err != nil {
fmt.Println(err)
}
defer listener.Close()
ctx := context.Background()
acceptFailures := 0
const maxAcceptFailures = 10
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
}
session, err := listener.Accept(ctx)
if err != nil {
fmt.Println("Listen (BEP/quic): Accepting connection:", err)
acceptFailures++
if acceptFailures > maxAcceptFailures {
// Return to restart the listener, because something
// seems permanently damaged.
fmt.Println(err)
return
}
// Slightly increased delay for each failure.
time.Sleep(time.Duration(acceptFailures) * time.Second)
continue
}
acceptFailures = 0
streamCtx, cancel := context.WithTimeout(ctx, time.Second*10)
stream, err := session.AcceptStream(streamCtx)
cancel()
if err != nil {
fmt.Println("failed to accept stream from %s: %v", session.RemoteAddr(), err)
_ = session.CloseWithError(1, err.Error())
continue
}
// prefixByte := make([]byte, 4)
// c1, err := io.ReadFull(stream, prefixByte)
// fmt.Println(c1, err)
// prefixLength, err := strconv.Atoi(string(prefixByte))
// if err != nil {
// fmt.Println(err)
// }
// messageByte := make([]byte, prefixLength)
// t, err := io.ReadFull(stream, messageByte)
// fmt.Println(t, err)
// m := model.MessageModel{}
// err = json.Unmarshal(messageByte, &m)
// if err != nil {
// fmt.Println(err)
// }
go ProcessingContent(stream)
}
}
//处理内容
func ProcessingContent(stream quic.Stream) {
for {
prefixByte := make([]byte, 6)
_, err := io.ReadFull(stream, prefixByte)
if err != nil {
fmt.Println(err)
return
}
prefixLength, err := strconv.Atoi(string(prefixByte))
if err != nil {
fmt.Println(err)
}
messageByte := make([]byte, prefixLength)
_, err = io.ReadFull(stream, messageByte)
if err != nil {
return
}
m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m)
if err != nil {
fmt.Println(err)
}
if m.Type == types.PERSONHELLO {
//nothing
continue
} else if m.Type == types.PERSONDIRECTORY {
friend := model2.FriendModel{}
friend.Token = m.From
var list []model.Path
rFriend := MyService.Friend().GetFriendById(friend)
if !reflect.DeepEqual(rFriend, model2.FriendModel{Token: m.From}) && !rFriend.Block {
if m.Data.(string) == "" || m.Data.(string) == "/" {
for _, v := range config.FileSettingInfo.ShareDir {
//tempList := MyService.ZiMa().GetDirPath(v)
temp := MyService.System().GetDirPathOne(v)
list = append(list, temp)
}
} else {
list = MyService.System().GetDirPath(m.Data.(string))
}
} else {
list = []model.Path{}
}
if rFriend.Write {
for i := 0; i < len(list); i++ {
list[i].Write = true
}
}
m.To = m.From
m.Data = list
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == types.PERSONDOWNLOAD {
SendFileData(stream, m.Data.(string), m.From, m.UUId, types.PERSONDOWNLOAD)
break
} else if m.Type == types.PERSONADDFRIEND {
friend := model2.FriendModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &friend)
if err != nil {
fmt.Println(err)
continue
}
go MyService.Friend().UpdateOrCreate(friend)
mi := model2.FriendModel{}
mi.Avatar = config.UserInfo.Avatar
mi.Profile = config.UserInfo.Description
mi.NickName = config.UserInfo.NickName
m.To = m.From
m.Data = mi
m.Type = types.PERSONADDFRIEND
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == types.PERSONCONNECTION {
if len(m.Data.(string)) > 0 {
fmt.Println("设置ip", m.Data.(string))
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.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.Write = false
friend.Version = user.Version
if len(config.UserInfo.Public) > 0 {
friend.State = types.FRIENDSTATEREQUEST
}
MyService.Friend().AddFriend(friend)
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
Dial(msg, false)
//agree user
if len(config.UserInfo.Public) == 0 {
msg.Type = types.PERSONAGREEFRIEND
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
Dial(msg, true)
}
break
} else if m.Type == types.PERSONAGREEFRIEND {
MyService.Friend().AgreeFrined(m.From)
break
} else if m.Type == types.PERSONCANCEL {
CancelList[m.UUId] = "cancel"
break
} else if m.Type == types.PERSONSUMMARY {
Summary(m, "upload")
continue
} else if m.Type == types.PERSONUPLOAD {
//TODO:检查是否存在如果存在直接结束
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
task.LocalPath = m.Data.(string)
MyService.Download().AddDownloadTask(task)
friend := MyService.Friend().GetFriendById(model2.FriendModel{Token: m.From})
if friend.Write {
continue
} else {
break
}
} else if m.Type == types.PERSONUPLOADDATA {
r := SaveFile(m, stream)
if r {
break
}
continue
} else if m.Type == types.PERSONINTERNALINSPECTION {
fmt.Println("内网测试")
var ips []string
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
go MyService.Friend().InternalInspection(ips, m.From)
} else if m.Type == types.PERSONPING {
fmt.Println("来自", m.From, "的ping", m.Data)
msg := m
m.To = m.From
m.Data = config.ServerInfo.Token
m.From = config.ServerInfo.Token
SendData(stream, m)
var ips []string
dataModelByte, _ := json.Marshal(msg.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
backIP := false
if v, ok := UDPAddressMap[msg.From]; ok {
for _, ip := range ips {
if ip == v {
backIP = true
break
}
}
}
if !backIP {
fmt.Println("检测需要查询ip", msg.From)
go MyService.Friend().InternalInspection(ips, msg.From)
}
break
} else if m.Type == types.PERSONIMAGETHUMBNAIL {
m.To = m.From
if data, err := file.GetImage(m.Data.(string), 100, 0); err == nil {
m.Data = data
} else {
m.Data = ""
}
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else {
//不应有不做返回的数据
//ServiceMessage <- m
break
}
}
stream.Close()
}
//文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid, t string) error {
summary := model.FileSummaryModel{}
msg := model.MessageModel{}
msg.Type = types.PERSONSUMMARY
msg.From = config.ServerInfo.Token
msg.To = to
msg.UUId = uuid
fStat, err := os.Stat(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
blockSize, length := file.GetBlockInfo(fStat.Size())
f, err := os.Open(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
//send file summary first
summary.BlockSize = blockSize
summary.Hash = file.GetHashByPath(filePath)
summary.Length = length
summary.Name = fStat.Name()
summary.Size = fStat.Size()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
bufferedReader := bufio.NewReader(f)
buf := make([]byte, blockSize)
defer stream.Close()
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
n, err := bufferedReader.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
}
tran.Hash = file.GetHashByContent(buf[:n])
tran.Index = i
tran.Length = length
fileMsg := model.MessageModel{}
fileMsg.Type = t
fileMsg.Data = tran
fileMsg.From = config.ServerInfo.Token
fileMsg.To = to
fileMsg.UUId = uuid
b, _ := json.Marshal(fileMsg)
prefixLength := file.PrefixLength(len(b))
dataLength := file.DataLength(len(buf[:n]))
data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...)
if _, ok := CancelList[uuid]; ok {
delete(CancelList, uuid)
return nil
}
stream.Write(data)
}
record := model2.PersonDownRecordDBModel{}
record.UUID = uuid
record.Name = f.Name()
record.Downloader = to
record.Path = filePath
record.Size = fStat.Size()
record.Type = types.PERSONFILEDOWNLOAD
if t == types.PERSONUPLOADDATA {
record.Type = types.PERSONFILEUPLOAD
}
MyService.DownRecord().AddDownRecord(record)
return nil
}

View file

@ -35,6 +35,8 @@ func (r *relyService) Create(rely model2.RelyDBModel) {
func (r *relyService) GetInfo(id string) model2.RelyDBModel {
var m model2.RelyDBModel
r.db.Where("custom_id = ?", id).First(&m)
// @tiger - 作为出参不应该直接返回数据库内的格式(见类似问题的注释)
return m
}

View file

@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-07-12 09:48:56
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-15 10:58:54
* @FilePath: /CasaOS/service/service.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package service
import (
@ -23,15 +33,9 @@ type Repository interface {
Notify() NotifyServer
Rely() RelyService
System() SystemService
Shortcuts() ShortcutsService
Person() PersonService
Friend() FriendService
Download() DownloadService
DownRecord() DownRecordService
}
func NewService(db *gorm.DB) Repository {
return &store{
app: NewAppService(db),
user: NewUserService(db),
@ -41,11 +45,6 @@ func NewService(db *gorm.DB) Repository {
notify: NewNotifyService(db),
rely: NewRelyService(db),
system: NewSystemService(),
shortcuts: NewShortcutsService(db),
person: NewPersonService(db),
friend: NewFriendService(db),
download: NewDownloadService(db),
downrecord: NewDownRecordService(db),
}
}
@ -59,32 +58,12 @@ type store struct {
notify NotifyServer
rely RelyService
system SystemService
shortcuts ShortcutsService
person PersonService
friend FriendService
download DownloadService
downrecord DownRecordService
}
func (c *store) DownRecord() DownRecordService {
return c.downrecord
}
func (c *store) Download() DownloadService {
return c.download
}
func (c *store) Friend() FriendService {
return c.friend
}
func (c *store) Rely() RelyService {
return c.rely
}
func (c *store) Shortcuts() ShortcutsService {
return c.shortcuts
}
func (c *store) Person() PersonService {
return c.person
}
func (c *store) System() SystemService {
return c.system
}

View file

@ -1,34 +0,0 @@
package service
import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type ShortcutsService interface {
DeleteData(id string)
AddData(m model2.ShortcutsDBModel)
EditData(m model2.ShortcutsDBModel)
GetList() (list []model2.ShortcutsDBModel)
}
type shortcutsService struct {
db *gorm.DB
}
func (s *shortcutsService) AddData(m model2.ShortcutsDBModel) {
s.db.Create(&m)
}
func (s *shortcutsService) EditData(m model2.ShortcutsDBModel) {
s.db.Save(&m)
}
func (s *shortcutsService) DeleteData(id string) {
var m model2.ShortcutsDBModel
s.db.Where("id=?", id).Delete(&m)
}
func (s *shortcutsService) GetList() (list []model2.ShortcutsDBModel) {
s.db.Order("sort desc,id").Find(&list)
return list
}
func NewShortcutsService(db *gorm.DB) ShortcutsService {
return &shortcutsService{db: db}
}

View file

@ -24,7 +24,6 @@ import (
)
type SystemService interface {
UpSystemConfig(str string, widget string)
UpdateSystemVersion(version string)
GetSystemConfigDebug() []string
GetCasaOSLogs(lineNumber int) string
@ -54,6 +53,12 @@ type SystemService interface {
type systemService struct {
}
func (s *systemService) UpdateUSBAutoMount(state string) {
config.ServerInfo.USBAutoMount = state
config.Cfg.Section("server").Key("USBAutoMount").SetValue(state)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
func (c *systemService) MkdirAll(path string) (int, error) {
_, err := os.Stat(path)
if err == nil {
@ -66,7 +71,7 @@ func (c *systemService) MkdirAll(path string) (int, error) {
return common_err.FILE_OR_DIR_EXISTS, err
}
}
return common_err.ERROR, err
return common_err.SERVICE_ERROR, err
}
func (c *systemService) RenameFile(oldF, newF string) (int, error) {
@ -77,12 +82,12 @@ func (c *systemService) RenameFile(oldF, newF string) (int, error) {
if os.IsNotExist(err) {
err := os.Rename(oldF, newF)
if err != nil {
return common_err.ERROR, err
return common_err.SERVICE_ERROR, err
}
return common_err.SUCCESS, nil
}
}
return common_err.ERROR, err
return common_err.SERVICE_ERROR, err
}
func (c *systemService) CreateFile(path string) (int, error) {
_, err := os.Stat(path)
@ -94,7 +99,7 @@ func (c *systemService) CreateFile(path string) (int, error) {
return common_err.SUCCESS, nil
}
}
return common_err.ERROR, err
return common_err.SERVICE_ERROR, err
}
func (c *systemService) GetDeviceTree() string {
return command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDeviceTree")
@ -232,28 +237,13 @@ func (s *systemService) ExecUSBAutoMountShell(state string) {
func (s *systemService) GetSystemConfigDebug() []string {
return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetSysInfo")
}
func (s *systemService) UpSystemConfig(str string, widget string) {
if len(str) > 0 && str != config.SystemConfigInfo.ConfigStr {
config.Cfg.Section("system").Key("ConfigStr").SetValue(str)
config.SystemConfigInfo.ConfigStr = str
}
if len(widget) > 0 && widget != config.SystemConfigInfo.WidgetList {
config.Cfg.Section("system").Key("WidgetList").SetValue(widget)
config.SystemConfigInfo.WidgetList = widget
}
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
func (s *systemService) UpAppOrderFile(str, id string) {
file.WriteToPath([]byte(str), config.AppInfo.DBPath+"/"+id, "app_order.json")
}
func (s *systemService) GetAppOrderFile(id string) []byte {
return file.ReadFullFile(config.AppInfo.UserDataPath + "/" + id + "/app_order.json")
}
func (s *systemService) UpdateUSBAutoMount(state string) {
config.ServerInfo.USBAutoMount = state
config.Cfg.Section("server").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)

View file

@ -1,503 +0,0 @@
package service
import (
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"os"
path2 "path"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go"
uuid "github.com/satori/go.uuid"
)
var UDPConn *net.UDPConn
var PeopleMap map[string]quic.Stream
var Message chan model.MessageModel
var UDPAddressMap map[string]string
func UDPSendData(msg model.MessageModel, localFilePath string) 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: p} //注意端口必须固定
addr := UDPAddressMap[msg.To]
ticket := msg.To
dstAddr, err := net.ResolveUDPAddr("udp", addr)
session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
if err != nil {
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 err
}
stream, err := session.OpenStreamSync(ctx)
if err != nil {
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 err
}
SayHello(stream, msg.To)
//TODO:发送
SendData(stream, msg)
SendFileData(stream, localFilePath, msg.To, msg.UUId, types.PERSONUPLOADDATA)
stream.Close()
if config.SystemConfigInfo.Analyse != "False" {
go MyService.Casa().PushConnectionStatus(msg.UUId, "OK", msg.From, msg.To, msg.Type)
}
return nil
}
func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) {
ctx, cancel := context.WithTimeout(context.Background(), 100*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: p} //注意端口必须固定
addr := UDPAddressMap[msg.To]
ticket := msg.To
if server {
addr = config.ServerInfo.Handshake + ":9527"
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(ticket), quic_helper.GetQUICConfig())
if err != nil {
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 {
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
}
SayHello(stream, msg.To)
SendData(stream, msg)
go ReadContent(stream)
result := <-Message
stream.Close()
if config.SystemConfigInfo.Analyse != "False" {
go MyService.Casa().PushConnectionStatus(msg.UUId, "OK", msg.From, msg.To, msg.Type)
}
return result, nil
}
func SayHello(stream quic.Stream, to string) {
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = "hello"
msg.To = to
msg.From = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String()
SendData(stream, msg)
}
//发送数据
func SendData(stream quic.Stream, m model.MessageModel) {
b, _ := json.Marshal(m)
prefixLength := file.PrefixLength(len(b))
data := append(prefixLength, b...)
stream.Write(data)
}
//读取数据
func ReadContent(stream quic.Stream) {
for {
prefixByte := make([]byte, 6)
_, err := io.ReadFull(stream, prefixByte)
if err != nil {
fmt.Println(err)
time.Sleep(time.Second * 1)
for k, v := range CancelList {
tempPath := config.AppInfo.TempPath + "/" + v
fmt.Println(file.RMDir(tempPath))
delete(CancelList, k)
}
break
}
prefixLength, err := strconv.Atoi(string(prefixByte))
if err != nil {
fmt.Println(err)
break
}
messageByte := make([]byte, prefixLength)
_, err = io.ReadFull(stream, messageByte)
if err != nil {
fmt.Println(err)
break
}
m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m)
if err != nil {
fmt.Println(err)
break
}
if m.Type == types.PERSONDOWNLOAD {
r := SaveFile(m, stream)
if r {
break
}
} else if m.Type == types.PERSONSUMMARY {
Summary(m, "download")
} 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.NickName = config.UserInfo.NickName
// mi.Token = config.ServerInfo.Token
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
go Dial(msg, false)
Message <- m
break
} else if m.Type == types.PERSONGETIP {
notify := notify.Person{}
notify.ShareId = m.From
if len(m.Data.(string)) == 0 {
if _, ok := UDPAddressMap[m.From]; ok {
notify.Type = "OFFLINE"
go MyService.Notify().SendPersonStatusBySocket(notify)
}
delete(UDPAddressMap, m.From)
Message <- m
break
}
if _, ok := UDPAddressMap[m.From]; !ok {
notify.Type = "ONLINE"
go MyService.Notify().SendPersonStatusBySocket(notify)
}
UDPAddressMap[m.From] = m.Data.(string)
if config.ServerInfo.Token != m.From && strings.Split(m.Data.(string), ":")[0] == strings.Split(UDPAddressMap[config.ServerInfo.Token], ":")[0] {
msg := model.MessageModel{}
msg.Type = types.PERSONINTERNALINSPECTION
msg.Data = ip_helper.GetDeviceAllIP(config.ServerInfo.UDPPort)
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
go Dial(msg, true)
}
Message <- m
break
} else if m.Type == types.PERSONINTERNALINSPECTION {
fmt.Println("接收到反验证")
var ips []string
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
go MyService.Friend().InternalInspection(ips, m.From)
Message <- m
break
} else {
Message <- m
}
}
Message <- model.MessageModel{}
}
func SendIPToServer() {
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
}
func LoopFriend() {
list := MyService.Friend().GetFriendList()
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
for i := 0; i < len(list); i++ {
if _, ok := UDPAddressMap[list[i].Token]; !ok {
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = list[i].Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
}
msg.Type = types.PERSONPING
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = list[i].Token
msg.UUId = uuid.NewV4().String()
if v, ok := UDPAddressMap[list[i].Token]; ok {
if ip_helper.HasLocalIP(net.ParseIP(strings.Split(v, ":")[0])) {
msg.Data = ip_helper.GetDeviceAllIP(config.ServerInfo.UDPPort)
}
oldIP := UDPAddressMap[list[i].Token]
data, err := Dial(msg, false)
if err != nil || reflect.DeepEqual(data, model.MessageModel{}) || len(data.Data.(string)) == 0 {
if oldIP == UDPAddressMap[list[i].Token] {
notify := notify.Person{}
notify.ShareId = data.From
notify.Type = "LEAVE"
go MyService.Notify().SendPersonStatusBySocket(notify)
delete(UDPAddressMap, list[i].Token)
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = list[i].Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
}
}
}
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)
}
}
//file summary
func Summary(m model.MessageModel, t string) {
dataModel := model.FileSummaryModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
}
task := MyService.Download().GetDownloadById(m.UUId)
task.State = types.DOWNLOADING
fullPath := path2.Join(task.LocalPath, task.Name)
if len(dataModel.Message) > 0 {
task.State = types.DOWNLOADERROR
task.Error = dataModel.Message
}
//The file already exists and the file is the same, no need to download
if t != "upload" && 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 = types.PERSONFILEDOWNLOAD
task.From = m.From
if t == "upload" {
task.Type = types.PERSONFILERECEIVEUPLOAD
}
MyService.Download().SaveDownload(task)
}
//Save file fragment
func SaveFile(m model.MessageModel, stream quic.Stream) bool {
dataModelByte, _ := json.Marshal(m.Data)
dataModel := model.TranFileModel{}
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
return false
}
dataLengthByte := make([]byte, 8)
_, err = io.ReadFull(stream, dataLengthByte)
if err != nil {
fmt.Println(err)
return false
}
dataLength, err := strconv.Atoi(string(dataLengthByte))
if err != nil {
fmt.Println(err)
return false
}
dataByte := make([]byte, dataLength)
_, err = io.ReadFull(stream, dataByte)
if err != nil {
fmt.Println(err)
return false
}
sum := md5.Sum(dataByte)
hash := hex.EncodeToString(sum[:])
if dataModel.Hash != hash {
fmt.Println("hash不匹配", hash, dataModel.Hash)
return false
}
tempPath := config.AppInfo.TempPath + "/" + m.UUId
file.IsNotExistMkDir(tempPath)
filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
_, err = os.Stat(filepath)
if os.IsNotExist(err) {
err = ioutil.WriteFile(filepath, dataByte, 0644)
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
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.PersonDownloadDBModel{}
task.UUID = m.UUId
if err != nil {
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
}
}
files, err := ioutil.ReadDir(tempPath)
if err != nil {
fmt.Println(err)
return false
}
if len(files) >= dataModel.Length {
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)
summary.State = types.DOWNLOADFINISHED
MyService.Download().EditDownloadState(summary)
} else {
os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
summary.State = types.DOWNLOADERROR
summary.Error = "hash mismatch"
MyService.Download().SetDownloadError(summary)
}
return true
}
return false
}

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-03-18 11:40:55
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-23 19:45:49
* @LastEditTime: 2022-07-12 10:05:37
* @FilePath: /CasaOS/service/user.go
* @Description:
* @Website: https://www.casaos.io
@ -15,13 +15,11 @@ import (
"mime/multipart"
"os"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type UserService interface {
SetUser(username, pwd, token, email, desc, nickName string) error
UpLoadFile(file multipart.File, name string) error
CreateUser(m model.UserDBModel) model.UserDBModel
GetUserCount() (userCount int64)
@ -31,6 +29,7 @@ type UserService interface {
GetUserAllInfoById(id string) (m model.UserDBModel)
GetUserAllInfoByName(userName string) (m model.UserDBModel)
DeleteUserById(id string)
DeleteAllUser()
GetUserInfoByUserName(userName string) (m model.UserDBModel)
GetAllUserName() (list []model.UserDBModel)
}
@ -41,12 +40,15 @@ type userService struct {
db *gorm.DB
}
func (u *userService) DeleteAllUser() {
u.db.Where("1=1").Delete(&model.UserDBModel{})
}
func (u *userService) DeleteUserById(id string) {
u.db.Where("id= ?", id).Delete(&model.UserDBModel{})
}
func (u *userService) GetAllUserName() (list []model.UserDBModel) {
u.db.Select("user_name").Find(&list)
u.db.Select("username").Find(&list)
return
}
func (u *userService) CreateUser(m model.UserDBModel) model.UserDBModel {
@ -70,47 +72,19 @@ func (u *userService) GetUserAllInfoById(id string) (m model.UserDBModel) {
return
}
func (u *userService) GetUserAllInfoByName(userName string) (m model.UserDBModel) {
u.db.Where("user_name= ?", userName).First(&m)
u.db.Where("username= ?", userName).First(&m)
return
}
func (u *userService) GetUserInfoById(id string) (m model.UserDBModel) {
u.db.Select("user_name", "id", "role", "nick_name", "description", "avatar").Where("id= ?", id).First(&m)
u.db.Select("username", "id", "role", "nickname", "description", "avatar", "email").Where("id= ?", id).First(&m)
return
}
func (u *userService) GetUserInfoByUserName(userName string) (m model.UserDBModel) {
u.db.Select("user_name", "id", "role", "nick_name", "description", "avatar").Where("user_name= ?", userName).First(&m)
u.db.Select("username", "id", "role", "nickname", "description", "avatar", "email").Where("username= ?", userName).First(&m)
return
}
//设置用户名密码
func (u *userService) SetUser(username, pwd, token, email, desc, nickName string) error {
if len(username) > 0 {
config.Cfg.Section("user").Key("UserName").SetValue(username)
config.UserInfo.UserName = username
config.Cfg.Section("user").Key("Initialized").SetValue("true")
config.UserInfo.Initialized = true
}
if len(pwd) > 0 {
config.Cfg.Section("user").Key("PWD").SetValue(pwd)
config.UserInfo.PWD = pwd
}
if len(email) > 0 {
config.Cfg.Section("user").Key("Email").SetValue(email)
config.UserInfo.Email = email
}
if len(desc) > 0 {
config.Cfg.Section("user").Key("Description").SetValue(desc)
config.UserInfo.Description = desc
}
if len(nickName) > 0 {
config.Cfg.Section("user").Key("NickName").SetValue(nickName)
config.UserInfo.NickName = nickName
}
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
return nil
}
//上传文件
func (c *userService) UpLoadFile(file multipart.File, url string) error {
out, _ := os.OpenFile(url, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)

View file

@ -2,7 +2,7 @@
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-02-17 18:53:22
* @LastEditors: LinkLeong
* @LastEditTime: 2022-07-01 15:15:09
* @LastEditTime: 2022-07-18 18:47:15
* @FilePath: /CasaOS/types/system.go
* @Description:
* @Website: https://www.casaos.io
@ -10,6 +10,6 @@
*/
package types
const CURRENTVERSION = "0.3.3"
const CURRENTVERSION = "0.3.4"
const BODY = ""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 66 65" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><style><![CDATA[.B{stroke:none}.C{fill-rule:nonzero}.D{stroke:#fff}.E{stroke-width:3.271}]]></style><use xlink:href="#B" x=".5" y=".5"/><defs><linearGradient id="A" x1="49.97%" y1="99.94%" x2="49.97%" y2="0.00%"><stop offset="0%" stop-color="#0882c8"/><stop offset="100%" stop-color="#26b6db"/></linearGradient></defs><symbol id="B" overflow="visible"><path d="M0 32C0 14.272 14.272 0 32 0s32 14.272 32 32-14.272 32-32 32S0 49.728 0 32z" fill="url(#A)" class="B C"/><path d="M8.177 31.891C8.177 18.693 18.802 8.068 32 8.068s23.823 10.625 23.823 23.823S45.198 55.714 32 55.714 8.177 45.089 8.177 31.891z" fill="none" class="D E"/><path d="M51.625 26.058c2.562.872 5.342-.491 6.215-3.053s-.491-5.342-3.053-6.215-5.342.491-6.215 3.053.491 5.342 3.053 6.215z" class="B C"/><path d="M53.206 21.479L36.797 35.108" fill="none" class="D E"/><path d="M42.304 49.608c-.218 2.671 1.745 5.07 4.47 5.342 2.726.218 5.07-1.744 5.343-4.47.218-2.671-1.745-5.07-4.47-5.343-2.726-.218-5.124 1.745-5.342 4.47z" class="B C"/><path d="M47.155 50.044L36.797 35.107" fill="none" class="D E"/><path d="M32.708 37.779c1.472 2.29 4.525 2.944 6.76 1.472 2.29-1.472 2.944-4.525 1.472-6.76-1.472-2.29-4.525-2.944-6.76-1.472-2.29 1.417-2.944 4.47-1.472 6.76zm-21.152-4.307c-2.344-1.363-5.342-.6-6.705 1.69-1.363 2.344-.6 5.342 1.69 6.705 2.344 1.363 5.342.6 6.705-1.69s.6-5.288-1.69-6.705z" class="B C"/><path d="M9.049 37.669l27.748-2.562" fill="none" class="D E"/></symbol></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="88" width="88"> <path style="fill:#00adef;" d="m0,12.402,35.687-4.8602,0.0156,34.423-35.67,0.20313zm35.67,33.529,0.0277,34.453-35.67-4.9041-0.002-29.78zm4.3261-39.025,47.318-6.906,0,41.527-47.318,0.37565zm47.329,39.349-0.0111,41.34-47.318-6.6784-0.0663-34.739z"/> </svg>

Before

Width:  |  Height:  |  Size: 486 B

View file

@ -20,7 +20,7 @@
<title>
CasaOS
</title>
<link href="/ui/css/10.f0cf5fc3.css" rel="prefetch"><link href="/ui/css/11.32be8789.css" rel="prefetch"><link href="/ui/css/12.ee780c90.css" rel="prefetch"><link href="/ui/css/13.dc77452d.css" rel="prefetch"><link href="/ui/css/14.daa8e8be.css" rel="prefetch"><link href="/ui/css/18.1f93b660.css" rel="prefetch"><link href="/ui/css/19.046fd3d8.css" rel="prefetch"><link href="/ui/css/3.623fa25f.css" rel="prefetch"><link href="/ui/css/9.f27e442b.css" rel="prefetch"><link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/10.js" rel="prefetch"><link href="/ui/js/11.js" rel="prefetch"><link href="/ui/js/12.js" rel="prefetch"><link href="/ui/js/13.js" rel="prefetch"><link href="/ui/js/14.js" rel="prefetch"><link href="/ui/js/15.js" rel="prefetch"><link href="/ui/js/16.js" rel="prefetch"><link href="/ui/js/17.js" rel="prefetch"><link href="/ui/js/18.js" rel="prefetch"><link href="/ui/js/19.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/20.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/8.js" rel="prefetch"><link href="/ui/js/9.js" rel="prefetch"><link href="/ui/css/app.1fb33240.css" rel="preload" as="style"><link href="/ui/css/vendors~app.6b5df7e4.css" rel="preload" as="style"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/vendors~app.js" rel="preload" as="script"><link href="/ui/css/vendors~app.6b5df7e4.css" rel="stylesheet"><link href="/ui/css/app.1fb33240.css" rel="stylesheet"></head>
<link href="/ui/css/1.73b4186b.css" rel="prefetch"><link href="/ui/css/10.daa8e8be.css" rel="prefetch"><link href="/ui/css/11.232c3bcb.css" rel="prefetch"><link href="/ui/css/15.1f93b660.css" rel="prefetch"><link href="/ui/css/16.046fd3d8.css" rel="prefetch"><link href="/ui/css/5.ae1e42db.css" rel="prefetch"><link href="/ui/css/6.f02d5b96.css" rel="prefetch"><link href="/ui/css/7.32be8789.css" rel="prefetch"><link href="/ui/css/8.ee780c90.css" rel="prefetch"><link href="/ui/css/9.a00e5221.css" rel="prefetch"><link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/10.js" rel="prefetch"><link href="/ui/js/11.js" rel="prefetch"><link href="/ui/js/12.js" rel="prefetch"><link href="/ui/js/13.js" rel="prefetch"><link href="/ui/js/14.js" rel="prefetch"><link href="/ui/js/15.js" rel="prefetch"><link href="/ui/js/16.js" rel="prefetch"><link href="/ui/js/17.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/8.js" rel="prefetch"><link href="/ui/js/9.js" rel="prefetch"><link href="/ui/css/app.e3d6571d.css" rel="preload" as="style"><link href="/ui/css/vendors~app.6b5df7e4.css" rel="preload" as="style"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/vendors~app.js" rel="preload" as="script"><link href="/ui/css/vendors~app.6b5df7e4.css" rel="stylesheet"><link href="/ui/css/app.e3d6571d.css" rel="stylesheet"></head>
<body>
<noscript>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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