Compare commits

..

79 Commits

Author SHA1 Message Date
link
63c6c2cebb Merge pull request #111 from IceWhaleTech/dev
Delete CasaOS-linux-amd64
2022-02-17 19:22:14 +08:00
link
6cba025679 Delete CasaOS-linux-amd64 2022-02-17 19:21:19 +08:00
link
d25b93c972 Merge pull request #110 from IceWhaleTech/dev
Dev
2022-02-17 18:53:54 +08:00
link
b14861703c Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-02-17 18:53:29 +08:00
link
32604225ce update ui 2022-02-17 18:52:14 +08:00
link
f623b29c38 Merge pull request #109 from IceWhaleTech/dev
Dev
2022-02-17 18:47:44 +08:00
link
94ae6ee8ec Merge branch 'main' into dev 2022-02-17 18:47:36 +08:00
link
5115bf72e1 update desc 2022-02-17 18:44:51 +08:00
link
e1a928cd78 Fixed issues 2022-02-17 18:43:25 +08:00
link
3977519c43 Update assist.sh 2022-01-30 11:21:24 +08:00
link
2f87834ac9 Merge pull request #93 from IceWhaleTech/dev
Update route.go
2022-01-28 16:25:01 +08:00
link
53335012d8 Update route.go 2022-01-28 16:24:28 +08:00
link
9d6302f7e3 Merge pull request #92 from IceWhaleTech/dev
Update UI
2022-01-28 16:14:59 +08:00
link
20950e2a60 Update UI 2022-01-28 16:14:35 +08:00
link
0e0e507f8f Merge pull request #91 from IceWhaleTech/dev
update ui
2022-01-28 15:35:15 +08:00
link
46e14617b6 update ui 2022-01-28 15:34:32 +08:00
link
903c73fafb Merge pull request #90 from IceWhaleTech/dev
update web
2022-01-28 14:33:40 +08:00
link
42a56df4a5 update web 2022-01-28 14:32:49 +08:00
link
493dc5c032 Merge pull request #89 from IceWhaleTech/dev
Compatible with more types of disks
2022-01-28 14:06:58 +08:00
link
9a73bc2a18 Compatible with more types of disks
Add usb display
2022-01-28 14:06:27 +08:00
link
55a9acd9f6 Merge pull request #85 from IceWhaleTech/dev
Apply multilingual support
2022-01-26 18:51:14 +08:00
link
d060968b7a Apply multilingual support 2022-01-26 18:50:34 +08:00
link
88a7f53130 Merge pull request #82 from IceWhaleTech/dev
Dev
2022-01-26 11:33:33 +08:00
link
26e5b18a5d Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-01-26 11:33:02 +08:00
link
011ace96f6 update ui 2022-01-26 11:32:57 +08:00
link
5c00655d14 Merge pull request #81 from IceWhaleTech/dev
Dev
2022-01-26 10:46:50 +08:00
link
eb36c262db Merge branch 'main' into dev 2022-01-26 10:46:43 +08:00
link
29d1861545 Merge branch 'main' into dev 2022-01-26 10:45:11 +08:00
link
3c9b410693 update dependency 2022-01-26 10:44:55 +08:00
link
4c3b41433b Update assist.sh 2022-01-24 22:06:31 +08:00
link
1fd13668c0 Merge pull request #78 from IceWhaleTech/dev
Dev
2022-01-24 17:22:48 +08:00
link
d1ab7261a6 Update usb-mount.sh 2022-01-24 17:21:43 +08:00
link
0fc65bcb3a update mount path 2022-01-24 17:08:28 +08:00
link
f1ce8bfd99 Merge pull request #77 from IceWhaleTech/dev
update disk
2022-01-24 11:19:47 +08:00
link
3f472f1864 update disk 2022-01-24 11:19:04 +08:00
link
229d94cae7 Merge pull request #74 from IceWhaleTech/dev
Fixed Storage Panel
2022-01-21 17:50:44 +08:00
link
c28e1bbf93 Fixed Storage Panel 2022-01-21 17:50:12 +08:00
link
a840029000 Merge pull request #73 from IceWhaleTech/dev
update UI
2022-01-20 18:45:54 +08:00
link
aad2646cf2 Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-01-20 18:45:17 +08:00
link
ca1f8ad73e Update UI 2022-01-20 18:44:55 +08:00
link
dea02763a2 Update UI 2022-01-20 18:44:40 +08:00
link
ea67385a64 Merge pull request #72 from IceWhaleTech/dev
Storage Manager
2022-01-20 18:41:56 +08:00
link
fa2daa2767 Merge branch 'main' into dev 2022-01-20 18:41:49 +08:00
link
fcb906aa85 Storage Manager
Fix the app store classification problem
Fix the application market classification problem
2022-01-20 18:38:59 +08:00
老竭力
489a617126 Update casa.yml 2022-01-04 16:22:38 +08:00
老竭力
601e7ce10b Update casa.yml 2022-01-04 14:51:09 +08:00
老竭力
4a6fc9a945 Update system.go 2022-01-04 14:47:46 +08:00
老竭力
b377af1d24 Update casa.yml 2021-12-30 19:17:11 +08:00
老竭力
3fc00f8da7 Update casa.yml 2021-12-30 19:13:40 +08:00
老竭力
6e39fe5f8c Update casa.yml 2021-12-30 19:04:37 +08:00
老竭力
20c240a123 Update casa.yml 2021-12-30 19:00:11 +08:00
老竭力
3ea9fc0de0 Update casa.yml 2021-12-30 18:52:37 +08:00
老竭力
b80b08ef07 Update casa.yml 2021-12-30 18:50:45 +08:00
老竭力
505af8d101 Update casa.yml 2021-12-30 18:46:17 +08:00
老竭力
ae35a6d291 Update casa.yml 2021-12-30 18:44:07 +08:00
John Guan
2b95c07a47 Update casa.yml 2021-12-30 18:16:19 +08:00
John Guan
27a011e715 Update casa.yml 2021-12-30 18:01:01 +08:00
link
476831a12f Merge pull request #65 from IceWhaleTech/dev
update action system
2021-12-30 16:59:05 +08:00
link
9675eff69e update action system 2021-12-30 16:58:24 +08:00
link
85a044246e Merge pull request #64 from IceWhaleTech/dev
update action system
2021-12-30 16:53:32 +08:00
link
5c41fbcf3d update action system 2021-12-30 16:52:58 +08:00
link
6baab7a525 Merge pull request #63 from IceWhaleTech/dev
update action system
2021-12-30 16:42:39 +08:00
link
ab3b5a9077 update action system 2021-12-30 16:41:16 +08:00
link
5811c271b2 Merge pull request #62 from IceWhaleTech/dev
update web
2021-12-30 16:20:50 +08:00
link
cf5387346d update web 2021-12-30 16:20:30 +08:00
link
8df63c6c5c Merge pull request #60 from IceWhaleTech/dev
New App Store
2021-12-29 16:42:56 +08:00
link
1d17d27c96 New App Store 2021-12-29 16:42:20 +08:00
John Guan
bdcbae69a5 Update README.md 2021-12-14 11:41:42 +08:00
John Guan
cdbc3437be Update README.md 2021-12-14 10:40:17 +08:00
link
8940b520e0 Merge pull request #53 from IceWhaleTech/dev
update ui
2021-12-11 15:44:55 +08:00
link
1d62fbd670 update ui 2021-12-11 15:44:17 +08:00
link
a0b56d809e Merge pull request #52 from IceWhaleTech/dev
update cpu changes when the application is removed
2021-12-10 18:08:49 +08:00
link
f1f6d33e26 update cpu changes when the application is removed 2021-12-10 18:08:02 +08:00
link
f292edd2ba Merge pull request #51 from IceWhaleTech/dev
update app.go
2021-12-10 17:14:46 +08:00
link
caa9b50b65 update app.go 2021-12-10 17:14:01 +08:00
link
61b824065b Merge pull request #50 from IceWhaleTech/dev
update stats steam
2021-12-10 16:34:29 +08:00
link
9a900b2ca0 update stats steam 2021-12-10 16:33:39 +08:00
link
4c1cbc98a4 Merge pull request #49 from IceWhaleTech/dev
fixed bug
2021-12-10 14:18:01 +08:00
link
8660b95756 fixed bug 2021-12-10 14:17:36 +08:00
64 changed files with 5605 additions and 829 deletions

View File

@@ -63,7 +63,7 @@ jobs:
# git clone $REPO_URL -b $REPO_BRANCH --recursive casa
# ln -sf /workdir/casa $GITHUB_WORKSPACE/casa
# ls
- name: Set enviroment for github-release
run: |
@@ -76,7 +76,7 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build frontend with nodejs and yarn
run: |
cd UI
@@ -90,7 +90,7 @@ jobs:
- name: Build with xgo
uses: crazy-max/ghaction-xgo@v1
with:
xgo_version: latest
xgo_version: v0.7.5
go_version: ${{ matrix.go_version }}
dest: build
prefix: casa

View File

@@ -6,7 +6,7 @@
[![Pull Requests](https://img.shields.io/github/issues-pr/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/pulls)
[![Issues](https://img.shields.io/github/issues/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/issues)
[![GitHub Stars](https://img.shields.io/github/stars/IceWhaleTech/CasaOS?color=162453&logo=github&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/stargazers)
[![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/Gx4BCEtHjx)
[![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/knqAbbBbeX)
CasaOS is an open-source Home Cloud system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant Home Cloud system.
@@ -19,7 +19,7 @@ IceWhale team believes that through community-driven collaborative innovation an
> ⚠️ Note:
>
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/knqAbbBbeX)!
### Quick Setup CasaOS
@@ -71,9 +71,9 @@ After looking at many systems and software on the market, the team found no serv
So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you.
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/knqAbbBbeX)!
[![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/Gx4BCEtHjx)
[![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/knqAbbBbeX)

2
UI

Submodule UI updated: a982eb4bdd...106902c76a

View File

@@ -15,6 +15,9 @@ ProjectPath = /casaOS/server
HttpPort = 8089
RunMode = release
ServerApi = https://api.casaos.zimaboard.com
Handshake =
Token =
[user]
UserName = admin
@@ -22,7 +25,6 @@ PWD = zimaboard
Email = user@gmail.com
Description = description
Initialized = false
Token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImVyZXJlIiwicGFzc3dvcmQiOiJhZHNmZGYiLCJleHAiOjE2MjQwMDU0ODEsImlzcyI6Imdpbi1ibG9nIn0.JNsCccZuFCwlSMLJg62iOIB2xymk_k7xGa11xhZ07bc
[zerotier]
UserName = user

10
go.mod
View File

@@ -10,10 +10,11 @@ require (
github.com/bits-and-blooms/bitset v1.2.1 // indirect
github.com/containerd/containerd v1.5.7
github.com/containerd/continuity v0.2.0 // indirect
github.com/docker/distribution v2.8.0+incompatible // indirect
github.com/docker/docker v20.10.7+incompatible
github.com/docker/go-connections v0.4.0
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b
github.com/gin-contrib/gzip v0.0.2 // indirect
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
@@ -33,8 +34,10 @@ require (
github.com/leodido/go-urn v1.2.1 // indirect
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/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect
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/pkg/errors v0.9.1
@@ -49,7 +52,6 @@ require (
github.com/swaggo/gin-swagger v1.3.0
github.com/swaggo/swag v1.7.3
github.com/tidwall/gjson v1.10.2
github.com/tidwall/sjson v1.2.3
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/ugorji/go v1.2.6 // indirect
go.opencensus.io v0.23.0 // indirect
@@ -67,6 +69,6 @@ require (
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/driver/sqlite v1.1.5
gorm.io/gorm v1.21.15
gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.22.5
)

16
go.sum
View File

@@ -261,6 +261,8 @@ github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TT
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.0+incompatible h1:l9EaZDICImO1ngI+uTifW+ZYvvz7fKISBAKpg+MbWbY=
github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
@@ -492,6 +494,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
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=
@@ -553,6 +557,9 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@@ -608,6 +615,8 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@@ -747,8 +756,6 @@ 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/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
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=
@@ -1225,8 +1232,13 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.1.5 h1:JU8G59VyKu1x1RMQgjefQnkZjDe9wHc1kARDZPu5dZs=
gorm.io/driver/sqlite v1.1.5/go.mod h1:NpaYMcVKEh6vLJ47VP6T7Weieu4H1Drs3dGD/K6GrGc=
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.21.15 h1:gAyaDoPw0lCyrSFWhBlahbUA1U4P5RViC1uIqoB+1Rk=
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU=
gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=

View File

@@ -58,8 +58,9 @@ func main() {
r := route.InitRouter()
//service.SyncTask(sqliteDB)
cron2 := cron.New() //创建一个cron实例
//执行定时任务每5秒执行一次
err := cron2.AddFunc("0 0 0 1/1 * *", func() {
//every day execution
err := cron2.AddFunc("0 0/1 * * * *", func() {
//service.PushIpInfo(*&config.ServerInfo.Token)
//service.UpdataDDNSList(mysqldb)
//service.SyncTask(sqliteDB)
})
@@ -77,6 +78,7 @@ func main() {
WriteTimeout: 60 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}

View File

@@ -15,6 +15,7 @@ type ServerAppList struct {
Icon string `json:"icon"`
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
Category string `json:"category"`
CategoryFont string `json:"category_font"`
PortMap string `json:"port_map"`
ImageVersion string `json:"image_version"`
Tip string `json:"tip"`
@@ -36,6 +37,12 @@ type ServerAppList struct {
Healthy string `json:"healthy"`
Plugins Strings `json:"plugins"`
Origin string `json:"origin"`
Type int `json:"type"`
Developer string `json:"developer"`
HostName string `json:"host_name"`
Privileged bool `json:"privileged"`
CapAdd Strings `json:"cap_add"`
Cmd Strings `json:"cmd"`
}
type Ports struct {

View File

@@ -5,6 +5,7 @@ type ServerCategoryList struct {
//CreatedAt time.Time `json:"created_at"`
//
//UpdatedAt time.Time `json:"updated_at"`
Font string `json:"font"`
Name string `json:"name"`
Count uint `json:"count"`
}

View File

@@ -20,13 +20,57 @@ type LSBLKModel struct {
Format string `json:"format"`
Health string `json:"health"`
HotPlug bool `json:"hotplug"`
UUID string `json:"uuid"`
FSUsed string `json:"fsused"`
Temperature int `json:"temperature"`
Tran string `json:"tran"`
MinIO uint64 `json:"min-io"`
UsedPercent float64 `json:"used_percent"`
Serial string `json:"serial"`
Children []LSBLKModel `json:"children"`
SubSystems string `json:"subsystems"`
//详情特有
StartSector uint64 `json:"start_sector,omitempty"`
Rota bool `json:"rota"` //true(hhd) false(ssd)
DiskType string `json:"disk_type"`
EndSector uint64 `json:"end_sector,omitempty"`
}
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"`
}
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"` //可用空间
}
type Storage struct {
Name string `json:"name"`
MountPoint string `json:"mountpoint"`
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"`
}
type Summary struct {
Size uint64 `json:"size"`
Avail uint64 `json:"avail"` //可用空间
Health bool `json:"health"`
Used uint64 `json:"used"`
}

6
model/heart.go Normal file
View File

@@ -0,0 +1,6 @@
package model
type CasaOSHeart struct {
UuId string `json:"uuid"`
Type string `json:"type"`
}

View File

@@ -114,12 +114,16 @@ type CustomizationPostData struct {
Volumes PathArray `json:"volumes"`
Devices PathArray `json:"devices"`
//Port string `json:"port,omitempty"`
PortMap string `json:"port_map"`
CpuShares int64 `json:"cpu_shares"`
Memory int64 `json:"memory"`
Restart string `json:"restart"`
EnableUPNP bool `json:"enable_upnp"`
Label string `json:"label"`
Description string `json:"description"`
Position bool `json:"position"`
PortMap string `json:"port_map"`
CpuShares int64 `json:"cpu_shares"`
Memory int64 `json:"memory"`
Restart string `json:"restart"`
EnableUPNP bool `json:"enable_upnp"`
Label string `json:"label"`
Description string `json:"description"`
Position bool `json:"position"`
HostName string `json:"host_name"`
Privileged bool `json:"privileged"`
CapAdd []string `json:"cap_add"`
Cmd []string `json:"cmd"`
}

6
model/notify.go Normal file
View File

@@ -0,0 +1,6 @@
package model
type NotifyMssage struct {
Type string `json:"type"`
Data string `json:"data"`
}

19
model/person.go Normal file
View File

@@ -0,0 +1,19 @@
package model
import "time"
type PersionModel struct {
Token string `json:"token"`
Ips []string `json:"ips"`
CreatedAt time.Time `gorm:"<-:create;autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"autoUpdateTime" 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"` //对接标识
}

69
model/smartctl_model.go Normal file
View File

@@ -0,0 +1,69 @@
package model
//
type SmartctlA struct {
Smartctl struct {
Version []int `json:"version"`
SvnRevision string `json:"svn_revision"`
PlatformInfo string `json:"platform_info"`
BuildInfo string `json:"build_info"`
Argv []string `json:"argv"`
ExitStatus int `json:"exit_status"`
} `json:"smartctl"`
Device struct {
Name string `json:"name"`
InfoName string `json:"info_name"`
Type string `json:"type"`
Protocol string `json:"protocol"`
} `json:"device"`
ModelName string `json:"model_name"`
SerialNumber string `json:"serial_number"`
FirmwareVersion string `json:"firmware_version"`
UserCapacity struct {
Blocks int `json:"blocks"`
Bytes int64 `json:"bytes"`
} `json:"user_capacity"`
SmartStatus struct {
Passed bool `json:"passed"`
} `json:"smart_status"`
AtaSmartData struct {
OfflineDataCollection struct {
Status struct {
Value int `json:"value"`
String string `json:"string"`
} `json:"status"`
CompletionSeconds int `json:"completion_seconds"`
} `json:"offline_data_collection"`
SelfTest struct {
Status struct {
Value int `json:"value"`
String string `json:"string"`
Passed bool `json:"passed"`
} `json:"status"`
PollingMinutes struct {
Short int `json:"short"`
Extended int `json:"extended"`
Conveyance int `json:"conveyance"`
} `json:"polling_minutes"`
} `json:"self_test"`
Capabilities struct {
Values []int `json:"values"`
ExecOfflineImmediateSupported bool `json:"exec_offline_immediate_supported"`
OfflineIsAbortedUponNewCmd bool `json:"offline_is_aborted_upon_new_cmd"`
OfflineSurfaceScanSupported bool `json:"offline_surface_scan_supported"`
SelfTestsSupported bool `json:"self_tests_supported"`
ConveyanceSelfTestSupported bool `json:"conveyance_self_test_supported"`
SelectiveSelfTestSupported bool `json:"selective_self_test_supported"`
AttributeAutosaveEnabled bool `json:"attribute_autosave_enabled"`
ErrorLoggingSupported bool `json:"error_logging_supported"`
GpLoggingSupported bool `json:"gp_logging_supported"`
} `json:"capabilities"`
} `json:"ata_smart_data"`
PowerOnTime struct {
Hours int `json:"hours"`
} `json:"power_on_time"`
PowerCycleCount int `json:"power_cycle_count"`
Temperature struct {
Current int `json:"current"`
} `json:"temperature"`
}

View File

@@ -24,6 +24,8 @@ type ServerModel struct {
RunMode string
ServerApi string
LockAccount bool
Handshake string
Token string
}
//服务配置
@@ -70,5 +72,5 @@ type SystemConfig struct {
}
type CasaOSGlobalVariables struct {
AddApp bool
AppChange bool
}

View File

@@ -1,7 +1,10 @@
package model
import "time"
type Path struct {
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"is_dir"`
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"is_dir"`
Date time.Time `json:"date"`
}

View File

@@ -3,33 +3,9 @@ package docker
import "strings"
func GetDir(id, envName string) string {
var path string
if len(id) == 0 {
id = "$AppID"
if strings.Contains(envName, "$AppID") && len(id) > 0 {
return strings.ReplaceAll(envName, "$AppID", id)
}
switch {
case strings.Contains(strings.ToLower(envName), "config") || strings.Contains(strings.ToLower(envName), "photoprism/storage") || strings.Contains(strings.ToLower(envName), "config"):
path = "/DATA/AppData/" + id + "/"
case strings.Contains(strings.ToLower(envName), "media"):
path = "/DATA/Media/"
case strings.Contains(strings.ToLower(envName), "movie"):
path = "/DATA/Media/Movies/"
case strings.Contains(strings.ToLower(envName), "music"):
path = "/DATA/Media/Music/"
case strings.Contains(strings.ToLower(envName), "photoprism/originals"):
path = "/DATA/Gallery"
case strings.Contains(strings.ToLower(envName), "download"):
path = "/DATA/Downloads/"
case strings.Contains(strings.ToLower(envName), "photo") || strings.Contains(strings.ToLower(envName), "pictures"):
path = "/DATA/Downloads/"
case strings.ToLower(envName) == "/srv":
path = "/DATA/"
case strings.ToLower(envName) == "/tv":
path = "/DATA/Media/TV Shows"
default:
//path = "/media"
}
return path
return envName
}

View File

@@ -2,11 +2,12 @@ package sqlite
import (
"fmt"
"time"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"time"
)
var gdb *gorm.DB
@@ -30,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
return nil
}
gdb = db
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{})
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{})
if err != nil {
fmt.Println("检查和创建数据库出错", err)
}

View File

@@ -2,9 +2,11 @@ package command
import (
"bufio"
"context"
"fmt"
"io/ioutil"
"os/exec"
"time"
)
func OnlyExec(cmdStr string) {
@@ -75,6 +77,7 @@ func ExecResultStr(cmdStr string) string {
func ExecLSBLK() []byte {
output, err := exec.Command("lsblk", "-O", "-J", "-b").Output()
if err != nil {
fmt.Println("lsblk", err)
return nil
}
return output
@@ -84,7 +87,26 @@ func ExecLSBLK() []byte {
func ExecLSBLKByPath(path string) []byte {
output, err := exec.Command("lsblk", path, "-O", "-J", "-b").Output()
if err != nil {
fmt.Println("lsblk", err)
return nil
}
return output
}
//exec smart
func ExecSmartCTLByPath(path string) []byte {
timeout := 3
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel()
output, err := exec.CommandContext(ctx, "smartctl", "-a", path, "-j").Output()
if err != nil {
fmt.Println("smartctl", err)
return nil
}
return output
}
func ExecEnabledSMART(path string) {
exec.Command("smartctl", "-s on", path).Output()
}

View File

@@ -2,18 +2,25 @@ package env_helper
import "strings"
func ReplaceDefaultENV(key string) string {
func ReplaceDefaultENV(key, tz string) string {
temp := ""
switch key {
case "$DefaultPassword":
temp = "casaos"
case "$DefaultUserName":
temp = "admin"
case "$PUID":
temp = "1000"
case "$PGID":
temp = "1000"
case "$TZ":
temp = tz
}
return temp
}
//replace env default setting
func ReplaceStringDefaultENV(str string) string {
return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName"))
return strings.ReplaceAll(strings.ReplaceAll(str, "$DefaultPassword", ReplaceDefaultENV("$DefaultPassword", "")), "$DefaultUserName", ReplaceDefaultENV("$DefaultUserName", ""))
}

View File

@@ -2,6 +2,7 @@ package file
import (
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"os"
@@ -159,3 +160,68 @@ func ReadFullFile(path string) []byte {
}
return content
}
// File copies a single file from src to dst
func CopyFile(src, dst string) error {
var err error
var srcfd *os.File
var dstfd *os.File
var srcinfo os.FileInfo
if srcfd, err = os.Open(src); err != nil {
return err
}
defer srcfd.Close()
if dstfd, err = os.Create(dst); err != nil {
return err
}
defer dstfd.Close()
if _, err = io.Copy(dstfd, srcfd); err != nil {
return err
}
if srcinfo, err = os.Stat(src); err != nil {
return err
}
return os.Chmod(dst, srcinfo.Mode())
}
// Dir copies a whole directory recursively
func CopyDir(src string, dst string) error {
var err error
var fds []os.FileInfo
var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil {
return err
}
if !srcinfo.IsDir() {
if err = CopyFile(src, dst); err != nil {
fmt.Println(err)
}
return nil
}
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err
}
if fds, err = ioutil.ReadDir(src); err != nil {
return err
}
for _, fd := range fds {
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
if fd.IsDir() {
if err = CopyDir(srcfp, dstfp); err != nil {
fmt.Println(err)
}
} else {
if err = CopyFile(srcfp, dstfp); err != nil {
fmt.Println(err)
}
}
}
return nil
}

View File

@@ -21,6 +21,13 @@ const (
//zerotier
GET_TOKEN_ERROR = 30001
//disk
NAME_NOT_AVAILABLE = 40001
DISK_NEEDS_FORMAT = 40002
DISK_BUSYING = 40003
REMOVE_MOUNT_POINT_ERROR = 40004
FORMAT_ERROR = 40005
//app
UNINSTALL_APP_ERROR = 50001
PULL_IMAGE_ERROR = 50002
@@ -29,6 +36,7 @@ const (
//file
FILE_DOES_NOT_EXIST = 60001
FILE_READ_ERROR = 60002
FILE_DELETE_ERROR = 60003
//shortcuts
SHORTCUTS_URL_ERROR = 70001
@@ -37,34 +45,42 @@ const (
var MsgFlags = map[int]string{
SUCCESS: "ok",
ERROR: "fail",
INVALID_PARAMS: "Invalid params",
ERROR_AUTH_TOKEN: "error auth token",
INVALID_PARAMS: "Parameters Error",
ERROR_AUTH_TOKEN: "Error auth token",
//user
PWD_INVALID: "Password invalid",
PWD_INVALID: "Invalid password",
PWD_IS_EMPTY: "Password is empty",
PWD_INVALID_OLD: "Old Password invalid",
ACCOUNT_LOCK: "Account Lock",
PWD_INVALID_OLD: "Invalid old password",
ACCOUNT_LOCK: "Account is locked",
//system
DIR_ALREADY_EXISTS: "Directory already exists",
DIR_ALREADY_EXISTS: "Folder already exists",
FILE_ALREADY_EXISTS: "File already exists",
FILE_OR_DIR_EXISTS: "File or directory already exists",
FILE_OR_DIR_EXISTS: "File or folder already exists",
PORT_IS_OCCUPIED: "Port is occupied",
//zerotier
GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",
//app
UNINSTALL_APP_ERROR: "uninstall app error",
PULL_IMAGE_ERROR: "pull image error",
DEVICE_NOT_EXIST: "device not exist",
UNINSTALL_APP_ERROR: "Error uninstalling app",
PULL_IMAGE_ERROR: "Error pulling image",
DEVICE_NOT_EXIST: "Device does not exist",
//disk
NAME_NOT_AVAILABLE: "Name not available",
DISK_NEEDS_FORMAT: "Drive needs to be formatted",
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",
//
FILE_DOES_NOT_EXIST: "file does not exist",
FILE_DOES_NOT_EXIST: "File does not exist",
FILE_READ_ERROR: "file read error",
SHORTCUTS_URL_ERROR: "url error",
FILE_READ_ERROR: "File read error",
FILE_DELETE_ERROR: "Delete error",
SHORTCUTS_URL_ERROR: "URL error",
}
//获取错误信息

View File

@@ -3,6 +3,7 @@ package route
import (
"encoding/json"
"encoding/xml"
"fmt"
"strconv"
"time"
@@ -22,6 +23,10 @@ import (
func InitFunction() {
go checkSystemApp()
Update2_3()
CheckSerialDiskMount()
CheckToken2_9()
}
var syncIsExistence = false
@@ -32,10 +37,9 @@ func installSyncthing(appId string) {
m := model.CustomizationPostData{}
var dockerImage string
var dockerImageVersion string
appInfo = service.MyService.OAPI().GetServerAppInfo(appId)
appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "system", "us_en")
dockerImage = appInfo.Image
dockerImageVersion = appInfo.ImageVersion
if len(appInfo.ImageVersion) == 0 {
dockerImageVersion = "latest"
@@ -72,9 +76,6 @@ func installSyncthing(appId string) {
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
}
for i := 0; i < len(appInfo.Volumes); i++ {
appInfo.Volumes[i].Path = docker.GetDir("", appInfo.Volumes[i].ContainerPath)
}
appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
id := uuid.NewV4().String()
@@ -85,9 +86,9 @@ func installSyncthing(appId string) {
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
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)
}
@@ -102,8 +103,8 @@ func installSyncthing(appId string) {
m.Volumes = appInfo.Volumes
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
if err != nil {
fmt.Println("container create error", err)
// create container error
return
}
@@ -171,7 +172,7 @@ func checkSystemApp() {
path := ""
for _, i := range paths {
if i.ContainerPath == "/config" {
path = docker.GetDir(v.CustomId, i.ContainerPath) + "config.xml"
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml"
for i := 0; i < 10; i++ {
if file.CheckNotExist(path) {
time.Sleep(1 * time.Second)
@@ -189,13 +190,57 @@ func checkSystemApp() {
}
}
if !syncIsExistence {
installSyncthing("44")
installSyncthing("74")
}
}
func CheckSerialDiskMount() {
// 检查挂载点重新挂载
// 检查新硬盘是否有多个分区,如有多个分区需提示
// check mount point
dbList := service.MyService.Disk().GetSerialAll()
list := service.MyService.Disk().LSBLK(true)
mountPoint := make(map[string]string, len(dbList))
//remount
for _, v := range dbList {
mountPoint[v.UUID] = v.MountPoint
}
for _, v := range list {
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)
}
}
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().RemoveLSBLKCache()
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
}
func Update2_3() {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
}
func CheckToken2_9() {
if len(config.ServerInfo.Token) == 0 {
token := uuid.NewV4().String
config.ServerInfo.Token = token()
config.Cfg.Section("server").Key("Token").SetValue(token())
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
}

View File

@@ -8,6 +8,7 @@ import (
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
v1 "github.com/IceWhaleTech/CasaOS/route/v1"
"github.com/IceWhaleTech/CasaOS/web"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
)
@@ -18,6 +19,7 @@ func InitRouter() *gin.Engine {
r := gin.Default()
r.Use(middleware.Cors())
r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode)
r.StaticFS("/ui", http.FS(web.Static))
@@ -33,7 +35,7 @@ func InitRouter() *gin.Engine {
r.GET("/v1/guide/check", v1.GetGuideCheck)
r.GET("/debug", v1.GetSystemConfigDebug)
r.GET("/v1/debug", v1.GetSystemConfigDebug)
//set user
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
//get user info
@@ -70,8 +72,7 @@ func InitRouter() *gin.Engine {
//获取网络信息
v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
//获取网络信息
v1ZiMaGroup.GET("/getinfo", v1.Info)
//获取系统信息
v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
}
@@ -197,6 +198,7 @@ func InitRouter() *gin.Engine {
v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
v1SysGroup.GET("/info", v1.Info)
}
v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use()
@@ -206,39 +208,43 @@ func InitRouter() *gin.Engine {
v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/dirpath", v1.DirPath)
//创建目录
//create folder
v1FileGroup.POST("/mkdir", v1.MkdirAll)
v1FileGroup.POST("/create", v1.PostCreateFile)
v1FileGroup.GET("/download", v1.GetDownloadFile)
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
v1FileGroup.DELETE("delete", v1.DeleteFile)
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
}
v1DiskGroup := v1Group.Group("/disk")
v1DiskGroup.Use()
{
//获取磁盘列表
v1DiskGroup.GET("/list", v1.GetPlugInDisk)
v1DiskGroup.GET("/check", v1.GetDiskCheck)
v1DiskGroup.GET("/list", v1.GetDiskList)
//获取磁盘详情
v1DiskGroup.GET("/info", v1.GetDiskInfo)
//格式化磁盘
//format storage
v1DiskGroup.POST("/format", v1.FormatDisk)
//添加分区
v1DiskGroup.POST("/part", v1.AddPartition)
// add storage
v1DiskGroup.POST("/storage", v1.AddPartition)
//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)
//mount SATA disk
v1DiskGroup.POST("/mount", v1.PostMountDisk)
//umount SATA disk
v1DiskGroup.POST("/umount", v1.DeleteUmountDisk)
v1DiskGroup.GET("/usb", v1.GetUSBList)
}
v1ShareGroup := v1Group.Group("/share")
@@ -278,6 +284,11 @@ func InitRouter() *gin.Engine {
{
v1SearchGroup.GET("/search", v1.GetSearchList)
}
v1PersonGroup := v1Group.Group("/persion")
v1PersonGroup.Use()
{
v1PersonGroup.GET("/test", v1.PersonTest)
}
v1Group.GET("/sync/config", v1.GetSyncConfig)
v1Group.Any("/syncthing/*url", v1.SyncToSyncthing)

View File

@@ -7,8 +7,6 @@ import (
"strconv"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
@@ -33,20 +31,34 @@ func AppList(c *gin.Context) {
//service.MyService.Docker().DockerContainerCommit("test2")
index := c.DefaultQuery("index", "1")
size := c.DefaultQuery("size", "10")
size := c.DefaultQuery("size", "10000")
t := c.DefaultQuery("type", "rank")
categoryId := c.DefaultQuery("category_id", "0")
key := c.DefaultQuery("key", "")
list, count := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
for i := 0; i < len(list); i++ {
ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
if ct != nil {
list[i].State = ct.State
}
}
data := make(map[string]interface{}, 2)
data["count"] = count
data["items"] = list
language := c.GetHeader("Language")
recommend, list, community := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key, language)
// for i := 0; i < len(recommend); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
// if ct != nil {
// recommend[i].State = ct.State
// }
// }
// for i := 0; i < len(list); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
// if ct != nil {
// list[i].State = ct.State
// }
// }
// for i := 0; i < len(community); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
// if ct != nil {
// community[i].State = ct.State
// }
// }
data := make(map[string]interface{}, 3)
data["recommend"] = recommend
data["list"] = list
data["community"] = community
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
@@ -126,7 +138,8 @@ func AppUsageList(c *gin.Context) {
func AppInfo(c *gin.Context) {
id := c.Param("id")
info := service.MyService.OAPI().GetServerAppInfo(id)
language := c.GetHeader("Language")
info := service.MyService.OAPI().GetServerAppInfo(id, "", language)
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) {
@@ -147,6 +160,13 @@ func AppInfo(c *gin.Context) {
info.PortMap = info.Ports[i].CommendPort
}
}
} else {
for i := 0; i < len(info.Ports); i++ {
if info.Ports[i].Type == 0 {
info.PortMap = info.Ports[i].ContainerPort
break
}
}
}
for i := 0; i < len(info.Devices); i++ {
@@ -154,13 +174,10 @@ func AppInfo(c *gin.Context) {
info.Devices[i].Path = info.Devices[i].ContainerPath
}
}
if len(info.Tip) > 0 {
info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
}
// if len(info.Tip) > 0 {
// info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
// }
for i := 0; i < len(info.Volumes); i++ {
info.Volumes[i].Path = docker.GetDir("", info.Volumes[i].ContainerPath)
}
// portOrder := func(c1, c2 *model.Ports) bool {
// return c1.Type < c2.Type
// }
@@ -207,7 +224,7 @@ func CategoryList(c *gin.Context) {
}
rear := append([]model.ServerCategoryList{}, list[0:]...)
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All"})
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All", Font: "apps"})
list = append(list, rear...)
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}

View File

@@ -1,62 +1,160 @@
package v1
import (
"fmt"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v3/disk"
)
// @Summary 获取磁盘列表
var diskMap = make(map[string]string)
// @Summary disk list
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/list [get]
func GetPlugInDisk(c *gin.Context) {
func GetDiskList(c *gin.Context) {
list := service.MyService.Disk().LSBLK(false)
dbList := service.MyService.Disk().GetSerialAll()
part := make(map[string]int64, len(dbList))
for _, v := range dbList {
part[v.MountPoint] = v.CreatedAt
}
findSystem := 0
//ls := service.MyService.Disk().GetPlugInDisk()
//fmt.Println(ls)
//dd, _ := disk.Partitions(true)
//fmt.Println(dd)
//
//dir, err := ioutil.ReadDir("/sys/block")
//if err != nil {
// panic(err)
//}
//
//files := make([]string, 0)
//
////fmt.Println(regexp.MatchString("sd[a-z]*[0-9]", "sda"))
//
//for _, f := range dir {
// if match, _ := regexp.MatchString("sd[a-z]", f.Name()); match {
// files = append(files, f.Name())
// }
//}
//fmt.Println(files)
//filess := make([]string, 0)
//for _, file := range files {
// dirs, _ := ioutil.ReadDir("/sys/block/" + file)
//
// for _, f := range dirs {
// if match, _ := regexp.MatchString("sd[a-z]*[0-9]", f.Name()); match {
// filess = append(filess, f.Name())
// }
// }
//}
//fmt.Println(filess)
//
//for _, s := range filess {
// fmt.Println(disk.Usage("/dev/" + s))
//}
disks := []model.Drive{}
storage := []model.Storage{}
avail := []model.Drive{}
for i := 0; i < len(list); i++ {
disk := model.Drive{}
if list[i].Rota {
disk.DiskType = "HDD"
} else {
disk.DiskType = "SSD"
}
disk.Serial = list[i].Serial
disk.Name = list[i].Name
disk.Size = list[i].Size
disk.Path = list[i].Path
disk.Model = list[i].Model
lst := service.MyService.Disk().LSBLK()
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: lst})
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
stor.Path = v.Path
stor.Type = v.FsType
stor.DriveName = "System"
disk.Model = "System"
if strings.Contains(v.SubSystems, "mmc") {
disk.DiskType = "MMC"
} else if strings.Contains(v.SubSystems, "usb") {
disk.DiskType = "USB"
}
disk.Health = "true"
disks = append(disks, disk)
storage = append(storage, stor)
findSystem = 1
break
}
}
} 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
stor.Path = list[i].Children[j].Path
stor.Type = list[i].Children[j].FsType
stor.DriveName = "System"
disk.Model = "System"
if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
disk.DiskType = "MMC"
} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
disk.DiskType = "USB"
}
disk.Health = "true"
disks = append(disks, disk)
storage = append(storage, stor)
findSystem = 1
break
}
}
}
}
if findSystem == 1 {
findSystem += 1
continue
}
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
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)
}
}
disk.Temperature = temp.Temperature.Current
disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
disks = append(disks, disk)
}
}
data := make(map[string]interface{}, 3)
data["drive"] = disks
data["storage"] = storage
data["avail"] = avail
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
}
// @Summary get disk list
@@ -68,7 +166,7 @@ func GetPlugInDisk(c *gin.Context) {
// @Router /disk/lists [get]
func GetPlugInDisks(c *gin.Context) {
list := service.MyService.Disk().LSBLK()
list := service.MyService.Disk().LSBLK(true)
var result []*disk.UsageStat
for _, item := range list {
result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
@@ -93,25 +191,46 @@ func GetDiskInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
}
// @Summary format disk
// @Summary format storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "磁盘路径 例如/dev/sda1"
// @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 FormatDisk(c *gin.Context) {
path := c.PostForm("path")
t := "ext4"
pwd := c.PostForm("pwd")
volume := c.PostForm("volume")
t := c.PostForm("type")
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
return
}
if len(path) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
//格式化磁盘
service.MyService.Disk().FormatDisk(path, t)
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_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: oasis_err.FORMAT_ERROR, Message: oasis_err.GetMsg(oasis_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: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
@@ -148,43 +267,231 @@ func RemovePartition(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary serial number
// @Summary add storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "磁盘路径 例如/dev/sda"
// @Param path formData string true "disk path e.g. /dev/sda"
// @Param serial formData string true "serial"
// @Param name formData string true "name"
// @Param format formData bool true "need format(true)"
// @Success 200 {string} string "ok"
// @Router /disk/addpart [post]
// @Router /disk/storage [post]
func AddPartition(c *gin.Context) {
name := c.PostForm("name")
path := c.PostForm("path")
serial := c.PostForm("serial")
if len(path) == 0 || len(serial) == 0 {
format, _ := strconv.ParseBool(c.PostForm("format"))
if len(name) == 0 || len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
service.MyService.Disk().AddPartition(path)
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
return
}
if !file.CheckNotExist("/DATA/" + name) {
// /mnt/name exist
c.JSON(http.StatusOK, model.Result{Success: oasis_err.NAME_NOT_AVAILABLE, Message: oasis_err.GetMsg(oasis_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: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
delete(diskMap, path)
return
}
} else {
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)
}
currentDisk = service.MyService.Disk().GetDiskInfo(path)
if len(currentDisk.Children) != 1 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
return
}
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)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_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"
// @Success 200 {string} string "ok"
// @Router /disk/mount [post]
func PostMountDisk(c *gin.Context) {
// for example: path=/dev/sda1
path := c.PostForm("path")
//执行挂载目录
service.MyService.Disk().MountDisk(path, "volume")
//添加到数据库
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"
}
for i := 0; i < len(list)+1; i++ {
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
mountPath = mountPath + strconv.Itoa(i)
break
}
}
//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: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
func DeleteUmountDisk(c *gin.Context) {
// @Summary remove mount point
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "e.g. /dev/sda1"
// @Param mount_point formData string true "e.g. /mnt/volume1"
// @Param pwd formData string true "user password"
// @Success 200 {string} string "ok"
// @Router /disk/umount [post]
func PostDiskUmount(c *gin.Context) {
// for example: path=/dev/sda1
path := c.PostForm("path")
service.MyService.Disk().UmountPointAndRemoveDir(path)
mountPoint := c.PostForm("volume")
pwd := c.PostForm("pwd")
//删除数据库记录
if len(path) == 0 || len(mountPoint) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
return
}
service.MyService.Disk().UmountPointAndRemoveDir(path)
//delete data
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
service.MyService.Disk().RemoveLSBLKCache()
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary confirm delete disk
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Param id path string true "id"
// @Success 200 {string} string "ok"
// @Router /disk/remove/{id} [delete]
func DeleteDisk(c *gin.Context) {
id := c.Param("id")
service.MyService.Disk().DeleteMount(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary check mount point
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/init [get]
func GetDiskCheck(c *gin.Context) {
dbList := service.MyService.Disk().GetSerialAll()
list := service.MyService.Disk().LSBLK(true)
mapList := make(map[string]string)
for _, v := range list {
mapList[v.Serial] = "1"
}
for _, v := range dbList {
if _, ok := mapList[v.UUID]; !ok {
//disk undefind
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_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: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
}

View File

@@ -2,6 +2,7 @@ package v1
import (
"bytes"
"encoding/json"
json2 "encoding/json"
"net/http"
"reflect"
@@ -145,6 +146,7 @@ func SpeedPush(c *gin.Context) {
// @Router /app/install/{id} [post]
func InstallApp(c *gin.Context) {
appId := c.Param("id")
language := c.GetHeader("Language")
var appInfo model.ServerAppList
m := model.CustomizationPostData{}
c.BindJSON(&m)
@@ -174,7 +176,7 @@ func InstallApp(c *gin.Context) {
dockerImageVersion = "latest"
}
if m.Origin != "custom" {
appInfo = service.MyService.OAPI().GetServerAppInfo(appId)
appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "", language)
} else {
@@ -218,14 +220,24 @@ func InstallApp(c *gin.Context) {
}
}
if m.Origin == "custom" {
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
return
}
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
return
}
} else {
dev := []model.PathMap{}
for _, device := range dev {
if !file.CheckNotExist(device.Path) {
dev = append(dev, device)
}
}
m.Devices = dev
}
//restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
//if len(restart) > 0 {
//
@@ -243,9 +255,11 @@ func InstallApp(c *gin.Context) {
installLog.State = 0
installLog.CustomId = id
installLog.Message = "installing rely"
installLog.Class = types.NOTIFY_APP
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.Id = uuid.NewV4().String()
service.MyService.Notify().AddLog(installLog)
if m.Origin != "custom" {
for _, plugin := range appInfo.Plugins {
@@ -421,16 +435,18 @@ func InstallApp(c *gin.Context) {
rely := model.MapStrings{}
copier.Copy(&rely, &relyMap)
if m.Origin != "custom" {
for i := 0; i < len(m.Volumes); i++ {
m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].ContainerPath)
}
}
// if m.Origin != "custom" {
// for i := 0; i < len(m.Volumes); i++ {
// m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
// }
// }
portsStr, _ := json2.Marshal(m.Ports)
envsStr, _ := json2.Marshal(m.Envs)
volumesStr, _ := json2.Marshal(m.Volumes)
devicesStr, _ := json2.Marshal(m.Devices)
cmd, _ := json2.Marshal(m.Cmd)
capAdd, _ := json.Marshal(m.CapAdd)
//step: 保存数据到数据库
md := model2.AppListDBModel{
CustomId: id,
@@ -458,15 +474,19 @@ func InstallApp(c *gin.Context) {
Memory: m.Memory,
Devices: string(devicesStr),
//Rely: rely,
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
Cmd: string(cmd),
CapAdd: string(capAdd),
HostName: m.HostName,
Privileged: m.Privileged,
}
//if appInfo.NetworkModel == "host" {
// m.PortMap = m.Port
//}
service.MyService.App().SaveContainer(md)
config.CasaOSGlobalVariables.AddApp = true
config.CasaOSGlobalVariables.AppChange = true
}()
@@ -704,7 +724,7 @@ func UnInstallApp(c *gin.Context) {
}
//step: 删除install log
service.MyService.Notify().DelLog(appId)
//service.MyService.Notify().DelLog(appId)
// for k, v := range info.Rely {
//
@@ -743,6 +763,13 @@ func UnInstallApp(c *gin.Context) {
// }
//}
}
config.CasaOSGlobalVariables.AppChange = true
unInstallLog := model2.AppNotify{}
unInstallLog.State = 0
unInstallLog.CustomId = appId
unInstallLog.Message = "uninstalled"
unInstallLog.Id = uuid.NewV4().String()
service.MyService.Notify().UpdateLog(unInstallLog)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
@@ -915,7 +942,9 @@ func UpdateSetting(c *gin.Context) {
envsStr, _ := json2.Marshal(m.Envs)
volumesStr, _ := json2.Marshal(m.Volumes)
devicesStr, _ := json2.Marshal(m.Devices)
if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel {
capAddStr, _ := json2.Marshal(m.CapAdd)
cmdStr, _ := json.Marshal(m.Cmd)
if !reflect.DeepEqual(string(portsStr), appInfo.Ports) || !reflect.DeepEqual(string(envsStr), appInfo.Envs) || !reflect.DeepEqual(string(volumesStr), appInfo.Volumes) || m.PortMap != appInfo.PortMap || m.NetworkModel != appInfo.NetModel || m.HostName != appInfo.HostName || !reflect.DeepEqual(string(cmdStr), appInfo.Cmd) || !reflect.DeepEqual(string(capAddStr), appInfo.CapAdd) || m.Privileged != appInfo.Privileged {
var newUUid = uuid.NewV4().String()
var err error
@@ -1033,6 +1062,10 @@ func UpdateSetting(c *gin.Context) {
appInfo.Restart = m.Restart
appInfo.Memory = m.Memory
appInfo.CpuShares = m.CpuShares
appInfo.Cmd = string(cmdStr)
appInfo.Privileged = m.Privileged
appInfo.CapAdd = string(capAddStr)
appInfo.HostName = m.HostName
appInfo.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
service.MyService.App().UpdateApp(appInfo)
@@ -1128,7 +1161,6 @@ func ContainerRelyInfo(c *gin.Context) {
func ContainerUpdateInfo(c *gin.Context) {
appId := c.Param("id")
appInfo := service.MyService.App().GetAppDBInfo(appId)
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
//todo 需要自定义错误
@@ -1151,6 +1183,10 @@ func ContainerUpdateInfo(c *gin.Context) {
var dir model.PathArray
json2.Unmarshal([]byte(appInfo.Devices), &dir)
var cmd []string
json2.Unmarshal([]byte(appInfo.Cmd), &cmd)
var capAdd []string
json2.Unmarshal([]byte(appInfo.CapAdd), &capAdd)
//volumesStr, _ := json2.Marshal(m.Volumes)
//devicesStr, _ := json2.Marshal(m.Devices)
m := model.CustomizationPostData{}
@@ -1172,6 +1208,11 @@ func ContainerUpdateInfo(c *gin.Context) {
m.EnableUPNP = appInfo.EnableUPNP
m.Position = appInfo.Position
m.CapAdd = capAdd
m.Cmd = cmd
m.HostName = appInfo.HostName
m.Privileged = appInfo.Privileged
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
}

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"os"
"path"
"strings"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
@@ -125,12 +126,12 @@ func GetLocalFile(c *gin.Context) {
return
}
// @Summary 下载文件
// @Summary download
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "路径"
// @Param path query string true "path of file"
// @Success 200 {string} string "ok"
// @Router /file/download [get]
func GetDownloadFile(c *gin.Context) {
@@ -163,7 +164,6 @@ func GetDownloadFile(c *gin.Context) {
c.Header("Content-Transfer-Encoding", "binary")
c.File(filePath)
return
}
// @Summary 获取目录列表
@@ -175,18 +175,18 @@ func GetDownloadFile(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /file/dirpath [get]
func DirPath(c *gin.Context) {
path := c.DefaultQuery("path", "/")
path := c.DefaultQuery("path", "")
info := service.MyService.ZiMa().GetDirPath(path)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary 重命名目录或文件
// @Summary rename file or dir
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param oldpath formData string true "旧的路径"
// @Param newpath formData string true "新路径"
// @Param oldpath formData string true "path of old"
// @Param newpath formData string true "path of new"
// @Success 200 {string} string "ok"
// @Router /file/rename [put]
func RenamePath(c *gin.Context) {
@@ -200,12 +200,12 @@ func RenamePath(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary 创建文件夹
// @Summary create folder
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param path formData string false "路径"
// @Param path formData string true "path of folder"
// @Success 200 {string} string "ok"
// @Router /file/mkdir [post]
func MkdirAll(c *gin.Context) {
@@ -238,21 +238,85 @@ func PostCreateFile(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
}
// @Summary 上传文件
// @Summary upload file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param path formData string false "路径"
// @Param path formData string false "file path"
// @Param file formData file true "file"
// @Success 200 {string} string "ok"
// @Router /file/mkdir [post]
// @Router /file/upload [post]
func PostFileUpload(c *gin.Context) {
file, _, _ := c.Request.FormFile("file")
//file.Read()
f, _, _ := c.Request.FormFile("file")
path := c.Query("path")
//上传文件
if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if !file.CheckNotExist(path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
defer out.Close()
io.Copy(out, file)
_, err := io.Copy(out, f)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary copy or move file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param from formData string true "from path"
// @Param to formData string true "to path"
// @Param t formData string true "action" Enums(move,copy)
// @Success 200 {string} string "ok"
// @Router /file/operate [post]
func PostOperateFileOrDir(c *gin.Context) {
from := c.PostForm("from")
to := c.PostForm("to")
t := c.PostForm("type")
if len(from) == 0 || len(t) == 0 || len(to) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if t == "move" {
lastPath := from[strings.LastIndex(from, "/")+1:]
if !file.CheckNotExist(to + "/" + lastPath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_OR_DIR_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
err := os.Rename(from, to+"/"+lastPath)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
} else if t == "copy" {
err := file.CopyDir(from, to)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
} else {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
func DeleteFile(c *gin.Context) {
path := c.Query("path")
//err := os.Remove(path)
err := os.RemoveAll(path)
if err != nil {
fmt.Println(err)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

@@ -1,15 +1,13 @@
package v1
import (
json2 "encoding/json"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"net/http"
"time"
)
var upGrader = websocket.Upgrader{
@@ -33,24 +31,17 @@ func NotifyWS(c *gin.Context) {
return
}
defer ws.Close()
service.WebSocketConns = append(service.WebSocketConns, ws)
if !service.SocketRun {
service.SocketRun = true
service.SendMeg()
}
for {
mt, message, err := ws.ReadMessage()
if err != nil {
break
}
if string(message) != "notify" {
return
}
for {
list := service.MyService.Notify().GetList()
json, _ := json2.Marshal(list)
err = ws.WriteMessage(mt, json)
if err != nil {
break
}
time.Sleep(time.Second * 2)
}
fmt.Println(mt, message, err)
}
}
// @Summary 标记notify已读
@@ -62,9 +53,10 @@ func NotifyWS(c *gin.Context) {
// @Router /notify/read/{id} [put]
func PutNotifyRead(c *gin.Context) {
id := c.Param("id")
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
// if len(id) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
// return
// }
fmt.Println(id)
service.MyService.Notify().MarkRead(id, types.NOTIFY_READ)
}

25
route/v1/persion.go Normal file
View File

@@ -0,0 +1,25 @@
package v1
import (
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
)
func PersonTest(c *gin.Context) {
//service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9")
m := model.ConnectState{}
m.CreatedAt = time.Now()
m.From = config.ServerInfo.Token
m.To = "fb2333a1-72b2-4cb4-9e31-61ccaffa55b9"
m.Type = ""
m.UUId = uuid.NewV4().String()
service.MyService.Person().Handshake(m)
}

View File

@@ -5,12 +5,16 @@ import (
"fmt"
"net/http"
"os"
"reflect"
"strconv"
"strings"
"time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
"github.com/IceWhaleTech/CasaOS/service"
@@ -104,9 +108,33 @@ func GetSystemConfigDebug(c *gin.Context) {
array := service.MyService.System().GetSystemConfigDebug()
disk := service.MyService.ZiMa().GetDiskInfo()
array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
sys := service.MyService.ZiMa().GetSysInfo()
//todo 准备sync需要显示的数据(镜像,容器)
var systemAppStatus string
images := service.MyService.Docker().IsExistImage("linuxserver/syncthing")
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: array})
list := service.MyService.App().GetSystemAppList()
for _, v := range *list {
systemAppStatus += v.Image + ",\n\t"
}
systemAppStatus += "Sync Key length: " + strconv.Itoa(len(config.SystemConfigInfo.SyncKey))
var bugContent string = fmt.Sprintf(`
- OS: %s
- CasaOS Version: %s
- Disk Total: %v
- Disk Used: %v
- Sync State: %s
- System Info: %s
- Browser: $Browser$
- Version: $Version$
`, sys.OS, types.CURRENTVERSION, disk.Total>>20, disk.Used>>20, systemAppStatus, array)
// 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: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: bugContent})
}
func Sys(c *gin.Context) {
service.DockerPull()
@@ -127,8 +155,9 @@ func GetWidgetConfig(c *gin.Context) {
func PostSetWidgetConfig(c *gin.Context) {
buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf)
fmt.Println("错误", strconv.Itoa(n))
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
fmt.Println("错误1", string(buf[0:n]))
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
@@ -221,3 +250,138 @@ func GetGuideCheck(c *gin.Context) {
func PostKillCasaOS(c *gin.Context) {
os.Exit(0)
}
// @Summary system info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/info [get]
func Info(c *gin.Context) {
var data = make(map[string]interface{}, 6)
list := service.MyService.Disk().LSBLK(true)
summary := model.Summary{}
healthy := true
findSystem := 0
for i := 0; i < len(list); i++ {
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 == "/" {
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
findSystem = 1
break
}
}
} else {
if list[i].Children[j].MountPoint == "/" {
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
findSystem = 1
break
}
}
}
}
if findSystem == 1 {
findSystem += 1
continue
}
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
if reflect.DeepEqual(temp, model.SmartctlA{}) {
continue
}
//list[i].Temperature = temp.Temperature.Current
if !temp.SmartStatus.Passed {
healthy = false
}
if len(list[i].Children) > 0 {
for _, v := range list[i].Children {
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
}
}
}
}
summary.Health = healthy
data["disk"] = summary
usbList := service.MyService.Disk().LSBLK(false)
usb := []model.DriveUSB{}
for _, v := range usbList {
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
used, _ := strconv.ParseUint(child.FSUsed, 10, 64)
temp.Used += used
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
usb = append(usb, temp)
}
}
data["usb"] = usb
cpu := service.MyService.ZiMa().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum()
cpuData := make(map[string]interface{})
cpuData["percent"] = cpu
cpuData["num"] = num
data["cpu"] = cpuData
data["mem"] = service.MyService.ZiMa().GetMemInfo()
//拼装网络信息
netList := service.MyService.ZiMa().GetNetInfo()
newNet := []model.IOCountersStat{}
nets := service.MyService.ZiMa().GetNet(true)
for _, n := range netList {
for _, netCardName := range nets {
if n.Name == netCardName {
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
item.DateTime = time.Now()
newNet = append(newNet, item)
break
}
}
}
data["net"] = newNet
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

View File

@@ -2,12 +2,13 @@ package v1
import (
json2 "encoding/json"
"net/http"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
"net/http"
)
// @Summary 登录zerotier获取token
@@ -432,11 +433,17 @@ func ZeroTierDeleteNetwork(c *gin.Context) {
// @Router /zerotier/join/{id} [post]
func ZeroTierJoinNetwork(c *gin.Context) {
networkId := c.Param("id")
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
if len(networkId) == 0 {
if len(networkId) != 16 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
for _, v := range networkId {
if !service.MyService.ZeroTier().NetworkIdFilter(v) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
}
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
@@ -450,10 +457,19 @@ func ZeroTierJoinNetwork(c *gin.Context) {
// @Router /zerotier/leave/{id} [post]
func ZeroTierLeaveNetwork(c *gin.Context) {
networkId := c.Param("id")
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
if len(networkId) == 0 {
if len(networkId) != 16 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
for _, v := range networkId {
if !service.MyService.ZeroTier().NetworkIdFilter(v) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
}
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

@@ -1,15 +1,15 @@
package v1
import (
"github.com/IceWhaleTech/CasaOS/model"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v3/disk"
"net/http"
"strings"
"time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
)
// @Summary 获取cpu信息
@@ -83,48 +83,6 @@ func NetInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
}
// @Summary 获取信息
// @Produce application/json
// @Accept application/json
// @Tags zima
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zima/getinfo [get]
func Info(c *gin.Context) {
var data = make(map[string]interface{}, 4)
var diskArr []*disk.UsageStat
diskArr = append(diskArr, service.MyService.ZiMa().GetDiskInfo())
data["disk"] = diskArr
cpu := service.MyService.ZiMa().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum()
cpuData := make(map[string]interface{})
cpuData["percent"] = cpu
cpuData["num"] = num
data["cpu"] = cpuData
data["mem"] = service.MyService.ZiMa().GetMemInfo()
//拼装网络信息
netList := service.MyService.ZiMa().GetNetInfo()
newNet := []model.IOCountersStat{}
nets := service.MyService.ZiMa().GetNet(true)
for _, n := range netList {
for _, netCardName := range nets {
if n.Name == netCardName {
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
item.DateTime = time.Now()
newNet = append(newNet, item)
break
}
}
}
data["net"] = newNet
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary 获取信息系统信息
// @Produce application/json
// @Accept application/json

View File

@@ -46,7 +46,7 @@ type appStruct struct {
//获取我的应用列表
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
}
@@ -81,13 +81,13 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
m.Label = m.Title
}
info, err := cli.ContainerInspect(context.Background(), container.ID)
var tm string
if err != nil {
tm = time.Now().String()
} else {
tm = info.State.StartedAt
}
// info, err := cli.ContainerInspect(context.Background(), container.ID)
// var tm string
// if err != nil {
// tm = time.Now().String()
// } else {
// tm = info.State.StartedAt
//}
list = append(list, model2.MyAppList{
Name: m.Label,
Icon: m.Icon,
@@ -95,9 +95,9 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
Port: m.PortMap,
Index: m.Index,
UpTime: tm,
Image: m.Image,
Slogan: m.Slogan,
//UpTime: tm,
Image: m.Image,
Slogan: m.Slogan,
//Rely: m.Rely,
})
}
@@ -120,7 +120,7 @@ func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
fts.Add("label", "origin=system")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
a.log.Error("获取docker容器失败", "app.sys", "line:123", err)
}
//获取本地数据库应用
@@ -179,7 +179,7 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
filters.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err)
}
if len(containers) > 0 {
@@ -240,7 +240,7 @@ func (a *appStruct) RemoveContainerById(id string) {
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
}
var dataStr map[string]model.DockerStatsModel
var dataStats sync.Map
var isFinish bool = false
@@ -269,25 +269,19 @@ func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
a.GetHardwareUsageSteam()
}()
}
// 切一下,再次分配任务
runtime.Gosched()
}
list := []model.DockerStatsModel{}
for _, v := range dataStr {
list = append(list, v)
}
dataStats.Range(func(key, value interface{}) bool {
list = append(list, value.(model.DockerStatsModel))
return true
})
return list
}
func (a *appStruct) GetHardwareUsageSteam() {
var lock = &sync.Mutex{}
if len(dataStr) == 0 {
lock.Lock()
dataStr = make(map[string]model.DockerStatsModel)
lock.Unlock()
}
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
@@ -299,16 +293,28 @@ func (a *appStruct) GetHardwareUsageSteam() {
ctx, cancel := context.WithCancel(ctx)
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm)
var list []types.ContainerStats
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
for i := 0; i < 100; i++ {
if config.CasaOSGlobalVariables.AddApp {
a.db.Table(model2.CONTAINERTABLENAME).Select("label,icon,container_id").Where("origin != ?", "system").Find(&lm)
if config.CasaOSGlobalVariables.AppChange {
lm = []model2.AppListDBModel{}
config.CasaOSGlobalVariables.AppChange = false
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
dataApps := dataStats
dataStats.Range(func(key, value interface{}) bool {
dataStats.Delete(key)
return true
})
for _, v := range lm {
m, _ := dataApps.Load(v.ContainerId)
if m != nil {
dataStats.Store(v.ContainerId, m)
}
}
}
var wg sync.WaitGroup
for _, v := range lm {
wg.Add(1)
go func(v model2.AppListDBModel, lock *sync.Mutex) {
go func(v model2.AppListDBModel, i int) {
defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
if err != nil {
@@ -319,37 +325,32 @@ func (a *appStruct) GetHardwareUsageSteam() {
if err := decode.Decode(&data); err == io.EOF {
return
}
lock.Lock()
m, _ := dataStats.Load(v.ContainerId)
dockerStats := model.DockerStatsModel{}
dockerStats.Pre = dataStr[v.ContainerId].Data
if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data
}
dockerStats.Data = data
dockerStats.Icon = v.Icon
dockerStats.Title = v.Label
dataStr[v.ContainerId] = dockerStats
lock.Unlock()
}(v, lock)
if len(v.Label) > 0 {
dockerStats.Title = v.Label
} else {
dockerStats.Title = v.Title
}
dataStats.Store(v.ContainerId, dockerStats)
if i == 99 {
stats.Body.Close()
}
}(v, i)
}
wg.Wait()
isFinish = true
if i == 99 {
for _, v := range list {
v.Body.Close()
}
}
time.Sleep(time.Second * 2)
time.Sleep(time.Second * 3)
}
isFinish = false
cancel()
}
// init install
func Init() {
}
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService {
Init()
return &appStruct{db: db, log: logger}
}

View File

@@ -1,7 +1,9 @@
package service
import (
"encoding/json"
json2 "encoding/json"
"fmt"
"strconv"
"github.com/IceWhaleTech/CasaOS/model"
@@ -12,11 +14,12 @@ import (
)
type CasaService interface {
GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64)
GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList)
GetServerCategoryList() []model.ServerCategoryList
GetTaskList(size int) []model2.TaskDBModel
GetServerAppInfo(id string) model.ServerAppList
GetServerAppInfo(id, t string, language string) model.ServerAppList
ShareAppFile(body []byte) string
PushHeart(id, t string, language string)
}
type casaService struct {
@@ -44,20 +47,34 @@ func (o *casaService) GetTaskList(size int) []model2.TaskDBModel {
return list
}
func (o *casaService) GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64) {
func (o *casaService) GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList) {
keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, language)
if result, ok := Cache.Get(keyName); ok {
res, ok := result.(string)
if ok {
json2.Unmarshal([]byte(gjson.Get(res, "data.list").String()), &list)
json2.Unmarshal([]byte(gjson.Get(res, "data.recommend").String()), &recommend)
json2.Unmarshal([]byte(gjson.Get(res, "data.community").String()), &community)
return
}
}
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/list?index="+index+"&size="+size+"&type="+tp+"&category_id="+categoryId+"&key="+key, head)
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index="+index+"&size="+size+"&rank="+tp+"&category_id="+categoryId+"&key="+key+"&language="+language, head)
list := []model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &list)
json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommend)
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community)
count := gjson.Get(listS, "data.count").Int()
json2.Unmarshal([]byte(gjson.Get(listS, "data.items").String()), &list)
return list, count
if len(list) > 0 {
Cache.SetDefault(keyName, listS)
}
return
}
func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
@@ -65,7 +82,7 @@ func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/category", head)
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
list := []model.ServerCategoryList{}
@@ -73,13 +90,12 @@ func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
return list
}
func (o *casaService) GetServerAppInfo(id string) model.ServerAppList {
func (o *casaService) GetServerAppInfo(id, t string, language string) model.ServerAppList {
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/info/"+id, head)
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t+"&language="+language, head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
@@ -109,6 +125,24 @@ func GetToken() string {
return auth
}
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 NewOasisService() CasaService {
return &casaService{}
}

View File

@@ -3,8 +3,10 @@ package service
import (
json2 "encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -18,39 +20,73 @@ import (
type DiskService interface {
GetPlugInDisk() []string
LSBLK() []model.LSBLKModel
FormatDisk(path, format string) string
UmountPointAndRemoveDir(path string) string
LSBLK(isUseCache bool) []model.LSBLKModel
SmartCTL(path string) model.SmartctlA
FormatDisk(path, format string) []string
UmountPointAndRemoveDir(path string) []string
GetDiskInfo(path string) model.LSBLKModel
DelPartition(path, num string) string
AddPartition(path string) string
GetDiskInfoByPath(path string) *disk.UsageStat
MountDisk(path, volume string)
SerialAll(mountPoint string) *[]model2.SerialDisk
GetSerialAll() []model2.SerialDisk
SaveMountPoint(m model2.SerialDisk)
DeleteMountPoint(path, mountPoint string)
DeleteMount(id string)
UpdateMountPoint(m model2.SerialDisk)
RemoveLSBLKCache()
}
type diskService struct {
log loger2.OLog
db *gorm.DB
}
func (d *diskService) RemoveLSBLKCache() {
key := "system_lsblk"
Cache.Delete(key)
}
func (d *diskService) SmartCTL(path string) model.SmartctlA {
key := "system_smart_" + path
if result, ok := Cache.Get(key); ok {
res, ok := result.(model.SmartctlA)
if ok {
return res
}
}
var m model.SmartctlA
str := command2.ExecSmartCTLByPath(path)
if str == nil {
d.log.Error("smartctl exec error,smartctl")
return m
}
err := json2.Unmarshal([]byte(str), &m)
if err != nil {
d.log.Error("json ummarshal error", err)
}
if !reflect.DeepEqual(m, model.SmartctlA{}) {
Cache.Add(key, m, time.Second*10)
}
return m
}
//通过脚本获取外挂磁盘
func (d *diskService) GetPlugInDisk() []string {
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPlugInDisk")
}
//格式化硬盘
func (d *diskService) FormatDisk(path, format string) string {
func (d *diskService) FormatDisk(path, format string) []string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;FormatDisk " + path + " " + format)
fmt.Println(r)
return ""
return r
}
//移除挂载点,删除目录
func (d *diskService) UmountPointAndRemoveDir(path string) string {
func (d *diskService) UmountPointAndRemoveDir(path string) []string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;UMountPorintAndRemoveDir " + path)
fmt.Println(r)
return ""
return r
}
//删除分区
@@ -62,8 +98,7 @@ func (d *diskService) DelPartition(path, num string) string {
//part
func (d *diskService) AddPartition(path string) string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
fmt.Println(r)
command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
return ""
}
@@ -74,21 +109,31 @@ func (d *diskService) AddAllPartition(path string) {
//获取硬盘详情
func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
diskInfo, err := disk.Usage(path + "1")
if err != nil {
fmt.Println(err)
}
fmt.Println(path)
fmt.Println(diskInfo)
diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
return diskInfo
}
//get disk details
func (d *diskService) LSBLK() []model.LSBLKModel {
func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
key := "system_lsblk"
var n []model.LSBLKModel
if result, ok := Cache.Get(key); ok && isUseCache {
res, ok := result.([]model.LSBLKModel)
if ok {
return res
}
}
str := command2.ExecLSBLK()
if str == nil {
d.log.Error("lsblk exec error")
d.log.Error("lsblk exec error,lsblk")
return nil
}
var m []model.LSBLKModel
@@ -97,8 +142,6 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
d.log.Error("json ummarshal error", err)
}
var n []model.LSBLKModel
var c []model.LSBLKModel
var fsused uint64
@@ -136,15 +179,19 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
fsused = 0
}
}
if len(n) > 0 {
Cache.Add(key, n, time.Second*100)
}
return n
}
func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
str := command2.ExecLSBLKByPath(path)
if str == nil {
d.log.Error("lsblk exec error")
d.log.Error("lsblk exec error,str")
return model.LSBLKModel{}
}
var ml []model.LSBLKModel
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
if err != nil {
@@ -152,9 +199,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
d.log.Error("json ummarshal error", err)
return model.LSBLKModel{}
}
//todo 需要判断长度
m := ml[0]
//声明数组
m := model.LSBLKModel{}
if len(ml) > 0 {
m = ml[0]
}
return m
// 下面为计算是否可以继续分区的部分,暂时不需要
chiArr := make(map[string]string)
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + m.Path)
if len(chiList) == 0 {
@@ -165,7 +216,6 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
tempArr := strings.Split(chiList[i], ",")
chiArr[tempArr[0]] = chiList[i]
}
var maxSector uint64 = 0
for i := 0; i < len(m.Children); i++ {
tempArr := strings.Split(chiArr[m.Children[i].Path], ",")
@@ -174,13 +224,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
if m.Children[i].EndSector > maxSector {
maxSector = m.Children[i].EndSector
}
}
diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDiskSizeAndSectors " + m.Path)
if len(diskEndSector) < 2 {
d.log.Error("diskEndSector length error")
}
diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
//添加可以分区情况
@@ -197,13 +247,30 @@ func (d *diskService) MountDisk(path, volume string) {
}
func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
d.db.Save(&m)
d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{})
d.db.Create(&m)
}
func (d *diskService) SerialAll(mountPoint string) *[]model2.SerialDisk {
func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
d.db.Model(&model2.SerialDisk{}).Where("uui = ?", m.UUID).Update("mount_point", m.MountPoint)
}
func (d *diskService) DeleteMount(id string) {
d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
}
func (d *diskService) DeleteMountPoint(path, mountPoint string) {
d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
}
func (d *diskService) GetSerialAll() []model2.SerialDisk {
var m []model2.SerialDisk
d.db.Find(&m)
return &m
return m
}
func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {

View File

@@ -8,7 +8,6 @@ import (
json2 "encoding/json"
"fmt"
"reflect"
"regexp"
"syscall"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -366,11 +365,11 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
// if net != "host" {
// portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
// }
port := ""
//port := ""
for _, portMap := range m.Ports {
if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
port = portMap.ContainerPort
}
// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
// port = portMap.ContainerPort
// }
if portMap.Protocol == "tcp" {
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
@@ -413,7 +412,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
var envArr []string
for _, e := range m.Envs {
if strings.HasPrefix(e.Value, "$") {
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value))
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
continue
}
if len(e.Value) > 0 {
@@ -434,7 +433,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
}
for _, p := range m.Devices {
if len(p.Path) > 0 {
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath})
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
}
}
hostConfingBind := []string{}
@@ -443,27 +442,28 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
for _, v := range m.Volumes {
path := v.Path
if len(path) == 0 {
path = docker.GetDir(containerDbId, v.ContainerPath)
path = docker.GetDir(containerDbId, v.Path)
if len(path) == 0 {
continue
}
}
path = strings.ReplaceAll(path, "$AppID", containerDbId)
reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
result1 := reg1.FindAllStringSubmatch(path, -1)
if len(result1) == 0 {
err = file.IsNotExistMkDir(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
} else {
err = file.IsNotExistCreateFile(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
//result1 := reg1.FindAllStringSubmatch(path, -1)
//if len(result1) == 0 {
err = file.IsNotExistMkDir(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
//}
// else {
// err = file.IsNotExistCreateFile(path)
// if err != nil {
// ds.log.Error("mkdir error", err)
// continue
// }
// }
volumes = append(volumes, mount.Mount{
Type: mount.TypeBind,
@@ -479,24 +479,29 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
if len(m.Restart) > 0 {
rp.Name = m.Restart
}
healthTest := []string{}
if len(port) > 0 {
healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
}
// healthTest := []string{}
// if len(port) > 0 {
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
// }
health := &container.HealthConfig{
Test: healthTest,
StartPeriod: 0,
Retries: 1000,
// health := &container.HealthConfig{
// Test: healthTest,
// StartPeriod: 0,
// Retries: 1000,
// }
// fmt.Print(health)
if len(m.HostName) == 0 {
m.HostName = m.Label
}
fmt.Print(health)
config := &container.Config{
Image: imageName,
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
Env: envArr,
// Healthcheck: health,
Hostname: m.HostName,
Cmd: m.Cmd,
}
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net)}
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net), Privileged: m.Privileged, CapAdd: m.CapAdd}
//if net != "host" {
config.ExposedPorts = ports
hostConfig.PortBindings = portMaps
@@ -754,7 +759,7 @@ func (ds *dockerService) DockerContainerUpdate(m model.CustomizationPostData, id
res.CPUShares = m.CpuShares
}
for _, p := range m.Devices {
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath})
res.Devices = append(res.Devices, container.DeviceMapping{PathOnHost: p.Path, PathInContainer: p.ContainerPath, CgroupPermissions: "rwm"})
}
_, err = cli.ContainerUpdate(context.Background(), id, container.UpdateConfig{RestartPolicy: rp, Resources: res})
if err != nil {

85
service/file.go Normal file
View File

@@ -0,0 +1,85 @@
package service
import (
"context"
"io"
)
// type InteruptReader struct {
// r io.Reader
// interupt chan int
// }
// func NewInteruptReader(r io.Reader) InteruptReader {
// return InteruptReader{
// r,
// make(chan int),
// }
// }
// func (r InteruptReader) Read(p []byte) (n int, err error) {
// if r.r == nil {
// return 0, io.EOF
// }
// select {
// case <-r.interupt:
// return r.r.Read(p)
// default:
// r.r = nil
// return 0, io.EOF
// }
// }
// func (r InteruptReader) Cancel() {
// r.interupt <- 0
// }
type reader struct {
ctx context.Context
r io.Reader
}
// NewReader wraps an io.Reader to handle context cancellation.
//
// Context state is checked BEFORE every Read.
func NewReader(ctx context.Context, r io.Reader) io.Reader {
if r, ok := r.(*reader); ok && ctx == r.ctx {
return r
}
return &reader{ctx: ctx, r: r}
}
func (r *reader) Read(p []byte) (n int, err error) {
select {
case <-r.ctx.Done():
return 0, r.ctx.Err()
default:
return r.r.Read(p)
}
}
type writer struct {
ctx context.Context
w io.Writer
}
type copier struct {
writer
}
func NewWriter(ctx context.Context, w io.Writer) io.Writer {
if w, ok := w.(*copier); ok && ctx == w.ctx {
return w
}
return &copier{writer{ctx: ctx, w: w}}
}
// Write implements io.Writer, but with context awareness.
func (w *writer) Write(p []byte) (n int, err error) {
select {
case <-w.ctx.Done():
return 0, w.ctx.Err()
default:
return w.w.Write(p)
}
}

81
service/file_test.go Normal file
View File

@@ -0,0 +1,81 @@
package service
import (
"context"
"fmt"
"io"
"log"
"os"
"testing"
"time"
)
var ctx context.Context
var cancel context.CancelFunc
func TestNewInteruptReader(t *testing.T) {
ctx, cancel = context.WithCancel(context.Background())
go func() {
// 在初始上下文的基础上创建一个有取消功能的上下文
// ctx, cancel := context.WithCancel(ctx)
fmt.Println("开始")
fIn, err := os.Open("/Users/liangjianli/Downloads/demo_data.tar.gz")
if err != nil {
}
defer fIn.Close()
fmt.Println("创建新文件")
fOut, err := os.Create("/Users/liangjianli/Downloads/demo_data1.tar.gz")
if err != nil {
fmt.Println(err)
}
defer fOut.Close()
fmt.Println("准备复制")
// _, err = io.Copy(out, NewReader(ctx, f))
// time.Sleep(time.Second * 2)
//ctx.Done()
// cancel()
// interrupt context after 500ms
// interrupt context with SIGTERM (CTRL+C)
//sigs := make(chan os.Signal, 1)
//signal.Notify(sigs, os.Interrupt)
if err != nil {
log.Fatal(err)
}
// Reader that fails when context is canceled
in := NewReader(ctx, fIn)
// Writer that fails when context is canceled
out := NewWriter(ctx, fOut)
//time.Sleep(2 * time.Second)
//cancel()
n, err := io.Copy(out, in)
log.Println(n, "bytes copied.")
if err != nil {
fmt.Println("Err:", err)
}
fmt.Println("Closing.")
}()
go func() {
//<-sigs
time.Sleep(time.Second)
fmt.Println("退出")
ddd()
}()
time.Sleep(time.Second * 10)
}
func ddd() {
cancel()
}

View File

@@ -40,7 +40,11 @@ type AppListDBModel struct {
Memory int64 `json:"memory"`
Restart string `json:"restart"`
//Rely model.MapStrings `gorm:"type:json" json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
Origin string `json:"origin"`
Origin string `json:"origin"`
HostName string `json:"host_name"`
Privileged bool `json:"privileged"`
CapAdd string `json:"cap_add"`
Cmd string `gorm:"type:json" json:"cmd"`
}
func (p *AppListDBModel) TableName() string {

View File

@@ -3,10 +3,11 @@ package model
//SerialAdvanced Technology Attachment (STAT)
type SerialDisk struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
DiskId string `json:"disk_id"`
UUID string `json:"uuid"`
Path string `json:"path"`
State int `json:"state"`
MountPoint string `json:"mount_point"`
CreatedAt int64 `json:"created_at"`
}
func (p *SerialDisk) TableName() string {

View File

@@ -6,9 +6,10 @@ type AppNotify struct {
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Id string `json:"id"`
Type int `json:"type"` // 1:显示即为已读 2:info 3:warning 4:error 5:success
Type int `json:"type"`
Icon string `json:"icon"`
Name string `json:"name"`
Class int `json:"class"`
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
}

View File

@@ -1,8 +1,12 @@
package service
import (
json2 "encoding/json"
"time"
"github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gorilla/websocket"
"gorm.io/gorm"
)
@@ -10,8 +14,9 @@ type NotifyServer interface {
GetLog(id string) model.AppNotify
AddLog(log model.AppNotify)
UpdateLog(log model.AppNotify)
UpdateLogByCustomId(log model.AppNotify)
DelLog(id string)
GetList() (list []model.AppNotify)
GetList(c int) (list []model.AppNotify)
MarkRead(id string, state int)
}
@@ -19,8 +24,8 @@ type notifyServer struct {
db *gorm.DB
}
func (i notifyServer) GetList() (list []model.AppNotify) {
i.db.Where("state=? or state=?", types.NOTIFY_DYNAMICE, types.NOTIFY_UNREAD).Find(&list)
func (i notifyServer) GetList(c int) (list []model.AppNotify) {
i.db.Where("class = ?", c).Where(i.db.Where("state = ?", types.NOTIFY_DYNAMICE).Or("state = ?", types.NOTIFY_UNREAD)).Find(&list)
return
}
@@ -31,20 +36,72 @@ func (i *notifyServer) AddLog(log model.AppNotify) {
func (i *notifyServer) UpdateLog(log model.AppNotify) {
i.db.Save(&log)
}
func (i *notifyServer) UpdateLogByCustomId(log model.AppNotify) {
if len(log.CustomId) == 0 {
return
}
i.db.Model(&model.AppNotify{}).Select("*").Where("custom_id = ? ", log.CustomId).Updates(log)
}
func (i *notifyServer) GetLog(id string) model.AppNotify {
var log model.AppNotify
i.db.Where("custom_id = ? ", id).First(&log)
return log
}
func (i *notifyServer) MarkRead(id string, state int) {
i.db.Update("state=", state).Where("custom_id = ? ", id)
if id == "0" {
i.db.Model(&model.AppNotify{}).Where("1 = ?", 1).Update("state", state)
return
}
i.db.Model(&model.AppNotify{}).Where("id = ? ", id).Update("state", state)
}
func (i *notifyServer) DelLog(id string) {
var log model.AppNotify
i.db.Where("custom_id = ?", id).Delete(&log)
}
func SendMeg() {
// for {
// mt, message, err := ws.ReadMessage()
// if err != nil {
// break
// }
// notify := model.NotifyMssage{}
// json2.Unmarshal(message, &notify)
// if notify.Type == "read" {
// service.MyService.Notify().MarkRead(notify.Data, types.NOTIFY_READ)
// }
// if notify.Type == "app" {
// go func(ws *websocket.Conn) {
for {
list := MyService.Notify().GetList(types.NOTIFY_APP)
json, _ := json2.Marshal(list)
if len(list) > 0 {
var temp []*websocket.Conn
for _, v := range WebSocketConns {
err := v.WriteMessage(1, json)
if err == nil {
temp = append(temp, v)
}
}
WebSocketConns = temp
for _, v := range list {
MyService.Notify().MarkRead(v.Id, types.NOTIFY_READ)
}
}
if len(WebSocketConns) == 0 {
SocketRun = false
}
time.Sleep(time.Second * 2)
}
// }(ws)
// }
// }
}
func NewNotifyService(db *gorm.DB) NotifyServer {
return &notifyServer{db: db}
}

117
service/person.go Normal file
View File

@@ -0,0 +1,117 @@
package service
import (
"encoding/json"
"fmt"
"log"
"net"
"reflect"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
)
type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error)
Handshake(m model.ConnectState)
}
type personService struct {
}
var IpInfo model.PersionModel
func PushIpInfo(token string) {
m := model.PersionModel{}
m.Ips = 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) Handshake(m model.ConnectState) {
//1先进行udp打通成功
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: 9901} //注意端口必须固定
dstAddr := &net.UDPAddr{
IP: net.ParseIP(config.ServerInfo.Handshake), Port: 9527}
//DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6"如果laddr不是nil将使用它作为本地地址否则自动选择一个本地地址。
//(conn)UDPConn代表一个UDP网络连接实现了Conn和PacketConn接口
conn, err := net.DialUDP("udp", srcAddr, dstAddr)
if err != nil {
fmt.Println(err)
}
b, _ := json.Marshal(m)
if _, err = conn.Write(b); err != nil {
fmt.Println(err)
}
data := make([]byte, 1024)
//ReadFromUDP从c读取一个UDP数据包将有效负载拷贝到b返回拷贝字节数和数据包来源地址。
//ReadFromUDP方***在超过一个固定的时间点之后超时,并返回一个错误。
n, _, err := conn.ReadFromUDP(data)
if err != nil {
fmt.Printf("error during read: %s", err)
}
conn.Close()
toPersion := model.PersionModel{}
err = json.Unmarshal(data[:n], &toPersion)
if err != nil {
fmt.Println(err)
}
// bidirectionHole(srcAddr, &anotherPeer)
//2udp打洞成功向服务器汇报打洞结果
//3转udp打洞
}
func bidirectionHole(srcAddr *net.UDPAddr, anotherAddr *net.UDPAddr) {
conn, err := net.DialUDP("udp", srcAddr, anotherAddr)
if err != nil {
fmt.Println("send handshake:", err)
}
go func() {
for {
time.Sleep(10 * time.Second)
if _, err = conn.Write([]byte("from []")); err != nil {
log.Println("send msg fail", err)
}
}
}()
for {
data := make([]byte, 1024)
n, _, err := conn.ReadFromUDP(data)
if err != nil {
log.Printf("error during read:%s\n", err)
} else {
log.Printf("收到数据:%s\n", data[:n])
}
}
}
func NewPersonService() PersonService {
return &personService{}
}

View File

@@ -2,6 +2,7 @@ package service
import (
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gorilla/websocket"
"github.com/patrickmn/go-cache"
"gorm.io/gorm"
)
@@ -10,6 +11,10 @@ var Cache *cache.Cache
var MyService Repository
var WebSocketConns []*websocket.Conn
var SocketRun bool
type Repository interface {
App() AppService
DDNS() DDNSService
@@ -27,6 +32,7 @@ type Repository interface {
System() SystemService
Shortcuts() ShortcutsService
Search() SearchService
Person() PersonService
}
func NewService(db *gorm.DB, log loger2.OLog) Repository {
@@ -48,6 +54,7 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
system: NewSystemService(log),
shortcuts: NewShortcutsService(db),
search: NewSearchService(),
person: NewPersonService(),
}
}
@@ -68,6 +75,7 @@ type store struct {
system SystemService
shortcuts ShortcutsService
search SearchService
person PersonService
}
func (c *store) Rely() RelyService {
@@ -76,6 +84,9 @@ func (c *store) Rely() RelyService {
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

@@ -2,6 +2,7 @@ package service
import (
"io/ioutil"
"net"
"os"
"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -16,6 +17,7 @@ type SystemService interface {
GetCasaOSLogs(lineNumber int) string
UpdateAssist()
UpSystemPort(port string)
GetTimeZone() string
}
type systemService struct {
log loger.OLog
@@ -30,6 +32,11 @@ func (s *systemService) UpdateSystemVersion(version string) {
func (s *systemService) UpdateAssist() {
s.log.Error(command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/assist.sh"))
}
func (s *systemService) GetTimeZone() string {
return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetTimeZone")
}
func (s *systemService) GetSystemConfigDebug() []string {
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetSysInfo")
}
@@ -65,6 +72,21 @@ func (s *systemService) GetCasaOSLogs(lineNumber int) string {
return string(content)
}
func GetDeviceAllIP() []string {
var address []string
addrs, err := net.InterfaceAddrs()
if err != nil {
return address
}
for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To16() != nil {
address = append(address, ipNet.IP.String())
}
}
}
return address
}
func NewSystemService(log loger.OLog) SystemService {
return &systemService{log: log}
}

View File

@@ -28,10 +28,6 @@ func (c *user) SetUser(username, pwd, token, email, desc string) error {
config.Cfg.Section("user").Key("PWD").SetValue(pwd)
config.UserInfo.PWD = pwd
}
if len(token) > 0 {
config.Cfg.Section("user").Key("Token").SetValue(token)
config.UserInfo.Token = token
}
if len(email) > 0 {
config.Cfg.Section("user").Key("Email").SetValue(email)
config.UserInfo.Email = email

View File

@@ -4,18 +4,20 @@ import (
"bytes"
"errors"
"fmt"
"github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/zerotier"
"github.com/PuerkitoBio/goquery"
"github.com/tidwall/gjson"
"io/ioutil"
"math/rand"
"net/http"
"strconv"
"strings"
"time"
"unicode"
"github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/zerotier"
"github.com/PuerkitoBio/goquery"
"github.com/tidwall/gjson"
)
type ZeroTierService interface {
@@ -33,6 +35,7 @@ type ZeroTierService interface {
DeleteMember(token string, id, mId string) interface{}
DeleteNetwork(token, id string) interface{}
GetJoinNetworks() string
NetworkIdFilter(letter rune) bool
}
type zerotierStruct struct {
}
@@ -333,6 +336,13 @@ func (c *zerotierStruct) GetJoinNetworks() string {
return json
}
func (c *zerotierStruct) NetworkIdFilter(letter rune) bool {
if unicode.IsNumber(letter) || unicode.IsLetter(letter) {
return true
} else {
return false
}
}
func NewZeroTierService() ZeroTierService {
//初始化client
client = http.Client{Timeout: 30 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error {

View File

@@ -7,6 +7,7 @@ import (
"runtime"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -84,12 +85,12 @@ func (c *zima) GetDirPath(path string) []model.Path {
ls, _ := ioutil.ReadDir(path)
dirs := []model.Path{}
if strings.Count(path, "/") > 0 {
if len(path) > 0 {
for _, l := range ls {
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir()})
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir(), Date: l.ModTime()})
}
} else {
dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true})
dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
}
return dirs
}

View File

@@ -9,4 +9,32 @@ version_0_2_3() {
}
# add in v0.2.5
readonly CASA_DEPANDS="curl smartmontools parted fdisk ntfs-3g"
version_0_2_5() {
install_depends "$CASA_DEPANDS"
}
#Install Depends
install_depends() {
((EUID)) && sudo_cmd="sudo"
if [[ ! -x "$(command -v '$1')" ]]; then
packagesNeeded=$1
if [ -x "$(command -v apk)" ]; then
$sudo_cmd apk add --no-cache $packagesNeeded
elif [ -x "$(command -v apt-get)" ]; then
$sudo_cmd apt-get -y -q install $packagesNeeded
elif [ -x "$(command -v dnf)" ]; then
$sudo_cmd dnf install $packagesNeeded
elif [ -x "$(command -v zypper)" ]; then
$sudo_cmd zypper install $packagesNeeded
fi
fi
}
version_0_2_3
version_0_2_5

View File

@@ -30,6 +30,11 @@ GetNetCard() {
fi
}
GetTimeZone(){
timedatectl | grep "Time zone" | awk '{print $3}'
}
#查看网卡状态
#param 网卡名称
CatNetCardState() {
@@ -68,10 +73,8 @@ UMountPorintAndRemoveDir() {
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
umount -l ${DEVICE}
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
umount -lf ${DEVICE}
/bin/rmdir "${MOUNT_POINT}"
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
fi
}
@@ -84,11 +87,11 @@ FormatDisk() {
elif [ "$2" == "ntfs" ]; then
mkfs.ntfs $1
elif [ "$2" == "ext4" ]; then
mkfs.ext4 -F $1
mkfs.ext4 -m 1 -F $1
elif [ "$2" == "exfat" ]; then
mkfs.exfat $1
else
mkfs.ext4 -F $1
mkfs.ext4 -m 1 -F $1
fi
}
@@ -112,13 +115,11 @@ AddPartition() {
parted -s $1 mklabel gpt
parted -s $1 mkpart primary ext4 0 100%
mkfs.ext4 $11
PATH=`lsblk -r $1 | sort | grep part | head -n 1 | awk '{print $1}'`
mkfs.ext4 -m 1 /dev/${PATH}
partprobe $1
# mount $11 $2
}
#磁盘类型
@@ -143,20 +144,20 @@ GetDiskHealthState() {
#result bytes
#result sectors
GetDiskSizeAndSectors() {
fdisk $1 -l | grep "/dev/sda:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
fdisk $1 -l | grep "$1:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
}
#获取磁盘分区数据扇区
#param 磁盘路径 /dev/sda
#result start,end,sectors
GetPartitionSectors() {
fdisk $1 -l | grep "/dev/sda[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
fdisk $1 -l | grep "$1[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
}
#检查没有使用的挂载点删除文件夹
AutoRemoveUnuseDir() {
DIRECTORY="/mnt/"
dir=$(ls -l $DIRECTORY | awk '/^d/ {print $NF}')
DIRECTORY="/DATA/"
dir=$(ls -l $DIRECTORY | grep "Storage[0-9]" | awk '/^d/ {print $NF}')
for i in $dir; do
path="$DIRECTORY$i"
@@ -183,7 +184,7 @@ do_mount() {
DEVBASE=$1
DEVICE="${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
MOUNT_POINT=$(lsblk -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
if [ -n "${MOUNT_POINT}" ]; then
${log} "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
@@ -194,7 +195,7 @@ do_mount() {
eval $(blkid -o udev ${DEVICE} | grep -i -e "ID_FS_LABEL" -e "ID_FS_TYPE")
LABEL=$2
if grep -q " /media/${LABEL} " /etc/mtab; then
if grep -q " ${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
@@ -205,7 +206,7 @@ do_mount() {
DEV_LABEL="${DEVBASE}"
fi
MOUNT_POINT="/media/${DEV_LABEL}"
MOUNT_POINT="${DEV_LABEL}"
${log} "Mount point: ${MOUNT_POINT}"
@@ -233,3 +234,94 @@ do_mount() {
;;
esac
}
# $1=sda1
do_umount() {
log="logger -t usb-mount.sh -s "
DEVBASE=$1
DEVICE="${DEVBASE}"
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
umount -l ${DEVICE}
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
/bin/rmdir "${MOUNT_POINT}"
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
fi
}
# $1=/mnt/volume1/data.img
# $2=100G
PackageDocker() {
image=$1
docker="/mnt/casa_docker"
#判断目录docker存在不存在则创建,存在检查是否为空
if [ ! -d "$docker" ]; then
mkdir ${docker}
fi
if [ "$(ls -A $docker)" = "" ]; then
echo "$docker count is 0"
else
mkdir ${docker}_bak
mv -r ${docker} ${docker}_bak
fi
daemon="/etc/docker/daemon.json"
#1创建img文件在挂载的目录
fallocate -l $2 $image
#2初始化img文件
mkfs -t ext4 $image
#3挂载img文件
sudo mount -o loop $image $docker
#4给移动/var/lib/docker数据到img挂载的目录
systemctl stop docker.socket
systemctl stop docker
cp -r /var/lib/docker/* ${docker}/
#5在/etc/docker写入daemon.json(需要检查)
if [ -d "$daemon" ]; then
mv -r $daemon ${daemon}.bak
fi
echo "{\"data-root\": \"$docker\"}" >$daemon
#删除老数据腾出空间
#rm -fr /var/lib/docker
systemctl start docker.socket
systemctl start docker
}
DockerImgMove() {
image=$1
systemctl stop docker.socket
systemctl stop docker
sudo umount -f $image
}
GetDockerDataRoot() {
docker info | grep "Docker Root Dir:"
}
SetLink() {
ln -s /mnt/casa_sda1/AppData /DATA/AppData
#删除所有软链
find /DATA -type l -delete
}
#压缩文件夹
TarFolder() {
#压缩
tar -zcvf data.tar.gz -C/DATA/ AppDataBak/
#解压
tar zxvf data.tar.gz
#查看某文件夹下的所有包括子文件夹文件
ls /DATA/Media -lR | grep "^-" | wc -l
# ls -lR|grep "^d"| wc -l 查看某个文件夹下文件夹的个数,包括子文件夹下的文件夹个数。
#查看固定文件夹大小
du -sh /DATA
}

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# copy to /casaOS/util/shell path
# chmod 755
@@ -12,7 +12,7 @@ DEVBASE=$2
DEVICE="/dev/${DEVBASE}"
# See if this drive is already mounted, and if so where
MOUNT_POINT=$(mount | grep ${DEVICE} | awk '{ print $3 }')
MOUNT_POINT=$(lsblk -o name,mountpoint | grep ${DEVICE} | awk '{print $2}')
do_mount() {
@@ -30,23 +30,32 @@ do_mount() {
# Figure out a mount point to use
# LABEL=${ID_FS_LABEL}
LABEL=${DEVBASE}
if grep -q " /mnt/casa_${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
DEV_LABEL="${LABEL}"
# LABEL=${DEVBASE}
# if grep -q " /DATA/USB_${LABEL} " /etc/mtab; then
# # Already in use, make a unique one
# LABEL+="-${DEVBASE}"
# fi
# DEV_LABEL="${LABEL}"
# Use the device name in case the drive doesn't have label
if [ -z ${DEV_LABEL} ]; then
DEV_LABEL="${DEVBASE}"
fi
# # Use the device name in case the drive doesn't have label
# if [ -z ${DEV_LABEL} ]; then
# DEV_LABEL="${DEVBASE}"
# fi
MOUNT_POINT="/mnt/casa_${DEV_LABEL}"
MOUNT_POINT="/DATA/USB_Storage1"
arr=("/DATA/USB_Storage1" "/DATA/USB_Storage2" "/DATA/USB_Storage3" "/DATA/USB_Storage4" "/DATA/USB_Storage5" "/DATA/USB_Storage6" "/DATA/USB_Storage7" "/DATA/USB_Storage8" "/DATA/USB_Storage9" "/DATA/USB_Storage10" "/DATA/USB_Storage11" "/DATA/USB_Storage12")
for folder in ${arr[@]}; do
#如果文件夹不存在,创建文件夹
if [ ! -d "$folder" ]; then
mkdir -p ${folder}
MOUNT_POINT=$folder
break
fi
done
${log} "Mount point: ${MOUNT_POINT}"
mkdir -p ${MOUNT_POINT}
# # Global mount options
# OPTS="rw,relatime"
@@ -84,7 +93,7 @@ do_mount() {
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
;;
*)
/bin/rmdir "${MOUNT_POINT}"
/bin/rmdir "${MOUNT_POINT}"
exit 0
;;
esac

View File

@@ -11,3 +11,7 @@ const (
NOTIFY_TYPE_ERROR
NOTIFY_TYPE_INSTALL_LOG
)
const (
NOTIFY_APP = iota
)

View File

@@ -1,4 +1,5 @@
package types
const CURRENTVERSION = "0.2.3"
const BODY = "<li>Add detailed CPU and memory statistics.</li><li>Add the multi-language function and add Chinese translation.</li><li>Add the function to modify the search engine.</li><li>Add the function of modifying the WebUI port</li><li>fixed some bugs</li><li>Preprocessing usb automounting</li><li>Update update script</li>"
const CURRENTVERSION = "0.2.9"
const BODY = "<li>Custom installation of new parameters</li><li>Fixed issues</li><li>Update front-end translation</li>"

BIN
web/img/USB.3ba78dec.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -15,7 +15,7 @@
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="/ui/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@mdi/font@6.2.95/css/materialdesignicons.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@mdi/font@6.5.95/css/materialdesignicons.min.css">
<title>
CasaOS
</title>

View File

@@ -214,7 +214,7 @@ eval("module.exports = __webpack_require__.p + \"img/Account.1bc4a418.png\";\n\n
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
/***/ })

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