mirror of
https://github.com/IceWhaleTech/CasaOS.git
synced 2025-12-23 13:04:42 +00:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63c6c2cebb | ||
|
|
6cba025679 | ||
|
|
d25b93c972 | ||
|
|
b14861703c | ||
|
|
32604225ce | ||
|
|
f623b29c38 | ||
|
|
94ae6ee8ec | ||
|
|
5115bf72e1 | ||
|
|
e1a928cd78 | ||
|
|
3977519c43 | ||
|
|
2f87834ac9 | ||
|
|
53335012d8 | ||
|
|
9d6302f7e3 | ||
|
|
20950e2a60 | ||
|
|
0e0e507f8f | ||
|
|
46e14617b6 | ||
|
|
903c73fafb | ||
|
|
42a56df4a5 | ||
|
|
493dc5c032 | ||
|
|
9a73bc2a18 | ||
|
|
55a9acd9f6 | ||
|
|
d060968b7a | ||
|
|
88a7f53130 | ||
|
|
26e5b18a5d | ||
|
|
011ace96f6 | ||
|
|
5c00655d14 | ||
|
|
eb36c262db | ||
|
|
29d1861545 | ||
|
|
3c9b410693 | ||
|
|
4c3b41433b | ||
|
|
1fd13668c0 | ||
|
|
d1ab7261a6 | ||
|
|
0fc65bcb3a | ||
|
|
f1ce8bfd99 | ||
|
|
3f472f1864 | ||
|
|
229d94cae7 | ||
|
|
c28e1bbf93 | ||
|
|
a840029000 | ||
|
|
aad2646cf2 | ||
|
|
ca1f8ad73e | ||
|
|
dea02763a2 | ||
|
|
ea67385a64 | ||
|
|
fa2daa2767 | ||
|
|
fcb906aa85 | ||
|
|
489a617126 | ||
|
|
601e7ce10b | ||
|
|
4a6fc9a945 | ||
|
|
b377af1d24 | ||
|
|
3fc00f8da7 | ||
|
|
6e39fe5f8c | ||
|
|
20c240a123 | ||
|
|
3ea9fc0de0 | ||
|
|
b80b08ef07 | ||
|
|
505af8d101 | ||
|
|
ae35a6d291 | ||
|
|
2b95c07a47 | ||
|
|
27a011e715 | ||
|
|
476831a12f | ||
|
|
9675eff69e | ||
|
|
85a044246e | ||
|
|
5c41fbcf3d | ||
|
|
6baab7a525 | ||
|
|
ab3b5a9077 | ||
|
|
5811c271b2 | ||
|
|
cf5387346d |
6
.github/workflows/casa.yml
vendored
6
.github/workflows/casa.yml
vendored
@@ -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
|
||||
|
||||
2
UI
2
UI
Submodule UI updated: f3088b6354...106902c76a
@@ -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
10
go.mod
@@ -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
16
go.sum
@@ -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=
|
||||
|
||||
6
main.go
6
main.go
@@ -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()
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ type ServerAppList struct {
|
||||
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 {
|
||||
|
||||
@@ -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
6
model/heart.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type CasaOSHeart struct {
|
||||
UuId string `json:"uuid"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
@@ -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
6
model/notify.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type NotifyMssage struct {
|
||||
Type string `json:"type"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
19
model/person.go
Normal file
19
model/person.go
Normal 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
69
model/smartctl_model.go
Normal 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"`
|
||||
}
|
||||
@@ -24,6 +24,8 @@ type ServerModel struct {
|
||||
RunMode string
|
||||
ServerApi string
|
||||
LockAccount bool
|
||||
Handshake string
|
||||
Token string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package command
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
func OnlyExec(cmdStr string) {
|
||||
@@ -85,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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
|
||||
@@ -3,6 +3,7 @@ package route
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -24,6 +25,8 @@ func InitFunction() {
|
||||
Update2_3()
|
||||
CheckSerialDiskMount()
|
||||
|
||||
CheckToken2_9()
|
||||
|
||||
}
|
||||
|
||||
var syncIsExistence = false
|
||||
@@ -34,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"
|
||||
@@ -84,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)
|
||||
}
|
||||
@@ -101,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
|
||||
}
|
||||
@@ -170,7 +172,7 @@ func checkSystemApp() {
|
||||
path := ""
|
||||
for _, i := range paths {
|
||||
if i.ContainerPath == "/config" {
|
||||
path = docker.GetDir(v.CustomId, i.Path) + "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)
|
||||
@@ -195,25 +197,50 @@ func CheckSerialDiskMount() {
|
||||
// check mount point
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
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 {
|
||||
mountPoint[h.MountPoint] = "1"
|
||||
if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
|
||||
if m, ok := mountPoint[h.UUID]; ok {
|
||||
//mount point check
|
||||
volume := m
|
||||
if !file.CheckNotExist(m) {
|
||||
for i := 0; file.CheckNotExist(volume); i++ {
|
||||
volume = m + strconv.Itoa(i+1)
|
||||
}
|
||||
}
|
||||
service.MyService.Disk().MountDisk(h.Path, volume)
|
||||
if volume != m {
|
||||
ms := model2.SerialDisk{}
|
||||
ms.UUID = v.UUID
|
||||
ms.MountPoint = volume
|
||||
service.MyService.Disk().UpdateMountPoint(ms)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remount
|
||||
for _, item := range dbList {
|
||||
if _, ok := mountPoint[item.MountPoint]; !ok {
|
||||
service.MyService.Disk().MountDisk(item.Path, item.MountPoint)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -206,42 +208,44 @@ 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.PUT("/move", v1.PutFileMove)
|
||||
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
|
||||
v1FileGroup.DELETE("delete", v1.DeleteFile)
|
||||
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
||||
}
|
||||
v1DiskGroup := v1Group.Group("/disk")
|
||||
v1DiskGroup.Use()
|
||||
{
|
||||
v1DiskGroup.GET("/check", v1.GetDiskCheck)
|
||||
//获取磁盘列表
|
||||
v1DiskGroup.GET("/list", v1.GetPlugInDisk)
|
||||
|
||||
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)
|
||||
v1DiskGroup.GET("/usb", v1.GetUSBList)
|
||||
|
||||
//mount SATA disk
|
||||
v1DiskGroup.POST("/mount", v1.PostMountDisk)
|
||||
|
||||
//umount SATA disk
|
||||
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
|
||||
v1DiskGroup.DELETE("/remove/:id", v1.DeleteDisk)
|
||||
}
|
||||
v1ShareGroup := v1Group.Group("/share")
|
||||
v1ShareGroup.Use()
|
||||
@@ -280,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)
|
||||
|
||||
|
||||
@@ -35,25 +35,26 @@ func AppList(c *gin.Context) {
|
||||
t := c.DefaultQuery("type", "rank")
|
||||
categoryId := c.DefaultQuery("category_id", "0")
|
||||
key := c.DefaultQuery("key", "")
|
||||
recommend, list, community := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
|
||||
for i := 0; i < len(recommend); i++ {
|
||||
ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
|
||||
if ct != nil {
|
||||
list[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 {
|
||||
list[i].State = ct.State
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -137,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) {
|
||||
|
||||
311
route/v1/disk.go
311
route/v1/disk.go
@@ -1,10 +1,16 @@
|
||||
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"
|
||||
@@ -12,18 +18,143 @@ import (
|
||||
"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
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
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
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: list})
|
||||
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
|
||||
@@ -35,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))
|
||||
@@ -60,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 "for example /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)})
|
||||
}
|
||||
|
||||
@@ -115,23 +267,77 @@ 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)})
|
||||
}
|
||||
|
||||
@@ -149,7 +355,7 @@ func PostMountDisk(c *gin.Context) {
|
||||
path := c.PostForm("path")
|
||||
serial := c.PostForm("serial")
|
||||
|
||||
mountPath := "/mnt/volume"
|
||||
mountPath := "/DATA/volume"
|
||||
var list = service.MyService.Disk().GetSerialAll()
|
||||
var pathMapList = make(map[string]string, len(list))
|
||||
for _, v := range list {
|
||||
@@ -165,13 +371,13 @@ func PostMountDisk(c *gin.Context) {
|
||||
|
||||
//mount dir
|
||||
service.MyService.Disk().MountDisk(path, mountPath)
|
||||
//save to data
|
||||
|
||||
m := model2.SerialDisk{}
|
||||
m.MountPoint = mountPath
|
||||
m.Path = path
|
||||
m.Serial = serial
|
||||
m.UUID = serial
|
||||
m.State = 0
|
||||
service.MyService.Disk().SaveMountPoint(m)
|
||||
//service.MyService.Disk().SaveMountPoint(m)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -180,19 +386,35 @@ func PostMountDisk(c *gin.Context) {
|
||||
// @Accept multipart/form-data
|
||||
// @Tags disk
|
||||
// @Security ApiKeyAuth
|
||||
// @Param path formData string true "for example: /dev/sda1"
|
||||
// @Param mount_point formData string true "for example: /mnt/volume1"
|
||||
// @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) {
|
||||
|
||||
//
|
||||
path := c.PostForm("path")
|
||||
mountPoint := c.PostForm("mount_point")
|
||||
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)})
|
||||
}
|
||||
|
||||
@@ -220,7 +442,7 @@ func DeleteDisk(c *gin.Context) {
|
||||
func GetDiskCheck(c *gin.Context) {
|
||||
|
||||
dbList := service.MyService.Disk().GetSerialAll()
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
list := service.MyService.Disk().LSBLK(true)
|
||||
|
||||
mapList := make(map[string]string)
|
||||
|
||||
@@ -229,7 +451,7 @@ func GetDiskCheck(c *gin.Context) {
|
||||
}
|
||||
|
||||
for _, v := range dbList {
|
||||
if _, ok := mapList[v.Serial]; !ok {
|
||||
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
|
||||
@@ -238,3 +460,38 @@ func GetDiskCheck(c *gin.Context) {
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -253,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 {
|
||||
@@ -441,6 +445,8 @@ func InstallApp(c *gin.Context) {
|
||||
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,
|
||||
@@ -468,9 +474,13 @@ 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
|
||||
@@ -714,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 {
|
||||
//
|
||||
@@ -754,6 +764,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)})
|
||||
|
||||
}
|
||||
@@ -925,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
|
||||
@@ -1043,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)
|
||||
|
||||
@@ -1138,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 需要自定义错误
|
||||
@@ -1161,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{}
|
||||
@@ -1182,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})
|
||||
}
|
||||
|
||||
|
||||
143
route/v1/file.go
143
route/v1/file.go
@@ -9,8 +9,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
@@ -127,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) {
|
||||
@@ -165,7 +164,6 @@ func GetDownloadFile(c *gin.Context) {
|
||||
c.Header("Content-Transfer-Encoding", "binary")
|
||||
|
||||
c.File(filePath)
|
||||
return
|
||||
}
|
||||
|
||||
// @Summary 获取目录列表
|
||||
@@ -177,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) {
|
||||
@@ -202,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) {
|
||||
@@ -240,82 +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)})
|
||||
}
|
||||
|
||||
func PutFileMove(c *gin.Context) {
|
||||
from := "/Users/liangjianli/go/CasaOS"
|
||||
to := "/Users/liangjianli/go/CasaOS/test"
|
||||
//t := 1 //是否覆盖
|
||||
|
||||
//方法体
|
||||
stopCh := make(chan int)
|
||||
f, err := os.Stat(from)
|
||||
if err != nil {
|
||||
//未拿到文件信息
|
||||
fmt.Println("stat", err)
|
||||
// @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 f.IsDir() {
|
||||
//from 是文件夹,定义to也是文件夹
|
||||
if list, err := ioutil.ReadDir(from); err == nil {
|
||||
for _, v := range list {
|
||||
time.Sleep(time.Second)
|
||||
if err = Copy(stopCh, filepath.Join(from, v.Name()), filepath.Join(to, v.Name())); err != nil {
|
||||
fmt.Printf("copy %s ,err %d", v.Name(), err)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
p := filepath.Dir(to)
|
||||
if _, err = os.Stat(p); err != nil {
|
||||
if err = os.MkdirAll(p, 0777); err != nil {
|
||||
fmt.Println("mkdir", err)
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(from)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("open file error ", err)
|
||||
}
|
||||
defer file.Close()
|
||||
out, err := os.Create(to)
|
||||
if err != nil {
|
||||
fmt.Println("create to file err", err)
|
||||
}
|
||||
defer out.Close()
|
||||
io.Copy(out, file)
|
||||
time.Sleep(time.Second * 4)
|
||||
close(stopCh)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
func Copy(stop chan int, from, to string) error {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return nil
|
||||
default:
|
||||
fmt.Println(from)
|
||||
|
||||
}
|
||||
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
|
||||
}
|
||||
return nil
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
@@ -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
25
route/v1/persion.go
Normal 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)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -107,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()
|
||||
@@ -234,10 +259,104 @@ func PostKillCasaOS(c *gin.Context) {
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/info [get]
|
||||
func Info(c *gin.Context) {
|
||||
var data = make(map[string]interface{}, 5)
|
||||
var data = make(map[string]interface{}, 6)
|
||||
|
||||
list := service.MyService.Disk().LSBLK()
|
||||
data["disk"] = list
|
||||
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{})
|
||||
|
||||
@@ -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)})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@@ -13,11 +14,12 @@ import (
|
||||
)
|
||||
|
||||
type CasaService interface {
|
||||
GetServerList(index, size, tp, categoryId, key string) (recommend, list, community []model.ServerAppList)
|
||||
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 {
|
||||
@@ -45,9 +47,9 @@ func (o *casaService) GetTaskList(size int) []model2.TaskDBModel {
|
||||
return list
|
||||
}
|
||||
|
||||
func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (recommend, list, community []model.ServerAppList) {
|
||||
func (o *casaService) GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList) {
|
||||
|
||||
keyName := fmt.Sprintf("list_%s_%s_%s_%s", index, size, tp, categoryId)
|
||||
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)
|
||||
@@ -63,7 +65,7 @@ func (o *casaService) GetServerList(index, size, tp, categoryId, key string) (re
|
||||
|
||||
head["Authorization"] = GetToken()
|
||||
|
||||
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/newlist?index="+index+"&size="+size+"&rank="+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)
|
||||
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.list").String()), &list)
|
||||
json2.Unmarshal([]byte(gjson.Get(listS, "data.recommend").String()), &recommend)
|
||||
@@ -88,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+"/v2/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)
|
||||
@@ -124,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{}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -19,9 +20,10 @@ 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
|
||||
@@ -31,30 +33,60 @@ type DiskService interface {
|
||||
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
|
||||
}
|
||||
|
||||
//删除分区
|
||||
@@ -66,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 ""
|
||||
}
|
||||
|
||||
@@ -78,23 +109,21 @@ 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 {
|
||||
if result, ok := Cache.Get(key); ok && isUseCache {
|
||||
|
||||
res, ok := result.([]model.LSBLKModel)
|
||||
if ok {
|
||||
@@ -151,7 +180,7 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
|
||||
}
|
||||
}
|
||||
if len(n) > 0 {
|
||||
Cache.Add(key, n, time.Second*10)
|
||||
Cache.Add(key, n, time.Second*100)
|
||||
}
|
||||
return n
|
||||
}
|
||||
@@ -162,6 +191,7 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
|
||||
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 {
|
||||
@@ -169,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 {
|
||||
@@ -182,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], ",")
|
||||
@@ -191,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 {
|
||||
//添加可以分区情况
|
||||
@@ -214,9 +247,14 @@ func (d *diskService) MountDisk(path, volume string) {
|
||||
}
|
||||
|
||||
func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
|
||||
d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{})
|
||||
d.db.Create(&m)
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -224,7 +262,7 @@ func (d *diskService) DeleteMount(id string) {
|
||||
|
||||
func (d *diskService) DeleteMountPoint(path, mountPoint string) {
|
||||
|
||||
d.db.Delete(&model2.SerialDisk{}).Where("path= ? && mount_point = ?", path, mountPoint)
|
||||
d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
|
||||
|
||||
command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
|
||||
}
|
||||
|
||||
@@ -433,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{}
|
||||
@@ -490,13 +490,18 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
||||
// Retries: 1000,
|
||||
// }
|
||||
// fmt.Print(health)
|
||||
if len(m.HostName) == 0 {
|
||||
m.HostName = m.Label
|
||||
}
|
||||
config := &container.Config{
|
||||
Image: imageName,
|
||||
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
|
||||
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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -3,10 +3,11 @@ package model
|
||||
//SerialAdvanced Technology Attachment (STAT)
|
||||
type SerialDisk struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
Serial string `json:"serial"`
|
||||
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 {
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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, ¬ify)
|
||||
// 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 ¬ifyServer{db: db}
|
||||
}
|
||||
|
||||
117
service/person.go
Normal file
117
service/person.go
Normal 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{}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
@@ -71,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}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,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
|
||||
}
|
||||
|
||||
@@ -89,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
|
||||
}
|
||||
|
||||
@@ -117,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
|
||||
|
||||
}
|
||||
|
||||
#磁盘类型
|
||||
@@ -148,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"
|
||||
@@ -188,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}"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,3 +11,7 @@ const (
|
||||
NOTIFY_TYPE_ERROR
|
||||
NOTIFY_TYPE_INSTALL_LOG
|
||||
)
|
||||
|
||||
const (
|
||||
NOTIFY_APP = iota
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package types
|
||||
|
||||
const CURRENTVERSION = "0.2.4"
|
||||
const BODY = "<li>New App Store</li><li>Fix minor bugs</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
BIN
web/img/USB.3ba78dec.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
web/img/storage.d487ddb6.png
Normal file
BIN
web/img/storage.d487ddb6.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -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>
|
||||
|
||||
@@ -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?");
|
||||
|
||||
/***/ })
|
||||
|
||||
|
||||
1686
web/js/2.js
1686
web/js/2.js
File diff suppressed because one or more lines are too long
10
web/js/3.js
10
web/js/3.js
File diff suppressed because one or more lines are too long
10
web/js/4.js
10
web/js/4.js
File diff suppressed because one or more lines are too long
166
web/js/app.js
166
web/js/app.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user