From cee34ec1c264a129de55c52dc8325dab91e3e998 Mon Sep 17 00:00:00 2001 From: link Date: Mon, 15 Aug 2022 11:37:21 +0800 Subject: [PATCH] 0.3.5 (#451) * initial completion of the sharing function * Adjusting multi-partition disk mounts * Add file sharing function * update usb auto mount shell * update samba config * add umount disk function * update change log * update usb auto mount \ * update usb auto mount * Update periodical.go --- .gitignore | 1 + CHANGELOG.md | 16 + go.mod | 11 +- go.sum | 54 +- main.go | 16 +- model/connections.go | 20 + model/disk.go | 50 +- model/share.go | 17 + model/zima.go | 27 +- pkg/samba/smaba.go | 75 +++ pkg/sqlite/db.go | 4 +- pkg/utils/common_err/e.go | 20 +- pkg/utils/file/file.go | 17 + pkg/utils/udev_helper.go | 33 ++ route/darwin.go | 25 + route/init.go | 68 ++- route/periodical.go | 78 ++- route/route.go | 23 + route/v1/disk.go | 247 +++++++--- route/v1/docker.go | 9 +- route/v1/file.go | 16 + route/v1/samba.go | 180 +++++++ route/v1/samba_test.go | 73 +++ route/v1/storage.go | 91 +++- route/v1/system.go | 60 ++- service/connections.go | 69 +++ service/disk.go | 8 +- service/docker.go | 43 +- service/model/o_connections.go | 28 ++ service/model/o_shares.go | 24 + service/service.go | 49 +- service/shares.go | 151 ++++++ service/system.go | 11 +- shell/helper.sh | 39 +- types/system.go | 6 +- web/index.html | 2 +- web/js/10.js | 8 +- web/js/11.js | 8 +- web/js/12.js | 8 +- web/js/4.js | 878 +++++++++++++++++++++++---------- web/js/5.js | 18 +- web/js/7.js | 8 +- web/js/8.js | 8 +- web/js/9.js | 8 +- web/js/app.js | 136 +++-- web/js/vendors~app.js | 18 +- 46 files changed, 2167 insertions(+), 592 deletions(-) create mode 100644 model/connections.go create mode 100644 model/share.go create mode 100644 pkg/samba/smaba.go create mode 100644 pkg/utils/udev_helper.go create mode 100644 route/darwin.go create mode 100644 route/v1/samba.go create mode 100644 route/v1/samba_test.go create mode 100644 service/connections.go create mode 100644 service/model/o_connections.go create mode 100644 service/model/o_shares.go create mode 100644 service/shares.go diff --git a/.gitignore b/.gitignore index 0b33be0..62ef035 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ __debug_bin main CasaOS github.com +.all-contributorsrc diff --git a/CHANGELOG.md b/CHANGELOG.md index d64918d..6704e1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [0.3.5-alpha] - 2022-08-08 + +### Added + +- [File] Mount the shared samba +- [File] File sharing via Samba +- [System] You can share casaos on Twitter, facebook, reddit + +### Changed + +- [Disk] Support for mounting existing data disks + +### Fixed + +- [App] fixed uninstalling imported docker container apps results in wiping ALL your config data from them ([#360](https://github.com/IceWhaleTech/CasaOS/issues/360)) + ## [0.3.4] - 2022-07-29(UTC) ### Added diff --git a/go.mod b/go.mod index f329d17..c7a3e1f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Microsoft/hcsshim v0.8.22 // indirect - github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect github.com/ambelovsky/go-structs v1.1.0 // indirect github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109 github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect @@ -22,17 +21,18 @@ require ( 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-playground/validator/v10 v10.6.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/golang-jwt/jwt/v4 v4.4.1 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/mock v1.6.0 github.com/gomodule/redigo v1.8.5 github.com/google/go-github/v36 v36.0.0 github.com/google/uuid v1.3.0 // indirect github.com/googollee/go-socket.io v1.6.2 github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.4.2 + github.com/hirochachacha/go-smb2 v1.1.0 github.com/jinzhu/copier v0.3.2 github.com/json-iterator/go v1.1.11 // indirect github.com/klauspost/compress v1.13.6 // indirect @@ -47,16 +47,17 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/selinux v1.8.5 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pilebones/go-udev v0.9.0 github.com/pkg/errors v0.9.1 github.com/prometheus/procfs v0.7.3 // indirect github.com/robfig/cron v1.2.0 github.com/satori/go.uuid v1.2.0 - github.com/shirou/gopsutil/v3 v3.21.5 + github.com/shirou/gopsutil/v3 v3.22.7 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/stretchr/testify v1.8.0 github.com/tidwall/gjson v1.10.2 - github.com/tklauser/go-sysconf v0.3.6 // indirect github.com/ugorji/go v1.2.6 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/zap v1.10.0 @@ -64,7 +65,6 @@ require ( golang.org/x/mod v0.5.0 // indirect golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect 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 @@ -75,7 +75,6 @@ require ( gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gorm.io/driver/sqlite v1.2.6 gorm.io/gorm v1.22.5 ) diff --git a/go.sum b/go.sum index f5c119c..202770e 100644 --- a/go.sum +++ b/go.sum @@ -86,9 +86,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 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/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -330,6 +327,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w= +github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= 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.2 h1:VMBkd4ZB1Hl7e1lOA5gEZ/qdD3d9vLIq57xKWgPCCV8= @@ -356,9 +355,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= @@ -455,8 +453,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs= @@ -513,6 +512,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI= +github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -577,6 +578,8 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -702,6 +705,8 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pilebones/go-udev v0.9.0 h1:N1uEO/SxUwtIctc0WLU0t69JeBxIYEYnj8lT/Nabl9Q= +github.com/pilebones/go-udev v0.9.0/go.mod h1:T2eI2tUSK0hA2WS5QLjXJUfQkluZQu+18Cqvem3CaXI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -709,6 +714,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= 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= @@ -756,8 +763,8 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= 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/shirou/gopsutil/v3 v3.22.7 h1:flKnuCMfUUrO+oAvwAd6GKZgnPzr098VA/UJ14nhJd4= +github.com/shirou/gopsutil/v3 v3.22.7/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= 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= @@ -818,14 +825,17 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 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= @@ -837,12 +847,10 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek= -github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4= -github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= -github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8= -github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= -github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= +github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= @@ -883,6 +891,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1103,10 +1113,9 @@ golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1116,8 +1125,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo= -golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1340,8 +1350,8 @@ 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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= diff --git a/main.go b/main.go index 932f28d..0aa2a70 100644 --- a/main.go +++ b/main.go @@ -15,6 +15,7 @@ import ( "github.com/IceWhaleTech/CasaOS/pkg/utils/random" "github.com/IceWhaleTech/CasaOS/route" "github.com/IceWhaleTech/CasaOS/service" + "github.com/IceWhaleTech/CasaOS/types" "github.com/robfig/cron" "gorm.io/gorm" @@ -26,21 +27,31 @@ var configFlag = flag.String("c", "", "config address") var dbFlag = flag.String("db", "", "db path") var resetUser = flag.Bool("ru", false, "reset user") var user = flag.String("user", "", "user name") +var version = flag.Bool("v", false, "show version") func init() { flag.Parse() + if *version { + fmt.Println("v" + types.CURRENTVERSION) + return + } config.InitSetup(*configFlag) config.UpdateSetup() + loger.LogInit() if len(*dbFlag) == 0 { *dbFlag = config.AppInfo.DBPath + "/db" } + sqliteDB = sqlite.GetDb(*dbFlag) //gredis.GetRedisConn(config.RedisInfo), + service.MyService = service.NewService(sqliteDB) + service.Cache = cache.Init() service.GetToken() + service.NewVersionApp = make(map[string]string) route.InitFunction() @@ -62,6 +73,9 @@ func init() { // @BasePath /v1 func main() { service.NotifyMsg = make(chan notify.Message, 10) + if *version { + return + } if *resetUser { if user == nil || len(*user) == 0 { fmt.Println("user is empty") @@ -81,7 +95,7 @@ func main() { return } go route.SocketInit(service.NotifyMsg) - + go route.MonitoryUSB() //model.Setup() //gredis.Setup() r := route.InitRouter() diff --git a/model/connections.go b/model/connections.go new file mode 100644 index 0000000..84719ab --- /dev/null +++ b/model/connections.go @@ -0,0 +1,20 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-27 10:30:43 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-04 20:06:04 + * @FilePath: /CasaOS/model/connections.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package model + +type Connections struct { + ID uint `json:"id"` + Username string `json:"username"` + Password string `json:"password,omitempty"` + Host string `json:"host"` + Port string `json:"port"` + MountPoint string `json:"mount_point"` +} diff --git a/model/disk.go b/model/disk.go index dd48976..75d3bc5 100644 --- a/model/disk.go +++ b/model/disk.go @@ -2,7 +2,7 @@ * @Author: LinkLeong link@icewhale.com * @Date: 2022-07-13 10:43:45 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-13 11:00:04 + * @LastEditTime: 2022-08-03 14:45:35 * @FilePath: /CasaOS/model/disk.go * @Description: * @Website: https://www.casaos.io @@ -39,6 +39,7 @@ type LSBLKModel struct { Serial string `json:"serial"` Children []LSBLKModel `json:"children"` SubSystems string `json:"subsystems"` + Label string `json:"label"` //详情特有 StartSector uint64 `json:"start_sector,omitempty"` Rota bool `json:"rota"` //true(hhd) false(ssd) @@ -47,35 +48,46 @@ type LSBLKModel struct { } type Drive struct { - Name string `json:"name"` - Size uint64 `json:"size"` - Model string `json:"model"` - Health string `json:"health"` - Temperature int `json:"temperature"` - DiskType string `json:"disk_type"` - NeedFormat bool `json:"need_format"` - Serial string `json:"serial"` - Path string `json:"path"` + Name string `json:"name"` + Size uint64 `json:"size"` + Model string `json:"model"` + Health string `json:"health"` + Temperature int `json:"temperature"` + DiskType string `json:"disk_type"` + NeedFormat bool `json:"need_format"` + Serial string `json:"serial"` + Path string `json:"path"` + ChildrenNumber int `json:"children_number"` } type DriveUSB struct { - Name string `json:"name"` - Size uint64 `json:"size"` - Used uint64 `json:"use"` - Model string `json:"model"` - Mount bool `json:"mount"` - Avail uint64 `json:"avail"` + Name string `json:"name"` + Size uint64 `json:"size"` + Model string `json:"model"` + Avail uint64 `json:"avail"` + Children []USBChildren `json:"children"` +} +type USBChildren struct { + Name string `json:"name"` + Size uint64 `json:"size"` + Avail uint64 `json:"avail"` + MountPoint string `json:"mount_point"` } type Storage struct { - Name string `json:"name"` - MountPoint string `json:"mountpoint"` + MountPoint string `json:"mount_point"` Size string `json:"size"` Avail string `json:"avail"` //可用空间 Type string `json:"type"` - CreatedAt int64 `json:"create_at"` Path string `json:"path"` DriveName string `json:"drive_name"` + Label string `json:"label"` +} +type Storages struct { + DiskName string `json:"disk_name"` + Size uint64 `json:"size"` + Path string `json:"path"` + Children []Storage `json:"children"` } type Summary struct { diff --git a/model/share.go b/model/share.go new file mode 100644 index 0000000..f164db1 --- /dev/null +++ b/model/share.go @@ -0,0 +1,17 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-26 11:12:12 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-07-27 14:58:55 + * @FilePath: /CasaOS/model/share.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package model + +type Shares struct { + ID uint `json:"id"` + Anonymous bool `json:"anonymous"` + Path string `json:"path"` +} diff --git a/model/zima.go b/model/zima.go index 217b3cc..e144b7c 100644 --- a/model/zima.go +++ b/model/zima.go @@ -1,14 +1,25 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-05-13 18:15:46 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-01 18:32:57 + * @FilePath: /CasaOS/model/zima.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ package model import "time" type Path struct { - Name string `json:"name"` //File name or document name - Path string `json:"path"` //Full path to file or folder - IsDir bool `json:"is_dir"` //Is it a folder - Date time.Time `json:"date"` - Size int64 `json:"size"` //File Size - Type string `json:"type,omitempty"` - Label string `json:"label,omitempty"` - Write bool `json:"write"` + Name string `json:"name"` //File name or document name + Path string `json:"path"` //Full path to file or folder + IsDir bool `json:"is_dir"` //Is it a folder + Date time.Time `json:"date"` + Size int64 `json:"size"` //File Size + Type string `json:"type,omitempty"` + Label string `json:"label,omitempty"` + Write bool `json:"write"` + Extensions map[string]interface{} `json:"extensions"` } diff --git a/pkg/samba/smaba.go b/pkg/samba/smaba.go new file mode 100644 index 0000000..58a9874 --- /dev/null +++ b/pkg/samba/smaba.go @@ -0,0 +1,75 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-27 10:35:29 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-01 13:56:44 + * @FilePath: /CasaOS/pkg/samba/smaba.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package samba + +import ( + "errors" + "net" + + "github.com/hirochachacha/go-smb2" +) + +func ConnectSambaService(host, port, username, password, directory string) error { + conn, err := net.Dial("tcp", host+":"+port) + if err != nil { + return err + } + defer conn.Close() + d := &smb2.Dialer{ + Initiator: &smb2.NTLMInitiator{ + User: username, + Password: password, + }, + } + + s, err := d.Dial(conn) + if err != nil { + return err + } + defer s.Logoff() + names, err := s.ListSharenames() + if err != nil { + return err + } + + for _, name := range names { + if name == directory { + return nil + } + } + return errors.New("directory not found") +} + +//get share name list +func GetSambaSharesList(host, port, username, password string) ([]string, error) { + conn, err := net.Dial("tcp", host+":"+port) + if err != nil { + return nil, err + } + defer conn.Close() + d := &smb2.Dialer{ + Initiator: &smb2.NTLMInitiator{ + User: username, + Password: password, + }, + } + + s, err := d.Dial(conn) + if err != nil { + return nil, err + } + defer s.Logoff() + names, err := s.ListSharenames() + if err != nil { + return nil, err + } + return names, err +} diff --git a/pkg/sqlite/db.go b/pkg/sqlite/db.go index 3503cd0..383d2c4 100644 --- a/pkg/sqlite/db.go +++ b/pkg/sqlite/db.go @@ -2,7 +2,7 @@ * @Author: LinkLeong link@icewhale.com * @Date: 2022-05-13 18:15:46 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-11 18:10:53 + * @LastEditTime: 2022-07-27 11:25:26 * @FilePath: /CasaOS/pkg/sqlite/db.go * @Description: * @Website: https://www.casaos.io @@ -53,7 +53,7 @@ func GetDb(dbPath string) *gorm.DB { drop table o_user; `) - err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.UserDBModel{}) + err = db.AutoMigrate(&model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.UserDBModel{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}) 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") diff --git a/pkg/utils/common_err/e.go b/pkg/utils/common_err/e.go index 79ee8cd..cc2a272 100644 --- a/pkg/utils/common_err/e.go +++ b/pkg/utils/common_err/e.go @@ -27,6 +27,9 @@ const ( PORT_IS_OCCUPIED = 20004 COMMAND_ERROR_INVALID_OPERATION = 20005 VERIFICATION_FAILURE = 20006 + Record_NOT_EXIST = 20007 + Record_ALREADY_EXIST = 20008 + SERVICE_NOT_RUNNING = 20009 //disk NAME_NOT_AVAILABLE = 40001 @@ -48,8 +51,9 @@ const ( DIR_NOT_EXISTS = 60004 SOURCE_DES_SAME = 60005 - //shortcuts - SHORTCUTS_URL_ERROR = 70001 + //share + SHARE_ALREADY_EXISTS = 70001 + SHARE_NAME_ALREADY_EXISTS = 70002 ) var MsgFlags = map[int]string{ @@ -78,6 +82,9 @@ var MsgFlags = map[int]string{ FILE_OR_DIR_EXISTS: "File or folder already exists", PORT_IS_OCCUPIED: "Port is occupied", VERIFICATION_FAILURE: "Verification failure", + Record_ALREADY_EXIST: "Record already exists", + Record_NOT_EXIST: "Record does not exist", + SERVICE_NOT_RUNNING: "Service is not running", //app UNINSTALL_APP_ERROR: "Error uninstalling app", @@ -91,16 +98,17 @@ var MsgFlags = map[int]string{ REMOVE_MOUNT_POINT_ERROR: "Failed to remove mount point", DISK_BUSYING: "Drive is busy", FORMAT_ERROR: "Formatting failed, please check if the directory is occupied", - + //share + SHARE_ALREADY_EXISTS: "Share already exists", + SHARE_NAME_ALREADY_EXISTS: "Share name already exists", // SOURCE_DES_SAME: "Source and destination cannot be the same.", FILE_DOES_NOT_EXIST: "File does not exist", DIR_NOT_EXISTS: "Directory does not exist", - FILE_READ_ERROR: "File read error", - FILE_DELETE_ERROR: "Delete error", - SHORTCUTS_URL_ERROR: "URL error", + FILE_READ_ERROR: "File read error", + FILE_DELETE_ERROR: "Delete error", COMMAND_ERROR_INVALID_OPERATION: "invalid operation", } diff --git a/pkg/utils/file/file.go b/pkg/utils/file/file.go index 20460ed..b08dcda 100644 --- a/pkg/utils/file/file.go +++ b/pkg/utils/file/file.go @@ -547,3 +547,20 @@ func MoveFile(sourcePath, destPath string) error { } return nil } + +func ReadLine(lineNumber int, path string) string { + file, err := os.Open(path) + if err != nil { + return "" + } + fileScanner := bufio.NewScanner(file) + lineCount := 1 + for fileScanner.Scan() { + if lineCount == lineNumber { + return fileScanner.Text() + } + lineCount++ + } + defer file.Close() + return "" +} diff --git a/pkg/utils/udev_helper.go b/pkg/utils/udev_helper.go new file mode 100644 index 0000000..701a6de --- /dev/null +++ b/pkg/utils/udev_helper.go @@ -0,0 +1,33 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-08-10 16:06:12 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-10 16:11:37 + * @FilePath: /CasaOS/pkg/utils/udev_helper.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package utils + +// func getOptionnalMatcher() (matcher netlink.Matcher, err error) { +// if filePath == nil || *filePath == "" { +// return nil, nil +// } + +// stream, err := ioutil.ReadFile(*filePath) +// if err != nil { +// return nil, err +// } + +// if stream == nil { +// return nil, fmt.Errorf("Empty, no rules provided in \"%s\", err: %w", *filePath, err) +// } + +// var rules netlink.RuleDefinitions +// if err := json.Unmarshal(stream, &rules); err != nil { +// return nil, fmt.Errorf("Wrong rule syntax, err: %w", err) +// } + +// return &rules, nil +// } diff --git a/route/darwin.go b/route/darwin.go new file mode 100644 index 0000000..8e6dd35 --- /dev/null +++ b/route/darwin.go @@ -0,0 +1,25 @@ +//go:build darwin +// +build darwin + +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-08-12 14:22:28 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-12 18:41:14 + * @FilePath: /CasaOS/route/darwin.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ + +package route + +func MonitoryUSB() { + +} +func SendAllHardwareStatusBySocket() { + +} +func SendUSBBySocket() { + +} diff --git a/route/init.go b/route/init.go index 7aedb2f..19e4e20 100644 --- a/route/init.go +++ b/route/init.go @@ -1,11 +1,13 @@ package route import ( + "fmt" "os" "strconv" "strings" "github.com/IceWhaleTech/CasaOS/pkg/config" + "github.com/IceWhaleTech/CasaOS/pkg/samba" "github.com/IceWhaleTech/CasaOS/pkg/utils/command" "github.com/IceWhaleTech/CasaOS/pkg/utils/encryption" "github.com/IceWhaleTech/CasaOS/pkg/utils/file" @@ -15,15 +17,14 @@ import ( ) func InitFunction() { - ShellInit() CheckSerialDiskMount() - CheckToken2_11() ImportApplications() + // Soon to be removed ChangeAPIUrl() - MoveUserToDB() + InitNetworkMount() } func CheckSerialDiskMount() { @@ -40,25 +41,25 @@ func CheckSerialDiskMount() { command.ExecEnabledSMART(v.Path) if v.Children != nil { for _, h := range v.Children { - if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" { - if m, ok := mountPoint[h.UUID]; ok { - //mount point check - volume := m - if !file.CheckNotExist(m) { - for i := 0; file.CheckNotExist(volume); i++ { - volume = m + strconv.Itoa(i+1) - } + //if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" { + if m, ok := mountPoint[h.UUID]; ok { + //mount point check + volume := m + if !file.CheckNotExist(m) { + for i := 0; file.CheckNotExist(volume); i++ { + volume = m + strconv.Itoa(i+1) } - service.MyService.Disk().MountDisk(h.Path, volume) - if volume != m { - ms := model2.SerialDisk{} - ms.UUID = v.UUID - ms.MountPoint = volume - service.MyService.Disk().UpdateMountPoint(ms) - } - } + service.MyService.Disk().MountDisk(h.Path, volume) + if volume != m { + ms := model2.SerialDisk{} + ms.UUID = v.UUID + ms.MountPoint = volume + service.MyService.Disk().UpdateMountPoint(ms) + } + } + //} } } } @@ -138,3 +139,32 @@ func MoveUserToDB() { } } + +func InitNetworkMount() { + connections := service.MyService.Connections().GetConnectionsList() + for _, v := range connections { + connection := service.MyService.Connections().GetConnectionByID(fmt.Sprint(v.ID)) + directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password) + if err != nil { + service.MyService.Connections().DeleteConnection(fmt.Sprint(connection.ID)) + continue + } + baseHostPath := "/mnt/" + connection.Host + + mountPointList := service.MyService.System().GetDirPath(baseHostPath) + for _, v := range mountPointList { + service.MyService.Connections().UnmountSmaba(v.Path) + } + + os.RemoveAll(baseHostPath) + + file.IsNotExistMkDir(baseHostPath) + for _, v := range directories { + mountPoint := baseHostPath + "/" + v + file.IsNotExistMkDir(mountPoint) + service.MyService.Connections().MountSmaba(connection.Username, connection.Host, v, connection.Port, mountPoint, connection.Password) + } + connection.Directories = strings.Join(directories, ",") + service.MyService.Connections().UpdateConnection(&connection) + } +} diff --git a/route/periodical.go b/route/periodical.go index 0740ab2..a4bcb10 100644 --- a/route/periodical.go +++ b/route/periodical.go @@ -1,8 +1,11 @@ +//go:build !darwin +// +build !darwin + /* * @Author: LinkLeong link@icewhale.com * @Date: 2022-07-01 15:11:36 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-21 15:25:07 + * @LastEditTime: 2022-08-12 18:58:00 * @FilePath: /CasaOS/route/periodical.go * @Description: * @Website: https://www.casaos.io @@ -11,14 +14,20 @@ package route import ( + "os" + "os/signal" "reflect" "strconv" "strings" + "syscall" "time" "unsafe" "github.com/IceWhaleTech/CasaOS/model" + "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/service" + "github.com/pilebones/go-udev/netlink" + "go.uber.org/zap" ) func SendNetINfoBySocket() { @@ -129,26 +138,22 @@ func SendUSBBySocket() { usb := []model.DriveUSB{} for _, v := range usbList { if v.Tran == "usb" { + isMount := false 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 { + isMount = true avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) temp.Avail += avail - used, _ := strconv.ParseUint(child.FSUsed, 10, 64) - temp.Used += used - } else { - mountTemp = false + } } - temp.Mount = mountTemp - usb = append(usb, temp) + if isMount { + usb = append(usb, temp) + } } } service.MyService.Notify().SendUSBInfoBySocket(usb) @@ -246,26 +251,22 @@ func SendAllHardwareStatusBySocket() { usb := []model.DriveUSB{} for _, v := range usbList { if v.Tran == "usb" { + isMount = false 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 { + isMount = true avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) temp.Avail += avail - used, _ := strconv.ParseUint(child.FSUsed, 10, 64) - temp.Used += used - } else { - mountTemp = false } } - temp.Mount = mountTemp - usb = append(usb, temp) + if isMount { + usb = append(usb, temp) + } + } } memInfo := service.MyService.System().GetMemInfo() @@ -273,3 +274,38 @@ func SendAllHardwareStatusBySocket() { service.MyService.Notify().SendAllHardwareStatusBySocket(summary, usb, memInfo, cpuData, newNet) } +func MonitoryUSB() { + var matcher netlink.Matcher + + conn := new(netlink.UEventConn) + if err := conn.Connect(netlink.UdevEvent); err != nil { + loger.Error("udev err", zap.Any("Unable to connect to Netlink Kobject UEvent socket", err)) + } + defer conn.Close() + + queue := make(chan netlink.UEvent) + errors := make(chan error) + quit := conn.Monitor(queue, errors, matcher) + + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + go func() { + <-signals + close(quit) + os.Exit(0) + }() + + for { + select { + case uevent := <-queue: + if uevent.Env["DEVTYPE"] == "disk" { + time.Sleep(time.Microsecond * 500) + SendUSBBySocket() + continue + } + case err := <-errors: + loger.Error("udev err", zap.Any("err", err)) + } + } + +} diff --git a/route/route.go b/route/route.go index b6dd35a..b7a5cd6 100644 --- a/route/route.go +++ b/route/route.go @@ -196,6 +196,9 @@ func InitRouter() *gin.Engine { //v1DisksGroup.POST("", v1.PostMountDisk) v1DisksGroup.GET("", v1.GetDiskList) + v1DisksGroup.GET("/usb", v1.GetDisksUSBList) + v1DisksGroup.DELETE("/usb", v1.DeleteDiskUSB) + v1DisksGroup.DELETE("", v1.DeleteDisksUmount) // //format storage // v1DiskGroup.POST("/format", v1.PostDiskFormat) @@ -218,6 +221,26 @@ func InitRouter() *gin.Engine { v1StorageGroup.PUT("", v1.PostDiskFormat) v1StorageGroup.DELETE("", v1.PostDiskUmount) + v1StorageGroup.GET("", v1.GetStorageList) + } + v1SambaGroup := v1Group.Group("/samba") + v1SambaGroup.Use() + { + v1ConnectionsGroup := v1SambaGroup.Group("/connections") + v1ConnectionsGroup.Use() + { + v1ConnectionsGroup.GET("", v1.GetSambaConnectionsList) + v1ConnectionsGroup.POST("", v1.PostSambaConnectionsCreate) + v1ConnectionsGroup.DELETE("/:id", v1.DeleteSambaConnections) + } + v1SharesGroup := v1SambaGroup.Group("/shares") + v1SharesGroup.Use() + { + v1SharesGroup.GET("", v1.GetSambaSharesList) + v1SharesGroup.POST("", v1.PostSambaSharesCreate) + v1SharesGroup.DELETE("/:id", v1.DeleteSambaShares) + v1SharesGroup.GET("/status", v1.GetSambaStatus) + } } } return r diff --git a/route/v1/disk.go b/route/v1/disk.go index 9d19a16..f04a0b1 100644 --- a/route/v1/disk.go +++ b/route/v1/disk.go @@ -1,7 +1,6 @@ package v1 import ( - "fmt" "net/http" "reflect" "strconv" @@ -45,19 +44,12 @@ func GetDiskList(c *gin.Context) { 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) } } @@ -87,14 +79,13 @@ func GetDiskList(c *gin.Context) { disk.Size = list[i].Size disk.Path = list[i].Path disk.Model = list[i].Model - + disk.ChildrenNumber = len(list[i].Children) if len(list[i].Children) > 0 && findSystem == 0 { for j := 0; j < len(list[i].Children); j++ { if len(list[i].Children[j].Children) > 0 { for _, v := range list[i].Children[j].Children { if v.MountPoint == "/" { stor := model.Storage{} - stor.Name = "System" stor.MountPoint = v.MountPoint stor.Size = v.FSSize stor.Avail = v.FSAvail @@ -118,7 +109,6 @@ func GetDiskList(c *gin.Context) { } else { if list[i].Children[j].MountPoint == "/" { stor := model.Storage{} - stor.Name = "System" stor.MountPoint = list[i].Children[j].MountPoint stor.Size = list[i].Children[j].FSSize stor.Avail = list[i].Children[j].FSAvail @@ -152,33 +142,31 @@ func GetDiskList(c *gin.Context) { if reflect.DeepEqual(temp, model.SmartctlA{}) { temp.SmartStatus.Passed = true } - if len(list[i].Children) == 1 && len(list[i].Children[0].MountPoint) > 0 { - stor := model.Storage{} - stor.MountPoint = list[i].Children[0].MountPoint - stor.Size = list[i].Children[0].FSSize - stor.Avail = list[i].Children[0].FSAvail - stor.Path = list[i].Children[0].Path - stor.Type = list[i].Children[0].FsType - stor.DriveName = list[i].Name - pathArr := strings.Split(list[i].Children[0].MountPoint, "/") - if len(pathArr) == 3 { - stor.Name = pathArr[2] - } - if t, ok := part[list[i].Children[0].MountPoint]; ok { - stor.CreatedAt = t - } - storage = append(storage, stor) - } else { - //todo 长度有问题 - if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" { - disk.NeedFormat = false - avail = append(avail, disk) - } else { - disk.NeedFormat = true - avail = append(avail, disk) + isAvail := true + for _, v := range list[i].Children { + if v.MountPoint != "" { + stor := model.Storage{} + stor.MountPoint = v.MountPoint + stor.Size = v.FSSize + stor.Avail = v.FSAvail + stor.Path = v.Path + stor.Type = v.FsType + stor.DriveName = list[i].Name + storage = append(storage, stor) + isAvail = false } } + if isAvail { + //if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" { + disk.NeedFormat = false + avail = append(avail, disk) + // } else { + // disk.NeedFormat = true + // avail = append(avail, disk) + // } + } + disk.Temperature = temp.Temperature.Current disk.Health = strconv.FormatBool(temp.SmartStatus.Passed) @@ -193,6 +181,107 @@ func GetDiskList(c *gin.Context) { c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) } +// @Summary disk list +// @Produce application/json +// @Accept application/json +// @Tags disk +// @Security ApiKeyAuth +// @Success 200 {string} string "ok" +// @Router /disk/list [get] +func GetDisksUSBList(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.Label + if temp.Name == "" { + temp.Name = v.Name + } + temp.Size = v.Size + children := []model.USBChildren{} + for _, child := range v.Children { + + if len(child.MountPoint) > 0 { + tempChildren := model.USBChildren{} + tempChildren.MountPoint = child.MountPoint + tempChildren.Size, _ = strconv.ParseUint(child.FSSize, 10, 64) + tempChildren.Avail, _ = strconv.ParseUint(child.FSAvail, 10, 64) + tempChildren.Name = child.Label + avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) + children = append(children, tempChildren) + temp.Avail += avail + } + } + + temp.Children = children + data = append(data, temp) + } + } + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) + +} + +func DeleteDisksUmount(c *gin.Context) { + id := c.GetHeader("user_id") + js := make(map[string]string) + c.ShouldBind(&js) + + path := js["path"] + pwd := js["password"] + + if len(path) == 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().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(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)}) + return + } + + diskInfo := service.MyService.Disk().GetDiskInfo(path) + for _, v := range diskInfo.Children { + service.MyService.Disk().UmountPointAndRemoveDir(v.Path) + //delete data + service.MyService.Disk().DeleteMountPoint(v.Path, v.MountPoint) + } + + service.MyService.Disk().RemoveLSBLKCache() + + //send notify to client + msg := notify.StorageMessage{} + msg.Action = "REMOVED" + msg.Path = path + msg.Volume = "" + 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), Data: path}) +} + +func DeleteDiskUSB(c *gin.Context) { + js := make(map[string]string) + c.ShouldBind(&js) + mountPoint := js["mount_point"] + if file.CheckNotExist(mountPoint) { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) + return + } + service.MyService.Disk().UmountUSB(mountPoint) + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mountPoint}) +} + // @Summary get disk list // @Produce application/json // @Accept application/json @@ -278,10 +367,10 @@ func PostDiskAddPartition(c *gin.Context) { js := make(map[string]interface{}) c.ShouldBind(&js) path := js["path"].(string) - name := js["name"].(string) + //name := js["name"].(string) format := js["format"].(bool) - if len(name) == 0 || len(path) == 0 { + if len(path) == 0 { c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) return } @@ -289,20 +378,17 @@ func PostDiskAddPartition(c *gin.Context) { 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(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)}) - return - } + + //diskInfo := service.MyService.Disk().GetDiskInfo(path) + + // if !file.CheckNotExist("/DATA/" + name) { + // // /mnt/name exist + // 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") { - 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 { + if format { // format := service.MyService.Disk().FormatDisk(path+"1", "ext4") // if len(format) == 0 { // delete(diskMap, path) @@ -312,34 +398,45 @@ func PostDiskAddPartition(c *gin.Context) { service.MyService.Disk().AddPartition(path) } - formatBool := true - for formatBool { - currentDisk = service.MyService.Disk().GetDiskInfo(path) - fmt.Println(currentDisk.Children) - if len(currentDisk.Children) > 0 { - formatBool = false - break - } - time.Sleep(time.Second) - } + // formatBool := true + // for formatBool { + // currentDisk = service.MyService.Disk().GetDiskInfo(path) + // if len(currentDisk.Children) > 0 { + // formatBool = false + // break + // } + // time.Sleep(time.Second) + // } currentDisk = service.MyService.Disk().GetDiskInfo(path) - if len(currentDisk.Children) != 1 { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)}) - return + // if len(currentDisk.Children) != 1 { + // c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)}) + // return + // } + for i := 0; i < len(currentDisk.Children); i++ { + childrenName := currentDisk.Children[i].Label + if len(childrenName) == 0 { + childrenName = "Storage_" + currentDisk.Children[i].Name + } + mountPath := "/DATA/" + childrenName + if !file.CheckNotExist(mountPath) { + ls := service.MyService.System().GetDirPath(mountPath) + if len(ls) > 0 { + // exist + c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)}) + return + } + } + m := model2.SerialDisk{} + m.MountPoint = mountPath + m.Path = currentDisk.Children[i].Path + m.UUID = currentDisk.Children[i].UUID + m.State = 0 + m.CreatedAt = time.Now().Unix() + service.MyService.Disk().SaveMountPoint(m) + //mount dir + service.MyService.Disk().MountDisk(currentDisk.Children[i].Path, mountPath) } - mountPath := "/DATA/" + name - m := model2.SerialDisk{} - m.MountPoint = mountPath - m.Path = currentDisk.Children[0].Path - m.UUID = currentDisk.Children[0].UUID - m.State = 0 - m.CreatedAt = time.Now().Unix() - service.MyService.Disk().SaveMountPoint(m) - - //mount dir - service.MyService.Disk().MountDisk(currentDisk.Children[0].Path, mountPath) - service.MyService.Disk().RemoveLSBLKCache() delete(diskMap, path) @@ -348,7 +445,7 @@ func PostDiskAddPartition(c *gin.Context) { msg := notify.StorageMessage{} msg.Action = "ADDED" msg.Path = currentDisk.Children[0].Path - msg.Volume = mountPath + msg.Volume = "/DATA/" msg.Size = currentDisk.Children[0].Size msg.Type = currentDisk.Children[0].Tran service.MyService.Notify().SendStorageBySocket(msg) diff --git a/route/v1/docker.go b/route/v1/docker.go index 3e15ae1..c04cce8 100644 --- a/route/v1/docker.go +++ b/route/v1/docker.go @@ -209,7 +209,7 @@ func InstallApp(c *gin.Context) { dockerImage = m.Image dockerImageVersion = "latest" } - + m.Image = dockerImage + ":" + dockerImageVersion for _, u := range m.Ports { if u.Protocol == "udp" { @@ -334,11 +334,11 @@ func InstallApp(c *gin.Context) { return } - for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) { + for !service.MyService.Docker().IsExistImage(m.Image) { time.Sleep(time.Second) } - _, err = service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m) + _, err = service.MyService.Docker().DockerContainerCreate(m, "") if err != nil { //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100) notify := notify.Application{} @@ -829,7 +829,6 @@ func UpdateSetting(c *gin.Context) { // c.JSON(http.StatusOK, model.Result{Success: common_err.ERROR_APP_NAME_EXIST, Message: common_err.GetMsg(common_err.ERROR_APP_NAME_EXIST)}) // return // } - service.MyService.Docker().DockerContainerStop(id) portMap, _ := strconv.Atoi(m.PortMap) if !port2.IsPortAvailable(portMap, "tcp") { @@ -874,7 +873,7 @@ func UpdateSetting(c *gin.Context) { service.MyService.Docker().DockerContainerUpdateName(id, id) //service.MyService.Docker().DockerContainerRemove(id, true) - containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m) + containerId, err := service.MyService.Docker().DockerContainerCreate(m, id) if err != nil { service.MyService.Docker().DockerContainerUpdateName(m.ContainerName, id) service.MyService.Docker().DockerContainerStart(id) diff --git a/route/v1/file.go b/route/v1/file.go index e2ca2b2..0b2dbc7 100644 --- a/route/v1/file.go +++ b/route/v1/file.go @@ -1,6 +1,7 @@ package v1 import ( + "fmt" "io" "io/ioutil" "log" @@ -218,6 +219,11 @@ func GetDownloadSingleFile(c *gin.Context) { func DirPath(c *gin.Context) { path := c.DefaultQuery("path", "") info := service.MyService.System().GetDirPath(path) + shares := service.MyService.Shares().GetSharesList() + sharesMap := make(map[string]string) + for _, v := range shares { + sharesMap[v.Path] = fmt.Sprint(v.ID) + } if path == "/DATA/AppData" { list := service.MyService.Docker().DockerContainerList() apps := make(map[string]string, len(list)) @@ -257,7 +263,17 @@ func DirPath(c *gin.Context) { } } } + for i := 0; i < len(info); i++ { + if v, ok := sharesMap[info[i].Path]; ok { + ex := make(map[string]interface{}) + shareEx := make(map[string]string) + shareEx["shared"] = "true" + shareEx["id"] = v + ex["share"] = shareEx + info[i].Extensions = ex + } + } //Hide the files or folders in operation fileQueue := make(map[string]string) if len(service.OpStrArr) > 0 { diff --git a/route/v1/samba.go b/route/v1/samba.go new file mode 100644 index 0000000..5bb3dc2 --- /dev/null +++ b/route/v1/samba.go @@ -0,0 +1,180 @@ +/* + * @Author: LinkLeong link@icewhale.com + * @Date: 2022-07-26 11:08:48 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-05 12:16:39 + * @FilePath: /CasaOS/route/v1/samba.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package v1 + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/IceWhaleTech/CasaOS/model" + "github.com/IceWhaleTech/CasaOS/pkg/samba" + "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" + "github.com/IceWhaleTech/CasaOS/pkg/utils/file" + "github.com/IceWhaleTech/CasaOS/service" + model2 "github.com/IceWhaleTech/CasaOS/service/model" + "github.com/gin-gonic/gin" +) + +// service + +func GetSambaStatus(c *gin.Context) { + status := service.MyService.System().IsServiceRunning("smbd") + + if !status { + c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_NOT_RUNNING, Message: common_err.GetMsg(common_err.SERVICE_NOT_RUNNING)}) + return + } + needInit := true + if file.Exists("/etc/samba/smb.conf") { + str := file.ReadLine(1, "/etc/samba/smb.conf") + if strings.Contains(str, "# Copyright (c) 2021-2022 CasaOS Inc. All rights reserved.") { + needInit = false + } + } + data := make(map[string]string, 1) + data["need_init"] = fmt.Sprintf("%v", needInit) + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) +} + +func GetSambaSharesList(c *gin.Context) { + shares := service.MyService.Shares().GetSharesList() + shareList := []model.Shares{} + for _, v := range shares { + shareList = append(shareList, model.Shares{ + Anonymous: v.Anonymous, + Path: v.Path, + ID: v.ID, + }) + } + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shareList}) +} + +func PostSambaSharesCreate(c *gin.Context) { + shares := []model.Shares{} + c.ShouldBindJSON(&shares) + for _, v := range shares { + if v.Path == "" { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) + return + } + if !file.Exists(v.Path) { + c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) + return + } + if len(service.MyService.Shares().GetSharesByPath(v.Path)) > 0 { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_ALREADY_EXISTS)}) + return + } + if len(service.MyService.Shares().GetSharesByPath(filepath.Base(v.Path))) > 0 { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.SHARE_NAME_ALREADY_EXISTS, Message: common_err.GetMsg(common_err.SHARE_NAME_ALREADY_EXISTS)}) + return + } + } + for _, v := range shares { + shareDBModel := model2.SharesDBModel{} + shareDBModel.Anonymous = true + shareDBModel.Path = v.Path + shareDBModel.Name = filepath.Base(v.Path) + service.MyService.Shares().CreateShare(shareDBModel) + } + + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: shares}) +} +func DeleteSambaShares(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INSUFFICIENT_PERMISSIONS, Message: common_err.GetMsg(common_err.INSUFFICIENT_PERMISSIONS)}) + return + } + service.MyService.Shares().DeleteShare(id) + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id}) +} + +//client + +func GetSambaConnectionsList(c *gin.Context) { + connections := service.MyService.Connections().GetConnectionsList() + connectionList := []model.Connections{} + for _, v := range connections { + connectionList = append(connectionList, model.Connections{ + ID: v.ID, + Username: v.Username, + Port: v.Port, + Host: v.Host, + MountPoint: v.MountPoint, + }) + } + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connectionList}) +} + +func PostSambaConnectionsCreate(c *gin.Context) { + connection := model.Connections{} + c.ShouldBindJSON(&connection) + if connection.Port == "" { + connection.Port = "445" + } + if connection.Username == "" || connection.Host == "" { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) + return + } + // check is exists + + connections := service.MyService.Connections().GetConnectionByHost(connection.Host) + if len(connections) > 0 { + c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.Record_ALREADY_EXIST, Message: common_err.GetMsg(common_err.Record_ALREADY_EXIST), Data: common_err.GetMsg(common_err.Record_ALREADY_EXIST)}) + return + } + // check connect is ok + directories, err := samba.GetSambaSharesList(connection.Host, connection.Port, connection.Username, connection.Password) + 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 + } + + connectionDBModel := model2.ConnectionsDBModel{} + connectionDBModel.Username = connection.Username + connectionDBModel.Password = connection.Password + connectionDBModel.Host = connection.Host + connectionDBModel.Port = connection.Port + connectionDBModel.Directories = strings.Join(directories, ",") + baseHostPath := "/mnt/" + connection.Host + connectionDBModel.MountPoint = baseHostPath + connection.MountPoint = baseHostPath + file.IsNotExistMkDir(baseHostPath) + for _, v := range directories { + mountPoint := baseHostPath + "/" + v + file.IsNotExistMkDir(mountPoint) + service.MyService.Connections().MountSmaba(connectionDBModel.Username, connectionDBModel.Host, v, connectionDBModel.Port, mountPoint, connectionDBModel.Password) + } + + service.MyService.Connections().CreateConnection(&connectionDBModel) + + connection.ID = connectionDBModel.ID + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: connection}) +} + +func DeleteSambaConnections(c *gin.Context) { + id := c.Param("id") + connection := service.MyService.Connections().GetConnectionByID(id) + if connection.Username == "" { + c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.Record_NOT_EXIST, Message: common_err.GetMsg(common_err.Record_NOT_EXIST)}) + return + } + mountPointList := service.MyService.System().GetDirPath(connection.MountPoint) + for _, v := range mountPointList { + service.MyService.Connections().UnmountSmaba(v.Path) + } + os.RemoveAll(connection.MountPoint) + service.MyService.Connections().DeleteConnection(id) + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: id}) +} diff --git a/route/v1/samba_test.go b/route/v1/samba_test.go new file mode 100644 index 0000000..455b973 --- /dev/null +++ b/route/v1/samba_test.go @@ -0,0 +1,73 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-08-02 15:10:56 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-02 16:58:42 + * @FilePath: /CasaOS/route/v1/samba_test.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package v1 + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder { + req, _ := http.NewRequest(method, path, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +// func TestHelloWorld(t *testing.T) { +// // Build our expected body +// body := gin.H{ +// "hello": "world", +// } +// // Grab our router +// router := "SetupRouter()" +// // Perform a GET request with that handler. +// w := performRequest(router, "GET", "/") +// // Assert we encoded correctly, +// // the request gives a 200 +// assert.Equal(t, http.StatusOK, w.Code) +// // Convert the JSON response to a map +// var response map[string]string +// err := json.Unmarshal([]byte(w.Body.String()), &response) +// // Grab the value & whether or not it exists +// value, exists := response["hello"] +// // Make some assertions on the correctness of the response. +// assert.Nil(t, err) +// assert.True(t, exists) +// assert.Equal(t, body["hello"], value) +// } + +func TestGetSambaSharesList(t *testing.T) { + gin.SetMode(gin.TestMode) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + executeWithContext := func() *httptest.ResponseRecorder { + response := httptest.NewRecorder() + con, ginEngine := gin.CreateTestContext(response) + + requestUrl := "/v1/samba/shares" + httpRequest, _ := http.NewRequest("GET", requestUrl, nil) + GetSambaSharesList(con) + ginEngine.ServeHTTP(response, httpRequest) + return response + } + + t.Run("Happy", func(t *testing.T) { + res := executeWithContext() + assert.Equal(t, http.StatusOK, res.Code) + }) + +} diff --git a/route/v1/storage.go b/route/v1/storage.go index ca02ed6..b45e22e 100644 --- a/route/v1/storage.go +++ b/route/v1/storage.go @@ -2,7 +2,7 @@ * @Author: LinkLeong link@icewhale.com * @Date: 2022-07-11 16:02:29 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-11 16:02:55 + * @LastEditTime: 2022-08-11 14:20:02 * @FilePath: /CasaOS/route/v1/storage.go * @Description: * @Website: https://www.casaos.io @@ -10,8 +10,95 @@ */ package v1 -import "github.com/gin-gonic/gin" +import ( + "reflect" + "strconv" + + "github.com/IceWhaleTech/CasaOS/model" + "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" + "github.com/IceWhaleTech/CasaOS/service" + "github.com/gin-gonic/gin" +) func GetStorageList(c *gin.Context) { + system := c.Query("system") + storages := []model.Storages{} + disks := service.MyService.Disk().LSBLK(false) + diskNumber := 1 + children := 1 + findSystem := 0 + for _, d := range disks { + if d.Tran != "usb" { + tempSystemDisk := false + children = 1 + tempDisk := model.Storages{ + DiskName: d.Model, + Path: d.Path, + Size: d.Size, + } + storageArr := []model.Storage{} + temp := service.MyService.Disk().SmartCTL(d.Path) + if reflect.DeepEqual(temp, model.SmartctlA{}) { + temp.SmartStatus.Passed = true + } + for _, v := range d.Children { + if v.MountPoint != "" { + if findSystem == 0 { + if v.MountPoint == "/" { + tempDisk.DiskName = "System" + findSystem = 1 + tempSystemDisk = true + } + if len(v.Children) > 0 { + for _, c := range v.Children { + if c.MountPoint == "/" { + tempDisk.DiskName = "System" + findSystem = 1 + tempSystemDisk = true + break + } + } + } + } + + stor := model.Storage{} + stor.MountPoint = v.MountPoint + stor.Size = v.FSSize + stor.Avail = v.FSAvail + stor.Path = v.Path + stor.Type = v.FsType + stor.DriveName = v.Name + if len(v.Label) == 0 { + stor.Label = "Storage" + strconv.Itoa(diskNumber) + "_" + strconv.Itoa(children) + children += 1 + } else { + stor.Label = v.Label + } + storageArr = append(storageArr, stor) + } + } + + if len(storageArr) > 0 { + if tempSystemDisk && len(system) > 0 { + tempStorageArr := []model.Storage{} + for i := 0; i < len(storageArr); i++ { + if storageArr[i].MountPoint != "/boot/efi" && storageArr[i].Type != "swap" { + tempStorageArr = append(tempStorageArr, storageArr[i]) + } + } + tempDisk.Children = tempStorageArr + storages = append(storages, tempDisk) + diskNumber += 1 + } else if !tempSystemDisk { + tempDisk.Children = storageArr + storages = append(storages, tempDisk) + diskNumber += 1 + } + + } + } + } + + c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: storages}) } diff --git a/route/v1/system.go b/route/v1/system.go index 42d7d32..e6d8029 100644 --- a/route/v1/system.go +++ b/route/v1/system.go @@ -174,7 +174,7 @@ func PostKillCasaOS(c *gin.Context) { func PutSystemUSBAutoMount(c *gin.Context) { js := make(map[string]string) c.ShouldBind(&js) - status := js["status"] + status := js["state"] if status == "on" { service.MyService.System().UpdateUSBAutoMount("True") service.MyService.System().ExecUSBAutoMountShell("True") @@ -182,7 +182,31 @@ func PutSystemUSBAutoMount(c *gin.Context) { service.MyService.System().UpdateUSBAutoMount("False") service.MyService.System().ExecUSBAutoMountShell("False") } + go func() { + usbList := service.MyService.Disk().LSBLK(false) + usb := []model.DriveUSB{} + for _, v := range usbList { + if v.Tran == "usb" { + isMount := false + temp := model.DriveUSB{} + temp.Model = v.Model + temp.Name = v.Name + temp.Size = v.Size + for _, child := range v.Children { + if len(child.MountPoint) > 0 { + isMount = true + avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) + temp.Avail += avail + } + } + if isMount { + usb = append(usb, temp) + } + } + } + service.MyService.Notify().SendUSBInfoBySocket(usb) + }() c.JSON(common_err.SUCCESS, model.Result{ Success: common_err.SUCCESS, @@ -202,7 +226,31 @@ func GetSystemUSBAutoMount(c *gin.Context) { if config.ServerInfo.USBAutoMount == "False" { state = "False" } + go func() { + usbList := service.MyService.Disk().LSBLK(false) + usb := []model.DriveUSB{} + for _, v := range usbList { + if v.Tran == "usb" { + isMount := false + temp := model.DriveUSB{} + temp.Model = v.Model + temp.Name = v.Name + temp.Size = v.Size + for _, child := range v.Children { + if len(child.MountPoint) > 0 { + isMount = true + avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) + temp.Avail += avail + } + } + if isMount { + usb = append(usb, temp) + } + } + } + service.MyService.Notify().SendUSBInfoBySocket(usb) + }() c.JSON(common_err.SUCCESS, model.Result{ Success: common_err.SUCCESS, @@ -354,21 +402,13 @@ func GetSystemUtilization(c *gin.Context) { 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 - used, _ := strconv.ParseUint(child.FSUsed, 10, 64) - temp.Used += used - } else { - mountTemp = false } } - temp.Mount = mountTemp usb = append(usb, temp) } } diff --git a/service/connections.go b/service/connections.go new file mode 100644 index 0000000..f9fe135 --- /dev/null +++ b/service/connections.go @@ -0,0 +1,69 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-26 18:13:22 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-04 20:10:31 + * @FilePath: /CasaOS/service/connections.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package service + +import ( + "github.com/IceWhaleTech/CasaOS/pkg/config" + command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" + "github.com/IceWhaleTech/CasaOS/service/model" + model2 "github.com/IceWhaleTech/CasaOS/service/model" + "gorm.io/gorm" +) + +type ConnectionsService interface { + GetConnectionsList() (connections []model2.ConnectionsDBModel) + GetConnectionByHost(host string) (connections []model2.ConnectionsDBModel) + GetConnectionByID(id string) (connections model2.ConnectionsDBModel) + CreateConnection(connection *model2.ConnectionsDBModel) + DeleteConnection(id string) + UpdateConnection(connection *model2.ConnectionsDBModel) + MountSmaba(username, host, directory, port, mountPoint, password string) string + UnmountSmaba(mountPoint string) string +} + +type connectionsStruct struct { + db *gorm.DB +} + +func (s *connectionsStruct) GetConnectionByHost(host string) (connections []model2.ConnectionsDBModel) { + s.db.Select("username,host,status,id").Where("host = ?", host).Find(&connections) + return +} +func (s *connectionsStruct) GetConnectionByID(id string) (connections model2.ConnectionsDBModel) { + s.db.Select("username,password,host,status,id,directories,mount_point,port").Where("id = ?", id).First(&connections) + return +} +func (s *connectionsStruct) GetConnectionsList() (connections []model2.ConnectionsDBModel) { + s.db.Select("username,host,port,status,id,mount_point").Find(&connections) + return +} +func (s *connectionsStruct) CreateConnection(connection *model2.ConnectionsDBModel) { + s.db.Create(connection) +} +func (s *connectionsStruct) UpdateConnection(connection *model2.ConnectionsDBModel) { + s.db.Save(connection) +} +func (s *connectionsStruct) DeleteConnection(id string) { + s.db.Where("id= ?", id).Delete(&model.ConnectionsDBModel{}) +} + +func (s *connectionsStruct) MountSmaba(username, host, directory, port, mountPoint, password string) string { + str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;MountCIFS " + username + " " + host + " " + directory + " " + port + " " + mountPoint + " " + password) + return str +} +func (s *connectionsStruct) UnmountSmaba(mountPoint string) string { + str := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;UMountPorintAndRemoveDir " + mountPoint) + return str +} + +func NewConnectionsService(db *gorm.DB) ConnectionsService { + return &connectionsStruct{db: db} +} diff --git a/service/disk.go b/service/disk.go index fb026bc..dfe8219 100644 --- a/service/disk.go +++ b/service/disk.go @@ -36,6 +36,7 @@ type DiskService interface { DeleteMount(id string) UpdateMountPoint(m model2.SerialDisk) RemoveLSBLKCache() + UmountUSB(path string) } type diskService struct { db *gorm.DB @@ -45,6 +46,10 @@ func (d *diskService) RemoveLSBLKCache() { key := "system_lsblk" Cache.Delete(key) } +func (d *diskService) UmountUSB(path string) { + r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;UDEVILUmount " + path) + fmt.Println(r) +} func (d *diskService) SmartCTL(path string) model.SmartctlA { key := "system_smart_" + path @@ -243,8 +248,9 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel { } func (d *diskService) MountDisk(path, volume string) { + //fmt.Println("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume) r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume) - fmt.Print(r) + fmt.Println(r) } func (d *diskService) SaveMountPoint(m model2.SerialDisk) { diff --git a/service/docker.go b/service/docker.go index 4501345..45bc4a8 100644 --- a/service/docker.go +++ b/service/docker.go @@ -45,7 +45,7 @@ import ( type DockerService interface { DockerPullImage(imageName string, icon, name string) error IsExistImage(imageName string) bool - DockerContainerCreate(imageName string, m model.CustomizationPostData) (containerId string, err error) + DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) DockerContainerStart(name string) error DockerContainerStats(name string) (string, error) @@ -376,7 +376,7 @@ func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (c //param mapPort 容器主端口映射到外部的端口 //param tcp 容器其他tcp端口 //param udp 容器其他udp端口 -func (ds *dockerService) DockerContainerCreate(imageName string, m model.CustomizationPostData) (containerId string, err error) { +func (ds *dockerService) DockerContainerCreate(m model.CustomizationPostData, id string) (containerId string, err error) { if len(m.NetworkModel) == 0 { m.NetworkModel = "bridge" } @@ -385,6 +385,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, m model.Customi if err != nil { return "", err } + defer cli.Close() ports := make(nat.PortSet) portMaps := make(nat.PortMap) @@ -523,15 +524,26 @@ func (ds *dockerService) DockerContainerCreate(imageName string, m model.Customi if len(m.HostName) == 0 { m.HostName = m.Label } - config := &container.Config{ - Image: imageName, - Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin, "casaos": "casaos"}, - Env: envArr, - // Healthcheck: health, - Hostname: m.HostName, - Cmd: m.Cmd, + + info, err := cli.ContainerInspect(context.Background(), id) + hostConfig := &container.HostConfig{} + config := &container.Config{} + config.Labels = map[string]string{} + if err == nil { + // info.HostConfig = &container.HostConfig{} + // info.Config = &container.Config{} + // info.NetworkSettings = &types.NetworkSettings{} + hostConfig = info.HostConfig + config = info.Config } + config.Cmd = m.Cmd + config.Image = m.Image + config.Env = envArr + config.Hostname = m.HostName + config.ExposedPorts = ports + config.Labels["origin"] = m.Origin + config.Labels["casaos"] = "casaos" config.Labels["web"] = m.PortMap config.Labels["icon"] = m.Icon config.Labels["desc"] = m.Description @@ -541,12 +553,19 @@ func (ds *dockerService) DockerContainerCreate(imageName string, m model.Customi 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} + //container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name) + + hostConfig.Mounts = volumes + hostConfig.Privileged = m.Privileged + hostConfig.CapAdd = m.CapAdd + hostConfig.NetworkMode = container.NetworkMode(m.NetworkModel) + hostConfig.RestartPolicy = rp + hostConfig.Resources = res + //hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: , Privileged: m.Privileged, CapAdd: m.CapAdd} //if net != "host" { - config.ExposedPorts = ports + hostConfig.PortBindings = portMaps //} - containerDb, err := cli.ContainerCreate(context.Background(), config, hostConfig, diff --git a/service/model/o_connections.go b/service/model/o_connections.go new file mode 100644 index 0000000..45b1244 --- /dev/null +++ b/service/model/o_connections.go @@ -0,0 +1,28 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-26 17:17:57 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-01 17:08:08 + * @FilePath: /CasaOS/service/model/o_connections.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package model + +type ConnectionsDBModel struct { + ID uint `gorm:"column:id;primary_key" json:"id"` + Updated int64 `gorm:"autoUpdateTime"` + Created int64 `gorm:"autoCreateTime"` + Username string `json:"username"` + Password string `json:"password"` + Host string `json:"host"` + Port string `json:"port"` + Status string `json:"status"` + Directories string `json:"directories"` // string array + MountPoint string `json:"mount_point"` //parent directory of mount point +} + +func (p *ConnectionsDBModel) TableName() string { + return "o_connections" +} diff --git a/service/model/o_shares.go b/service/model/o_shares.go new file mode 100644 index 0000000..a887522 --- /dev/null +++ b/service/model/o_shares.go @@ -0,0 +1,24 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-26 11:17:17 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-07-27 15:25:07 + * @FilePath: /CasaOS/service/model/o_shares.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package model + +type SharesDBModel struct { + ID uint `gorm:"column:id;primary_key" json:"id"` + Anonymous bool `json:"anonymous"` + Path string `json:"path"` + Name string `json:"name"` + Updated int64 `gorm:"autoUpdateTime"` + Created int64 `gorm:"autoCreateTime"` +} + +func (p *SharesDBModel) TableName() string { + return "o_shares" +} diff --git a/service/service.go b/service/service.go index 2f348fc..9eac558 100644 --- a/service/service.go +++ b/service/service.go @@ -2,7 +2,7 @@ * @Author: LinkLeong link@icewhale.com * @Date: 2022-07-12 09:48:56 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-15 10:58:54 + * @LastEditTime: 2022-07-27 10:28:48 * @FilePath: /CasaOS/service/service.go * @Description: * @Website: https://www.casaos.io @@ -33,31 +33,44 @@ type Repository interface { Notify() NotifyServer Rely() RelyService System() SystemService + Shares() SharesService + Connections() ConnectionsService } func NewService(db *gorm.DB) Repository { return &store{ - app: NewAppService(db), - user: NewUserService(db), - docker: NewDockerService(), - casa: NewCasaService(), - disk: NewDiskService(db), - notify: NewNotifyService(db), - rely: NewRelyService(db), - system: NewSystemService(), + app: NewAppService(db), + user: NewUserService(db), + docker: NewDockerService(), + casa: NewCasaService(), + disk: NewDiskService(db), + notify: NewNotifyService(db), + rely: NewRelyService(db), + system: NewSystemService(), + shares: NewSharesService(db), + connections: NewConnectionsService(db), } } type store struct { - db *gorm.DB - app AppService - user UserService - docker DockerService - casa CasaService - disk DiskService - notify NotifyServer - rely RelyService - system SystemService + db *gorm.DB + app AppService + user UserService + docker DockerService + casa CasaService + disk DiskService + notify NotifyServer + rely RelyService + system SystemService + shares SharesService + connections ConnectionsService +} + +func (s *store) Connections() ConnectionsService { + return s.connections +} +func (s *store) Shares() SharesService { + return s.shares } func (c *store) Rely() RelyService { diff --git a/service/shares.go b/service/shares.go new file mode 100644 index 0000000..01ea7b0 --- /dev/null +++ b/service/shares.go @@ -0,0 +1,151 @@ +/* + * @Author: LinkLeong link@icewhale.org + * @Date: 2022-07-26 11:21:14 + * @LastEditors: LinkLeong + * @LastEditTime: 2022-08-11 14:04:00 + * @FilePath: /CasaOS/service/shares.go + * @Description: + * @Website: https://www.casaos.io + * Copyright (c) 2022 by icewhale, All Rights Reserved. + */ +package service + +import ( + "path/filepath" + "strings" + + "github.com/IceWhaleTech/CasaOS/pkg/config" + command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" + "github.com/IceWhaleTech/CasaOS/pkg/utils/file" + "github.com/IceWhaleTech/CasaOS/service/model" + model2 "github.com/IceWhaleTech/CasaOS/service/model" + "gorm.io/gorm" +) + +type SharesService interface { + GetSharesList() (shares []model2.SharesDBModel) + GetSharesByPath(path string) (shares []model2.SharesDBModel) + GetSharesByName(name string) (shares []model2.SharesDBModel) + CreateShare(share model2.SharesDBModel) + DeleteShare(id string) + UpdateConfigFile() + InitSambaConfig() +} + +type sharesStruct struct { + db *gorm.DB +} + +func (s *sharesStruct) GetSharesByName(name string) (shares []model2.SharesDBModel) { + s.db.Select("anonymous,path,id").Where("name = ?", name).Find(&shares) + + return +} +func (s *sharesStruct) GetSharesByPath(path string) (shares []model2.SharesDBModel) { + s.db.Select("anonymous,path,id").Where("path = ?", path).Find(&shares) + return +} +func (s *sharesStruct) GetSharesList() (shares []model2.SharesDBModel) { + s.db.Select("anonymous,path,id").Find(&shares) + return +} +func (s *sharesStruct) CreateShare(share model2.SharesDBModel) { + s.db.Create(&share) + s.InitSambaConfig() + s.UpdateConfigFile() +} +func (s *sharesStruct) DeleteShare(id string) { + s.db.Where("id= ?", id).Delete(&model.SharesDBModel{}) + s.UpdateConfigFile() +} + +func (s *sharesStruct) UpdateConfigFile() { + shares := []model2.SharesDBModel{} + s.db.Select("anonymous,path").Find(&shares) + //generated config file + var configStr = "" + for _, share := range shares { + dirName := filepath.Base(share.Path) + configStr += ` +[` + dirName + `] +comment = CasaOS share ` + dirName + ` +public = Yes +path = ` + share.Path + ` +browseable = Yes +read only = No +guest ok = Yes +create mask = 0777 +directory mask = 0777 + +` + } + //write config file + file.WriteToPath([]byte(configStr), "/etc/samba", "smb.casa.conf") + //restart samba + command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;RestartSMBD") + +} +func (s *sharesStruct) InitSambaConfig() { + if file.Exists("/etc/samba/smb.conf") { + str := file.ReadLine(1, "/etc/samba/smb.conf") + if strings.Contains(str, "# Copyright (c) 2021-2022 CasaOS Inc. All rights reserved.") { + return + } + file.MoveFile("/etc/samba/smb.conf", "/etc/samba/smb.conf.bak") + var smbConf = "" + smbConf += `# Copyright (c) 2021-2022 CasaOS Inc. All rights reserved. +# +# +# ______ _______ +# ( __ \ ( ___ ) +# | ( \ ) | ( ) | +# | | ) | | | | | +# | | | | | | | | +# | | ) | | | | | +# | (__/ ) | (___) | +# (______/ (_______) +# +# _ _______ _________ +# ( ( /| ( ___ ) \__ __/ +# | \ ( | | ( ) | ) ( +# | \ | | | | | | | | +# | (\ \) | | | | | | | +# | | \ | | | | | | | +# | ) \ | | (___) | | | +# |/ )_) (_______) )_( +# +# _______ _______ ______ _________ _______ +# ( ) ( ___ ) ( __ \ \__ __/ ( ____ \ |\ /| +# | () () | | ( ) | | ( \ ) ) ( | ( \/ ( \ / ) +# | || || | | | | | | | ) | | | | (__ \ (_) / +# | |(_)| | | | | | | | | | | | | __) \ / +# | | | | | | | | | | ) | | | | ( ) ( +# | ) ( | | (___) | | (__/ ) ___) (___ | ) | | +# |/ \| (_______) (______/ \_______/ |/ \_/ +# +# +# IMPORTANT: CasaOS will not provide technical support for any issues +# caused by unauthorized modification to the configuration. + +[global] +## fruit settings + min protocol = SMB2 + ea support = yes +## vfs objects = fruit streams_xattr + fruit:metadata = stream + fruit:model = Macmini + fruit:veto_appledouble = no + fruit:posix_rename = yes + fruit:zero_file_id = yes + fruit:wipe_intentionally_left_blank_rfork = yes + fruit:delete_empty_adfiles = yes + map to guest = bad user + include=/etc/samba/smb.casa.conf` + file.WriteToPath([]byte(smbConf), "/etc/samba", "smb.conf") + } + +} + +func NewSharesService(db *gorm.DB) SharesService { + return &sharesStruct{db: db} +} diff --git a/service/system.go b/service/system.go index 95ce9aa..1bb622f 100644 --- a/service/system.go +++ b/service/system.go @@ -49,6 +49,7 @@ type SystemService interface { CreateFile(path string) (int, error) RenameFile(oldF, newF string) (int, error) MkdirAll(path string) (int, error) + IsServiceRunning(name string) bool } type systemService struct { } @@ -232,9 +233,9 @@ func (s *systemService) GetTimeZone() string { func (s *systemService) ExecUSBAutoMountShell(state string) { if state == "False" { - command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Remove_File") + command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Stop_Auto") } else { - command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Move_File") + command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;USB_Start_Auto") } } @@ -287,6 +288,12 @@ func GetDeviceAllIP() []string { } return address } + +func (s *systemService) IsServiceRunning(name string) bool { + status := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;CheckServiceStatus smbd") + return strings.TrimSpace(status) == "running" + +} func NewSystemService() SystemService { return &systemService{} } diff --git a/shell/helper.sh b/shell/helper.sh index 8bd81bf..a13b846 100644 --- a/shell/helper.sh +++ b/shell/helper.sh @@ -330,17 +330,17 @@ TarFolder() { du -sh /DATA } -USB_Move_File() { +USB_Start_Auto() { ((EUID)) && sudo_cmd="sudo" - $sudo_cmd cp -rf /casaOS/server/shell/11-usb-mount.rules /etc/udev/rules.d/ - $sudo_cmd chmod +x /casaOS/server/shell/usb-mount.sh - $sudo_cmd cp -rf /casaOS/server/shell/usb-mount@.service /etc/systemd/system/ + $sudo_cmd systemctl enable devmon@devmon + $sudo_cmd systemctl start devmon@devmon } -USB_Remove_File() { +USB_Stop_Auto() { ((EUID)) && sudo_cmd="sudo" - $sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules - $sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service + $sudo_cmd systemctl stop devmon@devmon + $sudo_cmd systemctl disable devmon@devmon + $sudo_cmd udevil clean } GetDeviceTree(){ @@ -363,4 +363,27 @@ AddSmabaUser(){ $2 $2 EOF -} \ No newline at end of file +} + +# $1:username $2:host $3:share $4:port $5:mountpoint $6:password +MountCIFS(){ + $sudo_cmd mount -t cifs -o username=$1,password=$6,port=$4 //$2/$3 $5 +} + +# $1:service name +CheckServiceStatus(){ + rs="`systemctl status $1 |grep -E 'Active|PID'`" +#echo "$rs" + run="`echo "$rs" |grep -B 2 'running'`" + fai="`echo "$rs" |grep -E -B 2 'failed|inactive|dead'`" + if [ "$run" == "" ] + then + echo "failed" + else + echo "running" + fi +} +UDEVILUmount(){ + $sudo_cmd udevil umount -f $1 +} + diff --git a/types/system.go b/types/system.go index 9a3d4e8..92b4c4c 100644 --- a/types/system.go +++ b/types/system.go @@ -2,7 +2,7 @@ * @Author: LinkLeong link@icewhale.com * @Date: 2022-02-17 18:53:22 * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-18 18:47:15 + * @LastEditTime: 2022-08-10 13:50:57 * @FilePath: /CasaOS/types/system.go * @Description: * @Website: https://www.casaos.io @@ -10,6 +10,6 @@ */ package types -const CURRENTVERSION = "0.3.4" +const CURRENTVERSION = "0.3.5" -const BODY = "" +const BODY = " " diff --git a/web/index.html b/web/index.html index bcede30..bb2b479 100644 --- a/web/index.html +++ b/web/index.html @@ -20,7 +20,7 @@ CasaOS - +