Compare commits

..

185 Commits

Author SHA1 Message Date
link
0dacc5db12 Merge pull request #141 from igorpecovnik/patch-1
Tested on Rockpro64, Odroid C2, Neo2, Cubox-i, amd64
2022-04-06 12:14:38 +08:00
link
fcbff194d2 Merge branch 'main' into patch-1 2022-04-06 12:14:31 +08:00
link
04e93b0e3c Merge pull request #138 from alvarosamudio/main
add a new OS to systems
2022-04-06 12:12:07 +08:00
link
2eff7fa8bc Merge pull request #148 from IceWhaleTech/dev
Dev
2022-04-06 12:11:39 +08:00
link
dd0645ee0f Add CasaConnect function 2022-04-06 12:10:51 +08:00
Igor Pečovnik
c93aa6286e Tested on Rockpro64, Odroid C2, Neo2, Cubox-i, x86
Basically it should work on all.
https://www.armbian.com/download/
https://docs.armbian.com/#what-is-the-difference-between-armbian-and-debianubuntu
2022-03-29 15:57:16 +02:00
Alvaro Samudio
bf7b32309f add Elementary OS 6.1 Jólnir to systems 2022-03-25 14:49:21 +00:00
Alvaro Samudio
cd779448ce add Deepin to systems 2022-03-25 14:41:05 +00:00
link
c3b2c1d599 Merge branch 'main' into dev 2022-03-18 11:41:04 +08:00
link
b7949e100f Merge Branches 2022-03-18 11:40:38 +08:00
link
80d24570d6 Merge pull request #130 from IceWhaleTech/Adding-ipv6-Support
fixed
2022-03-18 11:31:05 +08:00
link
539b72a388 fixed 2022-03-18 11:30:06 +08:00
link
a7d15a896e Need to fix bugs 2022-03-18 11:13:07 +08:00
link
9796c5aad7 prepare for test 2022-03-16 15:41:14 +08:00
link
892cd99eb3 Add some acquaintance network interface 2022-03-11 18:01:09 +08:00
link
02cb4cd392 Merge pull request #126 from IceWhaleTech/dev
fixed file upload bug
2022-03-10 16:26:00 +08:00
link
9213f9e379 fixed file upload bug 2022-03-10 16:25:33 +08:00
link
4473056d5c Merge pull request #125 from IceWhaleTech/dev
upload file manage
2022-03-10 13:41:15 +08:00
link
07e96511cd upload file manage 2022-03-10 13:40:42 +08:00
link
ce1dc52bc2 Merge pull request #123 from IceWhaleTech/dev
update file
2022-03-09 19:44:47 +08:00
link
d890b16644 update file 2022-03-09 19:44:08 +08:00
link
5737936318 Merge pull request #122 from IceWhaleTech/dev
Dev
2022-03-09 16:38:18 +08:00
link
33acfababd new file manager
Added CasaOS own file manager, now you can browse, upload, download files from the system, even edit code online, preview photos and videos through it. It will appear in the first position of Apps.
Added CPU core count display and memory capacity display.
2022-03-09 16:37:03 +08:00
link
28c1a52171 Determine the hole punching technique 2022-02-28 14:14:39 +08:00
link
892eef424c Merge branch 'main' into dev 2022-02-18 19:14:30 +08:00
link
f3c73ba79b Update usb-mount.sh 2022-02-18 19:14:11 +08:00
link
c6928c333d Add websocket 2022-02-18 19:06:03 +08:00
link
63c6c2cebb Merge pull request #111 from IceWhaleTech/dev
Delete CasaOS-linux-amd64
2022-02-17 19:22:14 +08:00
link
6cba025679 Delete CasaOS-linux-amd64 2022-02-17 19:21:19 +08:00
link
d25b93c972 Merge pull request #110 from IceWhaleTech/dev
Dev
2022-02-17 18:53:54 +08:00
link
b14861703c Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-02-17 18:53:29 +08:00
link
32604225ce update ui 2022-02-17 18:52:14 +08:00
link
f623b29c38 Merge pull request #109 from IceWhaleTech/dev
Dev
2022-02-17 18:47:44 +08:00
link
94ae6ee8ec Merge branch 'main' into dev 2022-02-17 18:47:36 +08:00
link
5115bf72e1 update desc 2022-02-17 18:44:51 +08:00
link
e1a928cd78 Fixed issues 2022-02-17 18:43:25 +08:00
link
3977519c43 Update assist.sh 2022-01-30 11:21:24 +08:00
link
2f87834ac9 Merge pull request #93 from IceWhaleTech/dev
Update route.go
2022-01-28 16:25:01 +08:00
link
53335012d8 Update route.go 2022-01-28 16:24:28 +08:00
link
9d6302f7e3 Merge pull request #92 from IceWhaleTech/dev
Update UI
2022-01-28 16:14:59 +08:00
link
20950e2a60 Update UI 2022-01-28 16:14:35 +08:00
link
0e0e507f8f Merge pull request #91 from IceWhaleTech/dev
update ui
2022-01-28 15:35:15 +08:00
link
46e14617b6 update ui 2022-01-28 15:34:32 +08:00
link
903c73fafb Merge pull request #90 from IceWhaleTech/dev
update web
2022-01-28 14:33:40 +08:00
link
42a56df4a5 update web 2022-01-28 14:32:49 +08:00
link
493dc5c032 Merge pull request #89 from IceWhaleTech/dev
Compatible with more types of disks
2022-01-28 14:06:58 +08:00
link
9a73bc2a18 Compatible with more types of disks
Add usb display
2022-01-28 14:06:27 +08:00
link
55a9acd9f6 Merge pull request #85 from IceWhaleTech/dev
Apply multilingual support
2022-01-26 18:51:14 +08:00
link
d060968b7a Apply multilingual support 2022-01-26 18:50:34 +08:00
link
88a7f53130 Merge pull request #82 from IceWhaleTech/dev
Dev
2022-01-26 11:33:33 +08:00
link
26e5b18a5d Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-01-26 11:33:02 +08:00
link
011ace96f6 update ui 2022-01-26 11:32:57 +08:00
link
5c00655d14 Merge pull request #81 from IceWhaleTech/dev
Dev
2022-01-26 10:46:50 +08:00
link
eb36c262db Merge branch 'main' into dev 2022-01-26 10:46:43 +08:00
link
29d1861545 Merge branch 'main' into dev 2022-01-26 10:45:11 +08:00
link
3c9b410693 update dependency 2022-01-26 10:44:55 +08:00
link
4c3b41433b Update assist.sh 2022-01-24 22:06:31 +08:00
link
1fd13668c0 Merge pull request #78 from IceWhaleTech/dev
Dev
2022-01-24 17:22:48 +08:00
link
d1ab7261a6 Update usb-mount.sh 2022-01-24 17:21:43 +08:00
link
0fc65bcb3a update mount path 2022-01-24 17:08:28 +08:00
link
f1ce8bfd99 Merge pull request #77 from IceWhaleTech/dev
update disk
2022-01-24 11:19:47 +08:00
link
3f472f1864 update disk 2022-01-24 11:19:04 +08:00
link
229d94cae7 Merge pull request #74 from IceWhaleTech/dev
Fixed Storage Panel
2022-01-21 17:50:44 +08:00
link
c28e1bbf93 Fixed Storage Panel 2022-01-21 17:50:12 +08:00
link
a840029000 Merge pull request #73 from IceWhaleTech/dev
update UI
2022-01-20 18:45:54 +08:00
link
aad2646cf2 Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-01-20 18:45:17 +08:00
link
ca1f8ad73e Update UI 2022-01-20 18:44:55 +08:00
link
dea02763a2 Update UI 2022-01-20 18:44:40 +08:00
link
ea67385a64 Merge pull request #72 from IceWhaleTech/dev
Storage Manager
2022-01-20 18:41:56 +08:00
link
fa2daa2767 Merge branch 'main' into dev 2022-01-20 18:41:49 +08:00
link
fcb906aa85 Storage Manager
Fix the app store classification problem
Fix the application market classification problem
2022-01-20 18:38:59 +08:00
老竭力
489a617126 Update casa.yml 2022-01-04 16:22:38 +08:00
老竭力
601e7ce10b Update casa.yml 2022-01-04 14:51:09 +08:00
老竭力
4a6fc9a945 Update system.go 2022-01-04 14:47:46 +08:00
老竭力
b377af1d24 Update casa.yml 2021-12-30 19:17:11 +08:00
老竭力
3fc00f8da7 Update casa.yml 2021-12-30 19:13:40 +08:00
老竭力
6e39fe5f8c Update casa.yml 2021-12-30 19:04:37 +08:00
老竭力
20c240a123 Update casa.yml 2021-12-30 19:00:11 +08:00
老竭力
3ea9fc0de0 Update casa.yml 2021-12-30 18:52:37 +08:00
老竭力
b80b08ef07 Update casa.yml 2021-12-30 18:50:45 +08:00
老竭力
505af8d101 Update casa.yml 2021-12-30 18:46:17 +08:00
老竭力
ae35a6d291 Update casa.yml 2021-12-30 18:44:07 +08:00
John Guan
2b95c07a47 Update casa.yml 2021-12-30 18:16:19 +08:00
John Guan
27a011e715 Update casa.yml 2021-12-30 18:01:01 +08:00
link
476831a12f Merge pull request #65 from IceWhaleTech/dev
update action system
2021-12-30 16:59:05 +08:00
link
9675eff69e update action system 2021-12-30 16:58:24 +08:00
link
85a044246e Merge pull request #64 from IceWhaleTech/dev
update action system
2021-12-30 16:53:32 +08:00
link
5c41fbcf3d update action system 2021-12-30 16:52:58 +08:00
link
6baab7a525 Merge pull request #63 from IceWhaleTech/dev
update action system
2021-12-30 16:42:39 +08:00
link
ab3b5a9077 update action system 2021-12-30 16:41:16 +08:00
link
5811c271b2 Merge pull request #62 from IceWhaleTech/dev
update web
2021-12-30 16:20:50 +08:00
link
cf5387346d update web 2021-12-30 16:20:30 +08:00
link
8df63c6c5c Merge pull request #60 from IceWhaleTech/dev
New App Store
2021-12-29 16:42:56 +08:00
link
1d17d27c96 New App Store 2021-12-29 16:42:20 +08:00
John Guan
bdcbae69a5 Update README.md 2021-12-14 11:41:42 +08:00
John Guan
cdbc3437be Update README.md 2021-12-14 10:40:17 +08:00
link
8940b520e0 Merge pull request #53 from IceWhaleTech/dev
update ui
2021-12-11 15:44:55 +08:00
link
1d62fbd670 update ui 2021-12-11 15:44:17 +08:00
link
a0b56d809e Merge pull request #52 from IceWhaleTech/dev
update cpu changes when the application is removed
2021-12-10 18:08:49 +08:00
link
f1f6d33e26 update cpu changes when the application is removed 2021-12-10 18:08:02 +08:00
link
f292edd2ba Merge pull request #51 from IceWhaleTech/dev
update app.go
2021-12-10 17:14:46 +08:00
link
caa9b50b65 update app.go 2021-12-10 17:14:01 +08:00
link
61b824065b Merge pull request #50 from IceWhaleTech/dev
update stats steam
2021-12-10 16:34:29 +08:00
link
9a900b2ca0 update stats steam 2021-12-10 16:33:39 +08:00
link
4c1cbc98a4 Merge pull request #49 from IceWhaleTech/dev
fixed bug
2021-12-10 14:18:01 +08:00
link
8660b95756 fixed bug 2021-12-10 14:17:36 +08:00
link
e7ebdc040f Merge pull request #48 from IceWhaleTech/dev
feat: Multiple updates
2021-12-09 19:03:45 +08:00
link
6c235d3f2a feat: Multiple updates
1.Add the function of modifying the WebUI port.
2.Add the function to modify the search engine.
3.Add the multi-language function and add Chinese translation.
4.Add detailed CPU and memory statistics.
2021-12-09 19:02:41 +08:00
link
997d912f4d Merge branch 'main' into dev 2021-12-06 17:12:53 +08:00
link
2508a4e07d Pull Submit 2021-12-06 17:08:36 +08:00
link
90b997337c Merge pull request #42 from xuchaoa/main
format code and fix wrong spell
2021-12-06 03:07:48 -06:00
xuc2
0bb3c92335 format code and fix wrong spell 2021-12-03 16:48:07 +08:00
link
7fd539c57e Merge pull request #40 from IceWhaleTech/dev
update volume path
2021-12-01 20:49:48 -06:00
link
52bd22ab2b update volume path 2021-12-02 10:49:02 +08:00
John Guan
46e9458e82 Update demo.yml 2021-12-01 21:58:57 +08:00
John Guan
3f5595e794 Update demo.yml 2021-12-01 21:54:02 +08:00
John Guan
d22cc7d3f6 Update demo.yml 2021-12-01 21:49:23 +08:00
John Guan
eb03a3e6c7 Update demo.yml 2021-12-01 21:46:34 +08:00
John Guan
65cc1f4752 Update demo.yml 2021-12-01 21:36:44 +08:00
John Guan
99db197a39 Update demo.yml 2021-12-01 21:31:17 +08:00
John Guan
7e2a5d553c Update demo.yml 2021-12-01 21:14:34 +08:00
John Guan
f02337b83b Update demo.yml 2021-12-01 21:09:18 +08:00
John Guan
f66b67b0c9 Update demo.yml 2021-12-01 21:05:52 +08:00
John Guan
91087b5341 Update demo.yml 2021-12-01 21:01:40 +08:00
John Guan
c67191d8c2 Update demo.yml 2021-12-01 20:45:36 +08:00
John Guan
0fac461783 Update demo.yml 2021-12-01 20:11:32 +08:00
John Guan
ec5bc922e7 Update demo.yml 2021-12-01 20:07:44 +08:00
John Guan
7194792c3f Update demo.yml 2021-12-01 19:51:36 +08:00
John Guan
76c8bade7f Update demo.yml 2021-12-01 19:50:30 +08:00
John Guan
126857fab0 Create demo.yml 2021-12-01 19:43:50 +08:00
link
9ca57e105e Merge pull request #38 from IceWhaleTech/dev
add uninstall.sh
2021-12-01 02:50:01 -06:00
link
2651140095 add uninstall.sh 2021-12-01 16:48:38 +08:00
link
14175bc438 Merge pull request #37 from IceWhaleTech/dev
fixed bug
2021-12-01 02:39:22 -06:00
link
956328da86 fixed bug 2021-12-01 16:25:56 +08:00
link
cc46a96a75 Merge pull request #27 from IceWhaleTech/v0.2.1
fixed path error
2021-11-25 05:44:33 -06:00
link
049090444e fixed path error 2021-11-25 19:41:25 +08:00
link
796c25b7a5 Merge pull request #26 from IceWhaleTech/v0.2.1
add sync function
2021-11-25 03:35:47 -06:00
link
9057290188 add sync function 2021-11-25 17:35:01 +08:00
John Guan
fcc57bb734 Update README.md 2021-11-24 18:35:14 +08:00
link
a98f5e087c Merge pull request #24 from IceWhaleTech/add-license-1
Create LICENSE
2021-11-19 03:34:09 -06:00
link
403d563869 Create LICENSE 2021-11-19 17:33:57 +08:00
John Guan
88c15104b4 update README.md 2021-11-12 17:52:16 +08:00
link
6176289b88 Merge pull request #23 from IceWhaleTech/v0.2.1
update volumes
2021-11-10 03:51:14 -06:00
link
5cfd44da79 update volumes 2021-11-10 17:50:46 +08:00
link
2437da33a6 Merge pull request #21 from IceWhaleTech/v0.2.1
Update system.go
2021-11-09 05:11:58 -06:00
link
49ca0af746 Update system.go 2021-11-09 19:10:18 +08:00
link
9440b89fab Merge pull request #20 from IceWhaleTech/v0.2.1
Fixing bugs
2021-11-09 04:58:59 -06:00
link
f020c1162d Fixing bugs
Resolve application installation path errors
2021-11-09 18:57:50 +08:00
link
120fb2cea2 Merge pull request #19 from IceWhaleTech/v0.2.1
update ui
2021-11-04 03:04:37 -05:00
link
37130966cf update ui 2021-11-04 16:03:33 +08:00
link
795b82c42c Update issue templates 2021-11-04 15:26:36 +08:00
link
57ad33d53a Merge pull request #17 from IceWhaleTech/v0.2.1
update ui
2021-11-03 06:06:21 -05:00
link
a6ceee7bc0 update ui 2021-11-03 19:05:41 +08:00
link
44bb05fad0 Merge pull request #16 from IceWhaleTech/v0.2.1
New App Store
2021-11-03 04:08:45 -05:00
link
a5fee0ee97 New App Store
Add App Store for installation
Fix favicon display in dark mode
2021-11-03 17:07:46 +08:00
John Guan
da99b2d01a Update README.md 2021-11-03 10:51:32 +08:00
link
1433e3297b Merge pull request #15 from IceWhaleTech/v0.2.1
Update UI
2021-10-29 06:36:37 -05:00
link
cad7af13af Update UI 2021-10-29 19:35:51 +08:00
link
39cb8904a3 Merge pull request #14 from IceWhaleTech/v0.2.1
V0.2.1
2021-10-29 05:39:54 -05:00
link
2ed372b3cd Update system.go 2021-10-29 18:39:07 +08:00
link
8bca76b78b Add new features
add casaOS logs
add application  terminal
add application  logs
2021-10-29 18:37:27 +08:00
link
595e0f28af Merge pull request #13 from IceWhaleTech/v0.2.1
update disk display
2021-10-27 06:04:34 -05:00
link
4939fe10aa update disk display
add casaos logs api
update ui
2021-10-27 19:03:59 +08:00
link
d2962a8e70 Merge pull request #12 from IceWhaleTech/v0.2.1
Add some features
2021-10-27 04:29:44 -05:00
link
d7d53d639b Add some features
Add terminal
Improve single user management function
2021-10-27 17:27:46 +08:00
link
d2ff1b0506 Merge pull request #10 from IceWhaleTech/v0.2.1
update UI
2021-10-22 05:28:34 -05:00
link
7191735737 update UI 2021-10-22 18:28:00 +08:00
link
21f3fd85d9 Merge pull request #9 from IceWhaleTech/v0.2.1
update initialization config
2021-10-22 04:59:00 -05:00
link
ba77e07e36 update initialization config
initialization user config
2021-10-22 17:57:22 +08:00
link
0d6e7ca339 Merge pull request #8 from IceWhaleTech/v0.2.1
update route.go
2021-10-22 04:19:53 -05:00
link
b1d5d9858b update route.go 2021-10-22 17:19:07 +08:00
link
4f06be0e45 Merge pull request #7 from IceWhaleTech/v0.2.1
update webui
2021-10-22 04:10:24 -05:00
link
812ffd56a8 update webui 2021-10-22 17:09:43 +08:00
老竭力
6ba845eec5 Update issue templates 2021-10-22 16:58:29 +08:00
link
4fa72289ed Merge pull request #6 from IceWhaleTech/v0.2.1
remove build file
2021-10-22 03:55:06 -05:00
link
5cdd842a3e remove build file
remove main
remove CasaOS
2021-10-22 16:54:17 +08:00
link
cc5504c0a9 Merge pull request #5 from IceWhaleTech/v0.2.1
Add authentication
2021-10-22 03:52:39 -05:00
John Guan
32e00b17b1 update README.md 2021-10-20 11:23:25 +08:00
John Guan
16108f03ac Merge branch 'main' of https://github.com/IceWhaleTech/CasaOS 2021-10-20 11:10:53 +08:00
John Guan
e7f990b224 Update README.md 2021-10-20 11:10:51 +08:00
link
c5d824c4ba Merge pull request #3 from IceWhaleTech/v0.2.1
Optimize installation process
2021-10-19 06:12:40 -05:00
link
e69d2e587b Merge pull request #2 from IceWhaleTech/v0.2.1
update create file and dir api
2021-10-18 05:25:26 -05:00
link
8fe0e4aa73 Update casa.yml 2021-10-15 19:48:38 +08:00
link
30a23a93a2 Update casa.yml 2021-10-15 19:38:50 +08:00
link
53157fbb1f Merge pull request #1 from IceWhaleTech/v0.2.1
add widget
2021-10-14 22:45:31 -05:00
401 changed files with 27427 additions and 4367 deletions

32
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -0,0 +1,15 @@
---
name: Submit application
about: Add an app to this project
title: ''
labels: ''
assignees: LinkLeong
---
Tested platform
e.g. linux/amd64,linux/arm-v7,linux-arm64
Please export and upload the configuration file of this application

View File

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

79
.github/workflows/demo.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
name: Demo Reset
# Controls when the workflow will run
on:
schedule:
- cron: "0 * * * *"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')
# OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')
# NEW_INSTANCE_NAME=CasaOS-Demo-$(date +%s)
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
reset:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Configure AWS credentials from Test account
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Get old instance and snapshot name, create new instance name
run: |
echo "OLD_INSTANCE_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
echo "OLD_INSTANCE_NAME=$(aws lightsail get-instances | grep '"name": "CasaOS-Demo-[0-9]' | sed 's/ //g' | sed 's/"//g' | sed 's/,//g' | sed 's/name://g')" >> $GITHUB_ENV
echo "NEW_INSTANCE_NAME=CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
- name: Create instances from snapshot
run: |
aws lightsail create-instances-from-snapshot \
--instance-snapshot-name ${{ env.OLD_INSTANCE_SNAPSHOT_NAME }} \
--instance-names ${{ env.NEW_INSTANCE_NAME }} \
--availability-zone us-west-2a \
--bundle-id large_2_0
- name: Wait for new instance running
run: |
TIMEOUT=$(($(date +%s)+600))
while [ $TIMEOUT -gt $(date +%s) ]
do
NEW_INSTANCE_STATE=$(aws lightsail get-instance-state --instance-name ${{ env.NEW_INSTANCE_NAME }} | grep '"name":' | sed 's/ //g' | sed 's/"//g' | sed 's/name://g')
if [ $NEW_INSTANCE_STATE == running ]
then
echo "New instance is running now"
sleep 10s
break
fi
done
- name: Put instance public ports
run: |
aws lightsail put-instance-public-ports \
--port-infos fromPort=0,toPort=65535,protocol=all \
--instance-name ${{ env.NEW_INSTANCE_NAME }}
- name: Attach static ip
run: |
aws lightsail attach-static-ip \
--static-ip-name CasaOS-Demo-IP \
--instance-name ${{ env.NEW_INSTANCE_NAME }}
- name: Delete old instance
run: |
aws lightsail delete-instance \
--instance-name ${{ env.OLD_INSTANCE_NAME }}

2
.gitignore vendored
View File

@@ -31,3 +31,5 @@ gen
/docs/
/conf/conf.ini
__debug_bin
main
CasaOS

BIN
CasaOS

Binary file not shown.

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,4 +1,4 @@
# CasaOS - A simple, easy-to-use, elegant open-source home server system.
# CasaOS - A simple, easy-to-use, elegant open-source Home Cloud system.
![CasaOS](https://raw.githubusercontent.com/IceWhaleTech/logo/main/casaos/casaos_banner_aldeyjarfoss.png)
@@ -6,18 +6,58 @@
[![Pull Requests](https://img.shields.io/github/issues-pr/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/pulls)
[![Issues](https://img.shields.io/github/issues/IceWhaleTech/CasaOS?color=162453&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/issues)
[![GitHub Stars](https://img.shields.io/github/stars/IceWhaleTech/CasaOS?color=162453&logo=github&style=flat-square)](https://github.com/IceWhaleTech/CasaOS/stargazers)
[![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/Gx4BCEtHjx)
[![Discord](https://img.shields.io/discord/884667213326463016?color=162453&label=Chat&logo=discord&logoColor=fff&style=flat-square)](https://discord.gg/knqAbbBbeX)
CasaOS is an open-source home server system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant home server system.
CasaOS is an open-source Home Cloud system based on the Docker ecosystem and designed for home scenarios. It is committed to building the world's most simple, easy-to-use, and elegant Home Cloud system.
IceWhale team believes that through community-driven collaborative innovation and open communication with global developers, we can reshape the digital home experience like never before.
![CasaOS Snapshot](snapshot.png)
![CasaOS Snapshot Mobile](snapshot-mobile.png)
## Getting Started
> ⚠️ Note:
>
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/knqAbbBbeX)!
### Quick Setup CasaOS
Fresh install a system from the list below and run the this command:
```sh
wget -qO- https://get.icewhale.io/casaos.sh | bash
```
or
```sh
curl -fsSL https://get.icewhale.io/casaos.sh | bash
```
### Uninstall CasaOS
```sh
curl -fsSL https://get.icewhale.io/casaos-uninstall.sh | bash
```
### System Compatibility
- Ubuntu Server 20.04 amd64 (✅ Recommend, Tested)
- Armbian 22.02 armhf/arm64/amd64 (✅ Recommend, Tested)
- Elementary OS 6.1 Jólnir amd64 (✅ Recommend, Tested)
- Deepin 20.4 amd64 (⚠️ Not Fully Tested Yet)
- Raspberry Pi Lite OS aarch64/arm64 (⚠️ Not Fully Tested Yet)
- Debian 11 amd64 (⚠️ Not Fully Tested Yet)
- OpenWrt 21.02 amd64 (⚠️ Not Fully Tested Yet)
- OpenWrt 21.02 aarch64/arm64 (⚠️ Not Fully Tested Yet)
## Key Features
- UI designed for home scenarios - simple, elegant, and easy-to-use
- Quick Docker app installation with only three steps, plus automatic management
- App Store for private cloud 🚧
- App Store for Home Cloud 🚧
- Home data/digital asset management 🚧
- Smart home manager 🚧
@@ -34,48 +74,11 @@ After looking at many systems and software on the market, the team found no serv
So, we set out to build this open source project to develop CasaOS with our own hands, everyone in the community, and you.
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
> A warm welcome for you to share and discuss your great ideas in the [Discord server](https://discord.gg/knqAbbBbeX)!
[![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/Gx4BCEtHjx)
[![Discord Card](https://discordapp.com/api/guilds/884667213326463016/widget.png?style=banner2)](https://discord.gg/knqAbbBbeX)
## Getting Started
> ⚠️ Note:
>
> CasaOS is still in the early development stage and may vary significantly with the final release. Feel free to test run and share your feedback in the [Discord server](https://discord.gg/Gx4BCEtHjx)!
### System Compatibility
- Ubuntu Server 20.04 amd64 (✅ Recommend, Tested)
- Debian 11 amd64 (⚠️ Not Fully Tested Yet)
- OpenWrt 21.02 amd64 (⚠️ Not Fully Tested Yet)
- Raspberry Pi OS aarch64/arm64 (🚧 Under Planning)
- OpenWrt 21.02 aarch64/arm64 (🚧 Under Planning)
### Quick Setup CasaOS
Fresh install a system from the above list and run the below command:
```sh
curl -fsSL https://get.icewhale.io/casaos.sh | bash
```
## To Do
**v 0.1.x**
- [x] An elegant UI for home scenarios
- [x] Custom installation of Docker Apps
- [x] Update, stop, uninstall, restart, etc. of Docker apps
- [x] Docker CLI parser
- [x] System Update
- [ ] Getting Started tutorial
- [ ] Docker Compose parser
- [ ] App config file import and export
- [ ] macvlan network mode
## Maintainers
- Jerry Liu
@@ -83,4 +86,4 @@ curl -fsSL https://get.icewhale.io/casaos.sh | bash
- Ober Zhang
- Zyaire Ann
- John Guan
- Right here, waiting for YOU!
- Right here, waiting for YOU!

2
UI

Submodule UI updated: 60d08a6b73...74fa1f8920

View File

@@ -9,24 +9,27 @@ DateTimeFormat = 2006-01-02 15:04:05
TimeFormat = 15:04:05
DateFormat = 2006-01-02
ProjectPath = /casaOS/server
RootPath = /casaOS
[server]
HttpPort = 8089
UDPPort =
RunMode = release
ServerApi = https://api.casaos.zimaboard.com
Handshake = socket.casaos.io
Token =
USBAutoMount = true
[user]
UserName = admin
PWD = zimaboard
Email = user@gmail.com
Description = description
Token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImVyZXJlIiwicGFzc3dvcmQiOiJhZHNmZGYiLCJleHAiOjE2MjQwMDU0ODEsImlzcyI6Imdpbi1ibG9nIn0.JNsCccZuFCwlSMLJg62iOIB2xymk_k7xGa11xhZ07bc
[zerotier]
UserName = user
PWD = pwd
Token = yBKYyavr2RdFAIVN7iTpzlsB1o6CqTgm
Initialized = false
Avatar =
NickName =
[redis]
Host = 127.0.0.1:6379
@@ -38,4 +41,8 @@ IdleTimeout = 200
[system]
ConfigStr =
WidgetList =
Analyse =
[file]
ShareDir =
DownloadDir =

31
go.mod
View File

@@ -7,29 +7,23 @@ require (
github.com/Microsoft/hcsshim v0.8.22 // indirect
github.com/PuerkitoBio/goquery v1.7.0
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/aquasecurity/libbpfgo v0.2.1-libbpf-0.4.0 // indirect
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/cpuguy83/go-md2man/v2 v2.0.1 // 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-delve/delve v1.7.2 // indirect
github.com/go-ini/ini v1.62.0
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/validator/v10 v10.6.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/gomodule/redigo v1.8.5
github.com/google/go-dap v0.6.0 // indirect
github.com/google/go-github/v36 v36.0.0
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
@@ -38,15 +32,15 @@ require (
github.com/json-iterator/go v1.1.11 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lucas-clemente/quic-go v0.25.0
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // 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/runc v1.0.2 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/selinux v1.8.5 // indirect
github.com/peterh/liner v1.2.1 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109
github.com/prometheus/procfs v0.7.3 // indirect
@@ -56,23 +50,19 @@ require (
github.com/sirupsen/logrus v1.8.1
github.com/smartystreets/assertions v1.2.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/spf13/cobra v1.2.1 // indirect
github.com/spf13/afero v1.2.2
github.com/swaggo/gin-swagger v1.3.0
github.com/swaggo/swag v1.7.3
github.com/tidwall/gjson v1.8.0
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/gjson v1.10.2
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/ugorji/go v1.2.6 // indirect
go.opencensus.io v0.23.0 // indirect
go.starlark.net v0.0.0-20210901212718-87f333178d59 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/mod v0.5.0 // indirect
golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
@@ -81,7 +71,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
src.techknowlogick.com/xgo v1.4.1-0.20211007230901-4fb1c2d7b2ab // indirect
gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.22.5
)

359
go.sum
View File

@@ -1,7 +1,9 @@
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
@@ -15,11 +17,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -28,7 +25,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -38,7 +34,12 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -74,7 +75,6 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.22 h1:CulZ3GW8sNJExknToo+RWD+U+6ZM5kkNfuxywSDPd08=
github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
@@ -101,14 +101,9 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aquasecurity/libbpfgo v0.1.2-0.20210708203834-4928d36fafac/go.mod h1:/+clceXE103FaXvVTIY2HAkQjxNtkra4DRWvZYr2SKw=
github.com/aquasecurity/libbpfgo v0.2.1-libbpf-0.4.0 h1:WekP69tdNlVfWdlXUqxGEwbeLCMfNcURBsq0uS5dPSI=
github.com/aquasecurity/libbpfgo v0.2.1-libbpf-0.4.0/go.mod h1:/+clceXE103FaXvVTIY2HAkQjxNtkra4DRWvZYr2SKw=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -120,13 +115,13 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=
github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
@@ -135,6 +130,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -145,7 +142,6 @@ github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJ
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
@@ -184,8 +180,6 @@ github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo
github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.5 h1:q1gxsZsGZ8ddVe98yO6pR21b5xQSMiR61lD0W96pgQo=
github.com/containerd/containerd v1.5.5/go.mod h1:oSTh0QpT1w6jYcGmbiSbxv9OSQYaa88mPyWIuU79zyo=
github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -244,7 +238,6 @@ github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgU
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
@@ -252,18 +245,15 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -276,16 +266,15 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/derekparker/trie v0.0.0-20200317170641-1fdf38b7b0e9 h1:G765iDCq7bP5opdrPkXk+4V3yfkgV9iGFuheWZ/X/zY=
github.com/derekparker/trie v0.0.0-20200317170641-1fdf38b7b0e9/go.mod h1:D6ICZm05D9VN1n/8iOtBxLpXtoGp6HDFUJ1RNVieOSE=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
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=
@@ -308,24 +297,24 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b h1:r13MvtFTtnvxtuKK7z0ZSQ2EfMmTzWDHwfDvGCoqUQE=
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b/go.mod h1:EfR6AU78zUiZ36oVS5YrmTzc2um3zDXWPx4L4st++jo=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
github.com/gin-contrib/gzip v0.0.2 h1:VMBkd4ZB1Hl7e1lOA5gEZ/qdD3d9vLIq57xKWgPCCV8=
@@ -339,8 +328,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-delve/delve v1.7.2 h1:QTDJlgx9OwUVYVm7xthyf2XHKrZcTQu3wkRbovktidM=
github.com/go-delve/delve v1.7.2/go.mod h1:CHdOd8kuHlQxtBJr1HmJX5h+KmmWd/7Lk5d+D1zHn4E=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -365,21 +354,17 @@ github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
@@ -394,6 +379,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
@@ -421,6 +408,7 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -428,7 +416,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -444,7 +433,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
@@ -464,9 +452,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-dap v0.5.1-0.20210713061233-c91b005e3987/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/go-dap v0.6.0 h1:Y1RHGUtv3R8y6sXq2dtGRMYrFB2hSqyFVws7jucrzX4=
github.com/google/go-dap v0.6.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v36 v36.0.0 h1:ndCzM616/oijwufI7nBRa+5eZHLldT+4yIB68ib5ogs=
github.com/google/go-github/v36 v36.0.0/go.mod h1:LFlKC047IOqiglRGNqNb9s/iAPTnnjtlshm+bxp+kwk=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@@ -475,7 +462,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -483,10 +469,6 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -494,6 +476,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
@@ -511,50 +495,34 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w=
github.com/jinzhu/copier v0.3.2/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
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=
@@ -583,13 +551,13 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -597,10 +565,12 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
@@ -608,39 +578,33 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco=
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
@@ -665,8 +629,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -676,11 +644,18 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -688,14 +663,14 @@ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
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=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg=
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -711,27 +686,24 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opencontainers/selinux v1.8.5 h1:OkT6bMHOQ1JQQO4ihjQ49sj0+wciDcjziSVTRn8VeTA=
github.com/opencontainers/selinux v1.8.5/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg=
github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109 h1:h9WYaTCQJ7hap8C5vQniEum2YZbc+iRad/ROafTjy10=
github.com/prestonTao/upnp v0.0.0-20150206124352-f4370df5e109/go.mod h1:U7VCLF6LMHzOFD/6Kww2MTQuwaNeEA1U1dOxFyZBoBE=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@@ -743,12 +715,14 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -762,27 +736,44 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil/v3 v3.21.5 h1:YUBf0w/KPLk7w1803AYBnH7BmA+1Z/Q5MEZxpREUaB4=
github.com/shirou/gopsutil/v3 v3.21.5/go.mod h1:ghfMypLDrFSWN2c9cDYFLHyynQ+QUht0cv/18ZqVczw=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -799,29 +790,23 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -835,24 +820,21 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI=
github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
github.com/swaggo/swag v1.7.3 h1:ucB7irEdRrhjmW+Z1Ss4GjO68oPKQFjSgOR8BCAvcbU=
github.com/swaggo/swag v1.7.3/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ=
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
@@ -877,10 +859,10 @@ github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxW
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
@@ -907,43 +889,34 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.starlark.net v0.0.0-20200821142938-949cc6f4b097/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU=
go.starlark.net v0.0.0-20210901212718-87f333178d59 h1:F8ArBy9n1l7HE1JjzOIYqweEqoUlywy5+L3bR0tIa9g=
go.starlark.net v0.0.0-20210901212718-87f333178d59/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -962,6 +935,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -972,8 +946,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -982,8 +954,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
@@ -993,13 +963,14 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -1024,40 +995,33 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI=
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1070,17 +1034,17 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1124,14 +1088,13 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1141,32 +1104,21 @@ golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927052749-1cf2251ac284 h1:lBPNCmq8u4zFP3huKCmUQ2Fx8kcY4X+O12UgGnyKsrg=
golang.org/x/sys v0.0.0-20210927052749-1cf2251ac284/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1190,7 +1142,9 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -1211,12 +1165,10 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1239,17 +1191,10 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1258,6 +1203,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1274,13 +1222,9 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@@ -1290,6 +1234,10 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -1321,21 +1269,13 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 h1:5Tbluzus3QxoAJx4IefGt1W0HQZW4nuMrVk684jI74Q=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1351,14 +1291,9 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
@@ -1392,7 +1327,6 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
@@ -1400,6 +1334,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -1415,15 +1350,18 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.1.5 h1:JU8G59VyKu1x1RMQgjefQnkZjDe9wHc1kARDZPu5dZs=
gorm.io/driver/sqlite v1.1.5/go.mod h1:NpaYMcVKEh6vLJ47VP6T7Weieu4H1Drs3dGD/K6GrGc=
gorm.io/gorm v1.21.15 h1:gAyaDoPw0lCyrSFWhBlahbUA1U4P5RViC1uIqoB+1Rk=
gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=
gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY=
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
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=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -1457,7 +1395,6 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
@@ -1466,5 +1403,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
src.techknowlogick.com/xgo v1.4.1-0.20211007230901-4fb1c2d7b2ab h1:JB9ZA1DJczGU93I2LHsSiut2XO+CyepZBwYicEMt/hg=
src.techknowlogick.com/xgo v1.4.1-0.20211007230901-4fb1c2d7b2ab/go.mod h1:31CE1YKtDOrKTk9PSnjTpe6YbO6W/0LTYZ1VskL09oU=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

BIN
main

Binary file not shown.

56
main.go
View File

@@ -4,13 +4,16 @@ import (
"flag"
"fmt"
"net/http"
"runtime"
"time"
"github.com/IceWhaleTech/CasaOS/pkg/cache"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/route"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/robfig/cron"
"gorm.io/gorm"
)
@@ -26,9 +29,40 @@ func init() {
config.InitSetup(*configFlag)
config.UpdateSetup()
loger2.LogSetup()
sysType := runtime.GOOS
if sysType == "windows" {
config.AppInfo.ProjectPath = "C:\\CasaOS\\service"
config.Cfg.Section("app").Key("ProjectPath").SetValue("C:\\CasaOS\\service")
config.AppInfo.RootPath = "C:\\CasaOS"
config.Cfg.Section("app").Key("RootPath").SetValue("C:\\CasaOS")
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
if sysType == "darwin" {
config.AppInfo.ProjectPath = "./CasaOS/service"
config.Cfg.Section("app").Key("ProjectPath").SetValue("./CasaOS/service")
config.AppInfo.RootPath = "./CasaOS"
config.Cfg.Section("app").Key("RootPath").SetValue("./CasaOS")
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
//gredis.GetRedisConn(config.RedisInfo),
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
service.Cache = cache.Init()
go service.UDPService()
fmt.Println("token", service.GetToken())
service.UDPAddressMap = make(map[string]string)
//go service.SocketConnect()
service.CancelList = make(map[string]string)
route.InitFunction()
go service.SendIPToServer()
go service.LoopFriend()
}
// @title casaOS API
@@ -53,17 +87,30 @@ func main() {
//gredis.Setup()
r := route.InitRouter()
//service.SyncTask(sqliteDB)
cron2 := cron.New() //创建一个cron实例
//执行定时任务每5秒执行一次
err := cron2.AddFunc("0 0 0 1/1 * *", func() {
cron2 := cron.New()
//every day execution
err := cron2.AddFunc("0 0/5 * * * *", func() {
//service.PushIpInfo(*&config.ServerInfo.Token)
//service.UpdataDDNSList(mysqldb)
//service.SyncTask(sqliteDB)
service.SendIPToServer()
service.LoopFriend()
})
if err != nil {
fmt.Println(err)
}
// err = cron2.AddFunc("0/1 * * * * *", func() {
//启动/关闭
// //service.SendIPToServer()
// //service.LoopNet()
// })
// if err != nil {
// fmt.Println(err)
// }
cron2.Start()
defer cron2.Stop()
s := &http.Server{
@@ -73,6 +120,7 @@ func main() {
WriteTimeout: 60 * time.Second,
MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()
}

View File

@@ -2,8 +2,9 @@ package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"github.com/gin-gonic/gin"
)
func Cors() gin.HandlerFunc {
@@ -17,7 +18,7 @@ func Cors() gin.HandlerFunc {
//服务器支持的所有跨域请求的方法
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language")
// 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//设置缓存时间

16
model/app-analyse.go Normal file
View File

@@ -0,0 +1,16 @@
package model
type AppAnalyse struct {
Name string `json:"name"`
Type string `json:"type"`
UUId string `json:"uuid"`
Language string `json:"language"`
}
type ConnectionStatus struct {
From string `json:"from"`
To string `json:"to"`
Error string `json:"error"`
UUId string `json:"uuid"`
Event string `json:"event"`
}

View File

@@ -7,32 +7,42 @@ import (
)
type ServerAppList struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Tagline string `json:"tagline"`
Tags Strings `gorm:"type:json" json:"tags"`
Icon string `json:"icon"`
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
Category string `json:"category"`
TcpPort uint `json:"tcp_port"`
PortMap uint `json:"port_map"`
ImageVersion string `json:"image_version"`
Tip string `json:"tip"`
Configures configures `gorm:"type:json" json:"configures"`
NetworkModel string `json:"network_mode"`
Image string `json:"image"`
Index string `json:"index"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
State string `json:"state"`
Author string `json:"author"`
MinMemory int `json:"min_memory"`
MinDisk int `json:"min_disk"`
MaxMemory uint64 `json:"max_memory"`
Thumbnail string `json:"thumbnail"`
Healthy string `json:"healthy"`
Plugins Strings `json:"plugins"`
Id uint `gorm:"column:id;primary_key" json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Tagline string `json:"tagline"`
Tags Strings `gorm:"type:json" json:"tags"`
Icon string `json:"icon"`
ScreenshotLink Strings `gorm:"type:json" json:"screenshot_link"`
Category string `json:"category"`
CategoryFont string `json:"category_font"`
PortMap string `json:"port_map"`
ImageVersion string `json:"image_version"`
Tip string `json:"tip"`
Envs EnvArray `json:"envs"`
Ports PortArray `json:"ports"`
Volumes PathArray `json:"volumes"`
Devices PathArray `json:"devices"`
NetworkModel string `json:"network_model"`
Image string `json:"image"`
Index string `json:"index"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
State string `json:"state"`
Author string `json:"author"`
MinMemory int `json:"min_memory"`
MinDisk int `json:"min_disk"`
MaxMemory uint64 `json:"max_memory"`
Thumbnail string `json:"thumbnail"`
Healthy string `json:"healthy"`
Plugins Strings `json:"plugins"`
Origin string `json:"origin"`
Type int `json:"type"`
Developer string `json:"developer"`
HostName string `json:"host_name"`
Privileged bool `json:"privileged"`
CapAdd Strings `json:"cap_add"`
Cmd Strings `json:"cmd"`
}
type Ports struct {

View File

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

View File

@@ -20,12 +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"`
}

8
model/docker.go Normal file
View File

@@ -0,0 +1,8 @@
package model
type DockerStatsModel struct {
Icon string `json:"icon"`
Title string `json:"title"`
Data interface{} `json:"data"`
Pre interface{} `json:"pre"`
}

6
model/heart.go Normal file
View File

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

View File

@@ -17,20 +17,22 @@ type UdpPorts struct {
/*******************使用gorm支持json************************************/
type PortMap struct {
ContainerPort string `json:"container,omitempty"`
CommendPort string `json:"host,omitempty"`
ContainerPort string `json:"container"`
CommendPort string `json:"host"`
Protocol string `json:"protocol"`
Desc string `json:"desc"`
Type int `json:"type"`
}
type PortArrey []PortMap
type PortArray []PortMap
// Value 实现方法
func (p PortArrey) Value() (driver.Value, error) {
func (p PortArray) Value() (driver.Value, error) {
return json.Marshal(p)
}
// Scan 实现方法
func (p *PortArrey) Scan(input interface{}) error {
func (p *PortArray) Scan(input interface{}) error {
return json.Unmarshal(input.([]byte), p)
}
@@ -41,20 +43,22 @@ func (p *PortArrey) Scan(input interface{}) error {
type Env struct {
Name string `json:"container"`
Value string `json:"host"`
Desc string `json:"desc"`
Type int `json:"type"`
}
type JSON json.RawMessage
type EnvArrey []Env
type EnvArray []Env
// Value 实现方法
func (p EnvArrey) Value() (driver.Value, error) {
func (p EnvArray) Value() (driver.Value, error) {
return json.Marshal(p)
//return .MarshalJSON()
}
// Scan 实现方法
func (p *EnvArrey) Scan(input interface{}) error {
func (p *EnvArray) Scan(input interface{}) error {
return json.Unmarshal(input.([]byte), p)
}
@@ -65,17 +69,19 @@ func (p *EnvArrey) Scan(input interface{}) error {
type PathMap struct {
ContainerPath string `json:"container"`
Path string `json:"host"`
Type int `json:"type"`
Desc string `json:"desc"`
}
type PathArrey []PathMap
type PathArray []PathMap
// Value 实现方法
func (p PathArrey) Value() (driver.Value, error) {
func (p PathArray) Value() (driver.Value, error) {
return json.Marshal(p)
}
// Scan 实现方法
func (p *PathArrey) Scan(input interface{}) error {
func (p *PathArray) Scan(input interface{}) error {
return json.Unmarshal(input.([]byte), p)
}
@@ -103,17 +109,21 @@ type CustomizationPostData struct {
Index string `json:"index"`
Icon string `json:"icon"`
Image string `json:"image"`
Envs EnvArrey `json:"envs"`
Ports PortArrey `json:"ports"`
Volumes PathArrey `json:"volumes"`
Devices PathArrey `json:"devices"`
Envs EnvArray `json:"envs"`
Ports PortArray `json:"ports"`
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"`
}

View File

@@ -1,19 +1,17 @@
package model
import "time"
type IOCountersStat struct {
Name string `json:"name"` // interface name
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
PacketsSent uint64 `json:"packetsSent"` // number of packets sent
PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
State string `json:"state"`
DateTime time.Time `json:"date_time"`
Name string `json:"name"` // interface name
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
PacketsSent uint64 `json:"packetsSent"` // number of packets sent
PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD)
Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving
Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending
State string `json:"state"`
Time int64 `json:"time"`
}

6
model/notify.go Normal file
View File

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

54
model/person.go Normal file
View File

@@ -0,0 +1,54 @@
package model
import "time"
type PersionModel struct {
Token string `json:"token"`
Ips []string `json:"ips"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
//记录链接状态
type ConnectState struct {
From string `json:"from"`
To string `json:"to"`
Type string `json:"type"` //current state 1:ready 2:ok
CreatedAt time.Time `json:"created_at"`
UUId string `json:"uuid"` //对接标识
}
type MessageModel struct {
Type string `json:"type"`
Data interface{} `json:"data"`
UUId string `json:"uuid"`
From string `json:"from"`
To string `json:"to"`
}
type TranFileModel struct {
Hash string `json:"hash"` //Verify current fragment integrity
Length int `json:"length"`
Index int `json:"index"`
}
//需要获取文件详情
type FileDetailModel struct {
Path string `json:"path"`
}
//返回文件详情
type FileSummaryModel struct {
Hash string `json:"hash"` //Verify file
Name string `json:"name"`
BlockSize int `json:"block_size"`
Length int `json:"length"`
Size int64 `json:"size"`
Message string `json:"message"`
}
type FriendsModel struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
NickName string `json:"nick_name"`
Desc string `json:"desc"`
ShareId string `json:"share_id"`
}

69
model/smartctl_model.go Normal file
View File

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

View File

@@ -15,13 +15,21 @@ type UserModel struct {
Head string
Email string
Description string
Initialized bool
Avatar string
NickName string
}
//服务配置
type ServerModel struct {
HttpPort string
RunMode string
ServerApi string
HttpPort string
RunMode string
ServerApi string
LockAccount bool
Handshake string
Token string
UDPPort string
USBAutoMount string
}
//服务配置
@@ -34,6 +42,7 @@ type APPModel struct {
TimeFormat string
DateFormat string
ProjectPath string
RootPath string
}
//公共返回模型
@@ -43,13 +52,6 @@ type Result struct {
Data interface{} `json:"data" example:"返回结果"`
}
//zeritier相关
type ZeroTierModel struct {
UserName string
PWD string
Token string
}
//redis配置文件
type RedisModel struct {
Host string
@@ -63,4 +65,16 @@ type SystemConfig struct {
ConfigStr string `json:"config_str"`
WidgetList string `json:"widget_list"`
ConfigPath string `json:"config_path"`
SyncPort string `json:"sync_port"`
SyncKey string `json:"sync_key"`
Analyse string `json:"analyse"`
}
type CasaOSGlobalVariables struct {
AppChange bool
}
type FileSetting struct {
ShareDir []string `json:"share_dir" delim:"|"`
DownloadDir string `json:"download_dir"`
}

View File

@@ -1,3 +1 @@
package model

8
model/system_app/sync.go Normal file
View File

@@ -0,0 +1,8 @@
package system_app
import "encoding/xml"
type SyncConfig struct {
XMLName xml.Name `xml:"configuration"`
Key string `xml:"gui>apikey"`
}

9
model/user.go Normal file
View File

@@ -0,0 +1,9 @@
package model
type UserInfo struct {
NickName string `json:"nick_name"`
Desc string `json:"desc"`
ShareId string `json:"share_id"`
Avatar string `json:"avatar"`
Version int `json:"version,omitempty"`
}

View File

@@ -1,7 +1,13 @@
package model
import "time"
type Path struct {
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"is_dir"`
Name string `json:"name"` //File name or document name
Path string `json:"path"` //Full path to file or folder
IsDir bool `json:"is_dir"` //Is it a folder
Date time.Time `json:"date"`
Size int64 `json:"size"` //File Size
Type string `json:"type,omitempty"`
Label string `json:"label,omitempty"`
}

11
pkg/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,11 @@
package cache
import (
"time"
"github.com/patrickmn/go-cache"
)
func Init() *cache.Cache {
return cache.New(5*time.Minute, 60*time.Second)
}

View File

@@ -25,14 +25,15 @@ var AppInfo = &model.APPModel{}
//redis相关配置
var RedisInfo = &model.RedisModel{}
//zerotier相关
var ZeroTierInfo = &model.ZeroTierModel{}
//server相关
var ServerInfo = &model.ServerModel{}
var SystemConfigInfo = &model.SystemConfig{}
var CasaOSGlobalVariables = &model.CasaOSGlobalVariables{}
var FileSettingInfo = &model.FileSetting{}
var Cfg *ini.File
//初始化设置,获取系统的部分信息。
@@ -52,10 +53,10 @@ func InitSetup(config string) {
mapTo("user", UserInfo)
mapTo("app", AppInfo)
mapTo("zerotier", ZeroTierInfo)
mapTo("redis", RedisInfo)
mapTo("server", ServerInfo)
mapTo("system", SystemConfigInfo)
mapTo("file", FileSettingInfo)
SystemConfigInfo.ConfigPath = configDir
// AppInfo.ProjectPath = getCurrentDirectory() //os.Getwd()

View File

@@ -1,13 +1,30 @@
package config
import "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
import (
"runtime"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
)
//检查目录是否存在
func mkdirDATAAll() {
dirArray := [7]string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
sysType := runtime.GOOS
var dirArray []string
if sysType == "linux" {
dirArray = []string{"/DATA/AppData", "/DATA/Documents", "/DATA/Downloads", "/DATA/Gallery", "/DATA/Media/Movies", "/DATA/Media/TV Shows", "/DATA/Media/Music"}
}
if sysType == "windows" {
dirArray = []string{"C:\\CasaOS\\DATA\\AppData", "C:\\CasaOS\\DATA\\Documents", "C:\\CasaOS\\DATA\\Downloads", "C:\\CasaOS\\DATA\\Gallery", "C:\\CasaOS\\DATA\\Media/Movies", "C:\\CasaOS\\DATA\\Media\\TV Shows", "C:\\CasaOS\\DATA\\Media\\Music"}
}
if sysType == "darwin" {
dirArray = []string{"./CasaOS/DATA/AppData", "./CasaOS/DATA/Documents", "./CasaOS/DATA/Downloads", "./CasaOS/DATA/Gallery", "./CasaOS/DATA/Media/Movies", "./CasaOS/DATA/Media/TV Shows", "./CasaOS/DATA/Media/Music"}
}
for _, v := range dirArray {
file.IsNotExistMkDir(v)
}
}
func UpdateSetup() {

View File

@@ -4,30 +4,35 @@ import (
"bytes"
json2 "encoding/json"
"fmt"
"github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"io"
"regexp"
"strconv"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
func NewSshClient() (*ssh.Client, error) {
func NewSshClient(user, password string) (*ssh.Client, error) {
// connet to ssh
// addr = fmt.Sprintf("%s:%d", host, port)
config := &ssh.ClientConfig{
Timeout: time.Second * 5,
User: "root",
User: user,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
//HostKeyCallback: ,
//HostKeyCallback: hostKeyCallBackFunc(h.Host),
}
//if h.Type == "password" {
config.Auth = []ssh.AuthMethod{ssh.Password("123456")}
config.Auth = []ssh.AuthMethod{ssh.Password(password)}
//} else {
// config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(h.Key)}
//}
addr := fmt.Sprintf("%s:%d", "192.168.2.142", 22)
addr := fmt.Sprintf("%s:%d", "127.0.0.1", 22)
c, err := ssh.Dial("tcp", addr, config)
if err != nil {
return nil, err
@@ -98,6 +103,98 @@ const (
wsMsgResize = "resize"
)
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
func ReceiveWsMsgUser(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
//tells other go routine quit
username := ""
for {
//read websocket msg
_, wsData, err := wsConn.ReadMessage()
if err != nil {
return ""
}
msgObj := wsMsg{}
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
msgObj.Type = "cmd"
msgObj.Cmd = string(wsData)
}
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
//}
switch msgObj.Type {
case wsMsgCmd:
//handle xterm.js stdin
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
decodeBytes := []byte(msgObj.Cmd)
if msgObj.Cmd == "\u007f" {
if len(username) == 0 {
continue
}
wsConn.WriteMessage(websocket.TextMessage, []byte("\b\x1b[K"))
username = username[:len(username)-1]
continue
}
if msgObj.Cmd == "\r" {
return username
}
username += msgObj.Cmd
if err := wsConn.WriteMessage(websocket.TextMessage, decodeBytes); err != nil {
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
}
//write input cmd to log buffer
if _, err := logBuff.Write(decodeBytes); err != nil {
logrus.WithError(err).Error("write received cmd into log buffer failed")
}
}
}
}
func ReceiveWsMsgPassword(wsConn *websocket.Conn, logBuff *bytes.Buffer) string {
//tells other go routine quit
password := ""
for {
//read websocket msg
_, wsData, err := wsConn.ReadMessage()
if err != nil {
logrus.WithError(err).Error("reading webSocket message failed")
return ""
}
msgObj := wsMsg{}
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
msgObj.Type = "cmd"
msgObj.Cmd = string(wsData)
}
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
//}
switch msgObj.Type {
case wsMsgCmd:
//handle xterm.js stdin
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
if msgObj.Cmd == "\r" {
return password
}
if msgObj.Cmd == "\u007f" {
if len(password) == 0 {
continue
}
password = password[:len(password)-1]
continue
}
password += msgObj.Cmd
}
}
}
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
func (ssConn *SshConn) ReceiveWsMsg(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
//tells other go routine quit
@@ -187,6 +284,64 @@ func flushComboOutput(w *wsBufferWriter, wsConn *websocket.Conn) error {
}
return nil
}
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
func (ssConn *SshConn) Login(wsConn *websocket.Conn, logBuff *bytes.Buffer, exitCh chan bool) {
//tells other go routine quit
defer setQuit(exitCh)
for {
select {
case <-exitCh:
return
default:
//read websocket msg
_, wsData, err := wsConn.ReadMessage()
if err != nil {
logrus.WithError(err).Error("reading webSocket message failed")
return
}
//unmashal bytes into struct
//msgObj := wsMsg{
// Type: "cmd",
// Cmd: "",
// Rows: 50,
// Cols: 180,
//}
msgObj := wsMsg{}
if err := json2.Unmarshal(wsData, &msgObj); err != nil {
msgObj.Type = "cmd"
msgObj.Cmd = string(wsData)
}
//if err := json.Unmarshal(wsData, &msgObj); err != nil {
// logrus.WithError(err).WithField("wsData", string(wsData)).Error("unmarshal websocket message failed")
//}
switch msgObj.Type {
case wsMsgResize:
//handle xterm.js size change
if msgObj.Cols > 0 && msgObj.Rows > 0 {
if err := ssConn.Session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
logrus.WithError(err).Error("ssh pty change windows size failed")
}
}
case wsMsgCmd:
//handle xterm.js stdin
//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
decodeBytes := []byte(msgObj.Cmd)
if err != nil {
logrus.WithError(err).Error("websock cmd string base64 decoding failed")
}
if _, err := ssConn.StdinPipe.Write(decodeBytes); err != nil {
logrus.WithError(err).Error("ws cmd bytes write to ssh.stdin pipe failed")
}
//write input cmd to log buffer
if _, err := logBuff.Write(decodeBytes); err != nil {
logrus.WithError(err).Error("write received cmd into log buffer failed")
}
}
}
}
}
func (ssConn *SshConn) SessionWait(quitChan chan bool) {
if err := ssConn.Session.Wait(); err != nil {
logrus.WithError(err).Error("ssh session wait failed")
@@ -241,7 +396,7 @@ func WsReaderCopy(reader *websocket.Conn, writer io.Writer) {
if err = json2.Unmarshal(p, &msgObj); err != nil {
writer.Write(p)
} else if msgObj.Type == wsMsgResize {
writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r" ))
writer.Write([]byte("stty rows " + strconv.Itoa(msgObj.Rows) + " && stty cols " + strconv.Itoa(msgObj.Cols) + " \r"))
}
}
}

View File

@@ -1,12 +1,11 @@
package docker
import "strings"
func GetDir(id, envName string) string {
var path string
switch envName {
case "/config":
path = "/oasis/app_data/" + id + "/"
default:
//path = "/media"
if strings.Contains(envName, "$AppID") && len(id) > 0 {
return strings.ReplaceAll(envName, "$AppID", id)
}
return path
return envName
}

View File

@@ -0,0 +1,10 @@
package docker
import (
"fmt"
"testing"
)
func TestGetDir(t *testing.T) {
fmt.Println(GetDir("", "config"))
}

View File

@@ -6,7 +6,6 @@ import (
"golang.org/x/oauth2"
)
func GetGithubClient() *github.Client {
ctx := context.Background()
ts := oauth2.StaticTokenSource(

51
pkg/quic_helper/config.go Normal file
View File

@@ -0,0 +1,51 @@
package quic_helper
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"math/big"
"github.com/lucas-clemente/quic-go"
)
// Setup a bare-bones TLS config for the server
func GetGenerateTLSConfig(token string) *tls.Config {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
panic(err)
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
panic(err)
}
return &tls.Config{
Certificates: []tls.Certificate{tlsCert},
NextProtos: []string{token},
SessionTicketsDisabled: true,
}
}
func GetClientTlsConfig(otherToken string) *tls.Config {
return &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{otherToken},
SessionTicketsDisabled: true,
}
}
func GetQUICConfig() *quic.Config {
return &quic.Config{
ConnectionIDLength: 4,
KeepAlive: true,
}
}

View File

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

View File

@@ -7,7 +7,7 @@ import (
"strings"
)
func GetCtrlUrl(host,device string) string {
func GetCtrlUrl(host, device string) string {
request := ctrlUrlRequest(host, device)
response, _ := http.DefaultClient.Do(request)
resultBody, _ := ioutil.ReadAll(response.Body)
@@ -86,4 +86,4 @@ func resolve(resultStr string) string {
}
}
return controlURL
}
}

View File

@@ -22,21 +22,21 @@ func send() (string, error) {
"ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" +
"MAN: \"ssdp:discover\"\r\n" + "MX: 3\r\n\r\n"
var conn *net.UDPConn
remotAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
remoteAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
if err != nil {
return "", errors.New("组播地址格式不正确")
}
locaAddr, err := net.ResolveUDPAddr("udp", ip_helper2.GetLoclIp()+":")
localAddr, err := net.ResolveUDPAddr("udp", ip_helper2.GetLoclIp()+":")
if err != nil {
return "", errors.New("本地ip地址格式不正确")
}
conn, err = net.ListenUDP("udp", locaAddr)
conn, err = net.ListenUDP("udp", localAddr)
defer conn.Close()
if err != nil {
return "", errors.New("监听udp出错")
}
_, err = conn.WriteToUDP([]byte(str), remotAddr)
_, err = conn.WriteToUDP([]byte(str), remoteAddr)
if err != nil {
return "", errors.New("发送msg到组播地址出错")
}

View File

@@ -5,4 +5,4 @@ import "testing"
func TestGateway(t *testing.T) {
Gateway()
}
}

View File

@@ -2,40 +2,37 @@ package upnp
import (
"bytes"
"github.com/pkg/errors"
"net/http"
"strconv"
"strings"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/pkg/errors"
)
//
////添加一个端口映射
func (n *Upnp)AddPortMapping(localPort, remotePort int, protocol string) (err error) {
defer func(err error) {
func (n *Upnp) AddPortMapping(localPort, remotePort int, protocol string) (err error) {
defer func() {
if errTemp := recover(); errTemp != nil {
//log.Println("upnp模块报错了", errTemp)
err = errTemp.(error)
loger2.NewOLoger().Error("upnp模块报错了", errTemp)
}
}(err)
if issuccess := addSend(localPort, remotePort, protocol,n.GatewayHost, n.CtrlUrl,n.LocalHost); issuccess {
}()
if isSuccess := addSend(localPort, remotePort, protocol, n.GatewayHost, n.CtrlUrl, n.LocalHost); isSuccess {
return nil
} else {
return errors.New("添加一个端口映射失败")
}
return
}
func addSend(localPort, remotePort int, protocol, host, ctrUrl,localHost string) bool {
request := addRequest(localPort, remotePort, protocol, host, ctrUrl,localHost)
func addSend(localPort, remotePort int, protocol, host, ctrUrl, localHost string) bool {
request := addRequest(localPort, remotePort, protocol, host, ctrUrl, localHost)
response, _ := http.DefaultClient.Do(request)
defer response.Body.Close()
//resultBody, _ := ioutil.ReadAll(response.Body)
//fmt.Println(string(resultBody))
if response.StatusCode == 200 {
return true
}
return false
return response.StatusCode == 200
}
type Node struct {
@@ -45,7 +42,7 @@ type Node struct {
Child []Node
}
func addRequest(localPort, remotePort int, protocol string, gatewayHost, ctlUrl,localHost string) *http.Request {
func addRequest(localPort, remotePort int, protocol string, gatewayHost, ctlUrl, localHost string) *http.Request {
//请求头
header := http.Header{}
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
@@ -109,27 +106,25 @@ func (n *Node) BuildXML() string {
return buf.String()
}
func (n *Upnp)DelPortMapping(remotePort int, protocol string) bool {
issuccess := delSendSend(remotePort, protocol,n.GatewayHost,n.CtrlUrl)
if issuccess {
func (n *Upnp) DelPortMapping(remotePort int, protocol string) bool {
isSuccess := delSendSend(remotePort, protocol, n.GatewayHost, n.CtrlUrl)
if isSuccess {
//this.MappingPort.delMapping(remotePort, protocol)
//fmt.Println("删除了一个端口映射: remote:", remotePort)
}
return issuccess
return isSuccess
}
func delSendSend(remotePort int, protocol,host,ctlUrl string) bool {
delrequest := delbuildRequest(remotePort, protocol,host,ctlUrl)
func delSendSend(remotePort int, protocol, host, ctlUrl string) bool {
delrequest := delbuildRequest(remotePort, protocol, host, ctlUrl)
response, _ := http.DefaultClient.Do(delrequest)
//resultBody, _ := ioutil.ReadAll(response.Body)
defer response.Body.Close()
if response.StatusCode == 200 {
// log.Println(string(resultBody))
return true
}
return false
return response.StatusCode == 200
}
func delbuildRequest(remotePort int, protocol,host,ctlUrl string) *http.Request {
func delbuildRequest(remotePort int, protocol, host, ctlUrl string) *http.Request {
//请求头
header := http.Header{}
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
@@ -160,4 +155,4 @@ func delbuildRequest(remotePort int, protocol,host,ctlUrl string) *http.Request
request.Header = header
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
return request
}
}

View File

@@ -7,10 +7,10 @@ import (
type Upnp struct {
LocalHost string `json:"local_host"`
GatewayName string `json:"gateway_name"` //网关名称
GatewayHost string `json:"gateway_host"` //网关ip和端口
GatewayName string `json:"gateway_name"` //网关名称
GatewayHost string `json:"gateway_host"` //网关ip和端口
DeviceDescUrl string `json:"device_desc_url"` //设备描述url
CtrlUrl string `json:"ctrl_url"` //控制请求url
CtrlUrl string `json:"ctrl_url"` //控制请求url
}
func Testaaa() {
@@ -23,4 +23,3 @@ func Testaaa() {
fmt.Println("gateway ip address: ", upnpMan.Gateway.Host)
}
}

View File

@@ -6,4 +6,4 @@ import (
func TestTestaaa(t *testing.T) {
(Testaaa())
}
}

View File

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

View File

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

81
pkg/utils/file/block.go Normal file
View File

@@ -0,0 +1,81 @@
package file
import (
"crypto/md5"
"encoding/hex"
"io"
"math"
"os"
"strconv"
)
// Get info of block
func GetBlockInfo(fileSize int64) (blockSize int, length int) {
switch {
case fileSize <= 1<<28: //256M
blockSize = 1 << 17 //128kb
case fileSize <= 1<<29: //512M
blockSize = 1 << 18 //256kb
case fileSize <= 1<<30: //1G
blockSize = 1 << 19 //512kb
case fileSize <= 1<<31: //2G
blockSize = 1 << 20 //(mb)
case fileSize <= 1<<32: //4G
blockSize = 1 << 21 //2mb
case fileSize <= 1<<33: //8G
blockSize = 1 << 22 //4mb
case fileSize <= 1<<34: //16g
blockSize = 1 << 23 //8mb
default:
blockSize = 1 << 24 //16mb
}
temp := float64(fileSize) / float64(blockSize)
length = int(math.Ceil(temp))
return
}
//get the hash of the data
func GetHashByContent(data []byte) string {
sum := md5.Sum(data)
return hex.EncodeToString(sum[:])
}
//get the hash of the data
func GetHashByPath(path string) string {
pFile, err := os.Open(path)
if err != nil {
return ""
}
defer pFile.Close()
md5h := md5.New()
io.Copy(md5h, pFile)
return hex.EncodeToString(md5h.Sum(nil))
}
//Comparison data hash
func ComparisonHash(data []byte, hash string) bool {
sum := md5.Sum(data)
return hex.EncodeToString(sum[:]) == hash
}
//get prefix byte length
func PrefixLength(byteLength int) []byte {
lengthByte := []byte{'0', '0', '0', '0', '0', '0'}
bSize := strconv.Itoa(byteLength)
cha := 6 - len(bSize)
for i := len(bSize); i > 0; i-- {
lengthByte[cha+i-1] = bSize[i-1]
}
return lengthByte
}
//get data byte length
func DataLength(length int) []byte {
lengthByte := []byte{'0', '0', '0', '0', '0', '0', '0', '0'}
bSize := strconv.Itoa(length)
cha := 8 - len(bSize)
for i := len(bSize); i > 0; i-- {
lengthByte[cha+i-1] = bSize[i-1]
}
return lengthByte
}

View File

@@ -1,11 +1,17 @@
package file
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"os"
"path"
path2 "path"
"path/filepath"
"strconv"
"strings"
)
// GetSize get the file size
@@ -35,7 +41,7 @@ func CheckPermission(src string) bool {
// IsNotExistMkDir create a directory if it does not exist
func IsNotExistMkDir(src string) error {
if notExist := CheckNotExist(src); notExist == true {
if notExist := CheckNotExist(src); notExist {
if err := MkDir(src); err != nil {
return err
}
@@ -50,6 +56,7 @@ func MkDir(src string) error {
if err != nil {
return err
}
os.Chmod(src, 0777)
return nil
}
@@ -135,6 +142,21 @@ func CreateFile(path string) error {
return nil
}
func CreateFileAndWriteContent(path string, content string) error {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
write.WriteString(content)
write.Flush()
return nil
}
// IsNotExistMkDir create a directory if it does not exist
func IsNotExistCreateFile(src string) error {
if notExist := CheckNotExist(src); notExist == true {
@@ -145,3 +167,169 @@ func IsNotExistCreateFile(src string) error {
return nil
}
func ReadFullFile(path string) []byte {
file, err := os.Open(path)
if err != nil {
return []byte("")
}
defer file.Close()
content, err := ioutil.ReadAll(file)
if err != nil {
return []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
lastPath := src[strings.LastIndex(src, "/")+1:]
if !strings.HasSuffix(dst, "/") {
dst += "/"
}
dstPath := dst
dst += lastPath
for i := 0; Exists(dst); i++ {
name := strings.Split(lastPath, ".")
nameIndex := 0
if len(name) > 2 {
nameIndex = len(name) - 2
}
name[nameIndex] = name[nameIndex] + "(Copy)"
dst = dstPath
for _, v := range name {
dst += v + "."
}
dst = strings.TrimSuffix(dst, ".")
}
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())
}
//Check for duplicate file names
func GetNoDuplicateFileName(fullPath string) string {
path, fileName := filepath.Split(fullPath)
fileSuffix := path2.Ext(fileName)
filenameOnly := strings.TrimSuffix(fileName, fileSuffix)
for i := 0; Exists(fullPath); i++ {
fullPath = path2.Join(path, filenameOnly+"("+strconv.Itoa(i+1)+")"+fileSuffix)
}
return fullPath
}
// Dir copies a whole directory recursively
func CopyDir(src string, dst string) error {
var err error
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
}
dstPath := dst
lastPath := src[strings.LastIndex(src, "/")+1:]
dst += "/" + lastPath
for i := 0; Exists(dst); i++ {
dst = dstPath + "/" + lastPath + strconv.Itoa(i+1)
}
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 := dst //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
}
//文件写入临时目录
func WriteToPath(data []byte, path, name string) error {
fullPath := path
if strings.HasSuffix(path, "/") {
fullPath += name
} else {
fullPath += "/" + name
}
IsNotExistCreateFile(fullPath)
file, err := os.OpenFile(fullPath,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0666,
)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(data)
return err
}
//最终拼接
func SpliceFiles(dir, path string, length int, startPoint int) error {
fullPath := path
IsNotExistCreateFile(fullPath)
file, _ := os.OpenFile(fullPath,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0666,
)
defer file.Close()
bufferedWriter := bufio.NewWriter(file)
for i := 0; i < length+startPoint; i++ {
data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
if err != nil {
return err
}
_, err = bufferedWriter.Write(data)
if err != nil {
return err
}
}
bufferedWriter.Flush()
return nil
}

176
pkg/utils/file/reader.go Normal file
View File

@@ -0,0 +1,176 @@
package file
import (
"bytes"
"fmt"
"io"
"os"
)
var (
buffSize = 1 << 20
)
// ReadLineFromEnd --
type ReadLineFromEnd struct {
f *os.File
fileSize int
bwr *bytes.Buffer
lineBuff []byte
swapBuff []byte
isFirst bool
}
// NewReadLineFromEnd --
func NewReadLineFromEnd(name string) (rd *ReadLineFromEnd, err error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
info, err := f.Stat()
if info.IsDir() {
return nil, fmt.Errorf("not file")
}
fileSize := int(info.Size())
rd = &ReadLineFromEnd{
f: f,
fileSize: fileSize,
bwr: bytes.NewBuffer([]byte{}),
lineBuff: make([]byte, 0),
swapBuff: make([]byte, buffSize),
isFirst: true,
}
return rd, nil
}
// ReadLine 结尾包含'\n'
func (c *ReadLineFromEnd) ReadLine() (line []byte, err error) {
var ok bool
for {
ok, err = c.buff()
if err != nil {
return nil, err
}
if ok {
break
}
}
line, err = c.bwr.ReadBytes('\n')
if err == io.EOF && c.fileSize > 0 {
err = nil
}
return line, err
}
// Close --
func (c *ReadLineFromEnd) Close() (err error) {
return c.f.Close()
}
func (c *ReadLineFromEnd) buff() (ok bool, err error) {
if c.fileSize == 0 {
return true, nil
}
if c.bwr.Len() >= buffSize {
return true, nil
}
offset := 0
if c.fileSize > buffSize {
offset = c.fileSize - buffSize
}
_, err = c.f.Seek(int64(offset), 0)
if err != nil {
return false, err
}
n, err := c.f.Read(c.swapBuff)
if err != nil && err != io.EOF {
return false, err
}
if c.fileSize < n {
n = c.fileSize
}
if n == 0 {
return true, nil
}
for {
m := bytes.LastIndex(c.swapBuff[:n], []byte{'\n'})
if m == -1 {
break
}
if m < n-1 {
err = c.writeLine(c.swapBuff[m+1 : n])
if err != nil {
return false, err
}
ok = true
} else if m == n-1 && !c.isFirst {
err = c.writeLine(nil)
if err != nil {
return false, err
}
ok = true
}
n = m
if n == 0 {
break
}
}
if n > 0 {
reverseBytes(c.swapBuff[:n])
c.lineBuff = append(c.lineBuff, c.swapBuff[:n]...)
}
if offset == 0 {
err = c.writeLine(nil)
if err != nil {
return false, err
}
ok = true
}
c.fileSize = offset
if c.isFirst {
c.isFirst = false
}
return ok, nil
}
func (c *ReadLineFromEnd) writeLine(b []byte) (err error) {
if len(b) > 0 {
_, err = c.bwr.Write(b)
if err != nil {
return err
}
}
if len(c.lineBuff) > 0 {
reverseBytes(c.lineBuff)
_, err = c.bwr.Write(c.lineBuff)
if err != nil {
return err
}
c.lineBuff = c.lineBuff[:0]
}
_, err = c.bwr.Write([]byte{'\n'})
if err != nil {
return err
}
return nil
}
func reverseBytes(b []byte) {
n := len(b)
if n <= 1 {
return
}
for i := 0; i < n; i++ {
k := n - 1
if k != i {
b[i], b[k] = b[k], b[i]
}
n--
}
}

View File

@@ -3,21 +3,23 @@ package httper
import (
"bytes"
"encoding/json"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/tidwall/gjson"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/tidwall/gjson"
)
//发送GET请求
//url:请求地址
//response:请求返回的内容
func Get(url string, head map[string]string) (response string) {
client := http.Client{Timeout: 30 * time.Second}
client := &http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequest("GET", url, nil)
req.BasicAuth()
for k, v := range head {
req.Header.Add(k, v)
}
@@ -52,10 +54,13 @@ func Get(url string, head map[string]string) (response string) {
//发送POST请求
//url:请求地址data:POST请求提交的数据,contentType:请求体格式application/json
//content:请求放回的内容
func Post(url string, data interface{}, contentType string) (content string) {
jsonStr, _ := json.Marshal(data)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
func Post(url string, data []byte, contentType string, head map[string]string) (content string) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
req.Header.Add("content-type", contentType)
for k, v := range head {
req.Header.Add(k, v)
}
if err != nil {
panic(err)
}
@@ -63,7 +68,8 @@ func Post(url string, data interface{}, contentType string) (content string) {
client := &http.Client{Timeout: 5 * time.Second}
resp, error := client.Do(req)
if error != nil {
panic(error)
fmt.Println(error)
return
}
defer resp.Body.Close()

View File

@@ -1 +0,0 @@
package utils

View File

@@ -2,11 +2,12 @@ package jwt
import (
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS/model"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/gin-gonic/gin"
"net/http"
)
func JWT(swagHandler gin.HandlerFunc) gin.HandlerFunc {

View File

@@ -2,13 +2,13 @@ package loger
import (
"fmt"
"github.com/IceWhaleTech/CasaOS/pkg/config"
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"log"
"os"
"path/filepath"
"runtime"
"time"
"github.com/IceWhaleTech/CasaOS/pkg/config"
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
)
//定义一个int的别名
@@ -20,6 +20,7 @@ type OLog interface {
Warn(v ...interface{})
Error(v ...interface{})
Fatal(v ...interface{})
Path() string
}
type oLog struct {
@@ -47,9 +48,8 @@ const (
func LogSetup() {
var err error
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
fileName := fmt.Sprintf("%s%s.%s",
fileName := fmt.Sprintf("%s.%s",
config.AppInfo.LogSaveName,
time.Now().Format(config.AppInfo.DateStrFormat),
config.AppInfo.LogFileExt,
)
F, err = file2.MustOpen(fileName, filePath)
@@ -60,7 +60,14 @@ func LogSetup() {
logger = log.New(F, DefaultPrefix, log.LstdFlags)
}
func (o *oLog) Path() string {
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
fileName := fmt.Sprintf("%s.%s",
config.AppInfo.LogSaveName,
config.AppInfo.LogFileExt,
)
return filePath + fileName
}
func (o *oLog) Debug(v ...interface{}) {
setPrefix(DEBUG)
logger.Println(v)

View File

@@ -7,16 +7,27 @@ const (
ERROR_AUTH_TOKEN = 401
//user
PWD_INVALID = 10001
PWD_INVALID = 10001
PWD_IS_EMPTY = 10002
PWD_INVALID_OLD = 10003
ACCOUNT_LOCK = 10004
//system
DIR_ALREADY_EXISTS = 20001
FILE_ALREADY_EXISTS = 20002
FILE_OR_DIR_EXISTS = 20003
PORT_IS_OCCUPIED = 20004
//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
@@ -25,38 +36,69 @@ const (
//file
FILE_DOES_NOT_EXIST = 60001
FILE_READ_ERROR = 60002
FILE_DELETE_ERROR = 60003
DIR_NOT_EXISTS = 60004
//shortcuts
SHORTCUTS_URL_ERROR = 70001
//person
PERSON_REMOTE_ERROR = 80001
PERSON_DOWN_NOT_EXIST = 80002
PERSON_EXIST_DOWNLOAD = 80003
PERSON_NOT_EXIST_USER = 80004
PERSON_EXIST_FRIEND = 80005
PERSON_MYSELF = 80006
)
var MsgFlags = map[int]string{
SUCCESS: "ok",
ERROR: "fail",
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: "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",
DIR_NOT_EXISTS: "Directory does not exist",
FILE_READ_ERROR: "File read error",
FILE_DELETE_ERROR: "Delete error",
SHORTCUTS_URL_ERROR: "URL error",
PERSON_REMOTE_ERROR: "Remote connection error",
PERSON_DOWN_NOT_EXIST: "Download record does not exist",
PERSON_EXIST_DOWNLOAD: "The same download task exists",
PERSON_EXIST_FRIEND: "Friend already exist",
PERSON_NOT_EXIST_USER: "User does not exist",
PERSON_MYSELF: "You can not add yourself",
}
//获取错误信息

View File

@@ -47,6 +47,7 @@ func IsPortAvailable(port int, t string) bool {
uc, err := net.ListenUDP("udp", sadd)
if err != nil {
fmt.Println(err.Error())
return false
} else {
defer uc.Close()

View File

@@ -6,5 +6,5 @@ import (
)
func TestRandomString(t *testing.T) {
fmt.Println(RandomString(6,true))
}
fmt.Println(RandomString(6, true))
}

View File

@@ -1,8 +1,9 @@
package sort
import (
"github.com/IceWhaleTech/CasaOS/model"
"sort"
"github.com/IceWhaleTech/CasaOS/model"
)
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool

View File

@@ -1,47 +0,0 @@
package zerotier
import (
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/tidwall/gjson"
"net/http"
)
func PostData(url, token string, data string) interface{} {
body, code := httper2.ZeroTierPostJson(url, data, GetHead(token))
if code != http.StatusOK {
return ""
}
result := gjson.Parse(body)
return result.Value()
}
func GetData(url, token string) interface{} {
body, code := httper2.ZeroTierGet(url, GetHead(token))
if code != http.StatusOK {
return ""
}
result := gjson.Parse(body)
return result.Value()
}
func DeleteMember(url, token string) interface{} {
body, code := httper2.ZeroTierDelete(url, GetHead(token))
if code != http.StatusOK {
return ""
}
result := gjson.Parse(body)
return result.Value()
}
func GetHead(token string) map[string]string {
var head = make(map[string]string)
head["Authorization"] = "Bearer " + token
head["Content-Type"] = "application/json"
return head
}

View File

@@ -4,6 +4,7 @@
package route
import (
_ "github.com/IceWhaleTech/CasaOS/docs"
ginSwagger "github.com/swaggo/gin-swagger"
swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles"
)

293
route/init.go Normal file
View File

@@ -0,0 +1,293 @@
package route
import (
"encoding/json"
"encoding/xml"
"fmt"
"runtime"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/system_app"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
uuid "github.com/satori/go.uuid"
)
func InitFunction() {
go checkSystemApp()
Update2_3()
CheckSerialDiskMount()
CheckToken2_11()
}
var syncIsExistence = false
func installSyncthing(appId string) {
var appInfo model.ServerAppList
m := model.CustomizationPostData{}
var dockerImage string
var dockerImageVersion string
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "system", "us_en")
dockerImage = appInfo.Image
dockerImageVersion = appInfo.ImageVersion
if len(appInfo.ImageVersion) == 0 {
dockerImageVersion = "latest"
}
if appInfo.NetworkModel != "host" {
for i := 0; i < len(appInfo.Ports); i++ {
if p, _ := strconv.Atoi(appInfo.Ports[i].ContainerPort); port.IsPortAvailable(p, appInfo.Ports[i].Protocol) {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
} else {
if appInfo.Ports[i].Protocol == "tcp" {
if p, err := port.GetAvailablePort("tcp"); err == nil {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
}
} else if appInfo.Ports[i].Protocol == "upd" {
if p, err := port.GetAvailablePort("udp"); err == nil {
appInfo.Ports[i].CommendPort = strconv.Itoa(p)
}
}
}
if appInfo.Ports[i].Type == 0 {
appInfo.PortMap = appInfo.Ports[i].CommendPort
}
}
}
for i := 0; i < len(appInfo.Devices); i++ {
if !file.CheckNotExist(appInfo.Devices[i].ContainerPath) {
appInfo.Devices[i].Path = appInfo.Devices[i].ContainerPath
}
}
if len(appInfo.Tip) > 0 {
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
}
appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
id := uuid.NewV4().String()
installLog := model2.AppNotify{}
// step下载镜像
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)
}
m.CpuShares = 50
m.Envs = appInfo.Envs
m.Memory = int64(appInfo.MaxMemory)
m.Origin = "system"
m.PortMap = appInfo.PortMap
m.Ports = appInfo.Ports
m.Restart = "always"
m.Volumes = appInfo.Volumes
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
}
//stepstart container
err = service.MyService.Docker().DockerContainerStart(id)
if err != nil {
//start container error
return
}
portsStr, _ := json.Marshal(appInfo.Ports)
envsStr, _ := json.Marshal(appInfo.Envs)
volumesStr, _ := json.Marshal(appInfo.Volumes)
devicesStr, _ := json.Marshal(appInfo.Devices)
//step: 保存数据到数据库
md := model2.AppListDBModel{
CustomId: id,
Title: appInfo.Title,
//ScreenshotLink: appInfo.ScreenshotLink,
Slogan: appInfo.Tagline,
Description: appInfo.Description,
//Tags: appInfo.Tags,
Icon: appInfo.Icon,
Version: dockerImageVersion,
ContainerId: containerId,
Image: dockerImage,
Index: appInfo.Index,
PortMap: appInfo.PortMap,
Label: appInfo.Title,
EnableUPNP: false,
Ports: string(portsStr),
Envs: string(envsStr),
Volumes: string(volumesStr),
Position: true,
NetModel: appInfo.NetworkModel,
Restart: m.Restart,
CpuShares: 50,
Memory: int64(appInfo.MaxMemory),
Devices: string(devicesStr),
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
}
service.MyService.App().SaveContainer(md)
checkSystemApp()
}
// check if the system application is installed
func checkSystemApp() {
list := service.MyService.App().GetSystemAppList()
for _, v := range *list {
if v.Image == "linuxserver/syncthing" {
if v.State != "running" {
//stepstart container
service.MyService.Docker().DockerContainerStart(v.CustomId)
}
syncIsExistence = true
if config.SystemConfigInfo.SyncPort != v.Port {
config.SystemConfigInfo.SyncPort = v.Port
}
var paths []model.PathMap
json.Unmarshal([]byte(v.Volumes), &paths)
path := ""
for _, i := range paths {
if i.ContainerPath == "/config" {
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml"
for i := 0; i < 10; i++ {
if file.CheckNotExist(path) {
time.Sleep(1 * time.Second)
} else {
break
}
}
break
}
}
content := file.ReadFullFile(path)
syncConfig := &system_app.SyncConfig{}
xml.Unmarshal(content, &syncConfig)
config.SystemConfigInfo.SyncKey = syncConfig.Key
}
}
if !syncIsExistence {
installSyncthing("74")
}
}
func CheckSerialDiskMount() {
// check mount point
dbList := service.MyService.Disk().GetSerialAll()
list := service.MyService.Disk().LSBLK(true)
mountPoint := make(map[string]string, len(dbList))
//remount
for _, v := range dbList {
mountPoint[v.UUID] = v.MountPoint
}
for _, v := range list {
command.ExecEnabledSMART(v.Path)
if v.Children != nil {
for _, h := range v.Children {
if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
if m, ok := mountPoint[h.UUID]; ok {
//mount point check
volume := m
if !file.CheckNotExist(m) {
for i := 0; file.CheckNotExist(volume); i++ {
volume = m + strconv.Itoa(i+1)
}
}
service.MyService.Disk().MountDisk(h.Path, volume)
if volume != m {
ms := model2.SerialDisk{}
ms.UUID = v.UUID
ms.MountPoint = volume
service.MyService.Disk().UpdateMountPoint(ms)
}
}
}
}
}
}
service.MyService.Disk().RemoveLSBLKCache()
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
}
func Update2_3() {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/assist.sh")
}
func CheckToken2_11() {
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)
}
if len(config.AppInfo.RootPath) == 0 {
config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
config.AppInfo.RootPath = "/casaOS"
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
// if len(config.ServerInfo.Handshake) == 0 {
// config.Cfg.Section("app").Key("RootPath").SetValue("/casaOS")
// config.AppInfo.RootPath = "/casaOS"
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
// }
sysType := runtime.GOOS
if len(config.FileSettingInfo.DownloadDir) == 0 {
downloadPath := "/DATA/Downloads"
if sysType == "windows" {
downloadPath = "C:\\CasaOS\\DATA\\Downloads"
}
if sysType == "darwin" {
downloadPath = "~/CasaOS/DATA/Downloads"
}
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
config.FileSettingInfo.DownloadDir = downloadPath
file.IsNotExistMkDir(config.FileSettingInfo.DownloadDir)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
if len(config.UserInfo.Description) == 0 {
config.Cfg.Section("user").Key("Description").SetValue("nothing")
config.UserInfo.Description = "nothing"
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
if len(config.ServerInfo.Handshake) == 0 {
config.Cfg.Section("server").Key("Handshake").SetValue("socket.casaos.io")
config.ServerInfo.Handshake = "socket.casaos.io"
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
service.MyService.System().ExecUSBAutoMountShell(config.ServerInfo.USBAutoMount)
// str := []string{}
// str = append(str, "ddd")
// str = append(str, "aaa")
// ddd := strings.Join(str, "|")
// config.Cfg.Section("file").Key("ShareDir").SetValue(ddd)
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}

View File

@@ -3,21 +3,24 @@ package route
import (
"net/http"
_ "github.com/IceWhaleTech/CasaOS/docs"
"github.com/IceWhaleTech/CasaOS/middleware"
"github.com/IceWhaleTech/CasaOS/pkg/config"
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"
)
var swagHandler gin.HandlerFunc
var OnlineDemo bool = false
func InitRouter() *gin.Engine {
r := gin.Default()
r.Use(middleware.Cors())
r.Use(gzip.Gzip(gzip.DefaultCompression))
gin.SetMode(config.ServerInfo.RunMode)
r.StaticFS("/ui", http.FS(web.Static))
@@ -28,14 +31,17 @@ func InitRouter() *gin.Engine {
if swagHandler != nil {
r.GET("/swagger/*any", swagHandler)
}
//登录
r.POST("/v1/user/login", v1.Login)
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
r.GET("/v1/user/info", v1.GetUserInfo)
v1Group := r.Group("/v1")
v1Group.Use(jwt2.JWT(swagHandler))
@@ -45,15 +51,19 @@ func InitRouter() *gin.Engine {
{
//chang head
v1UserGroup.POST("/changhead", v1.Up_Load_Head)
v1UserGroup.POST("/head", v1.PostUserHead)
//chang user name
v1UserGroup.PUT("/changusername", v1.Chang_User_Name)
v1UserGroup.PUT("/username", v1.PutUserName)
//chang pwd
v1UserGroup.PUT("/changuserpwd", v1.Chang_User_Pwd)
v1UserGroup.PUT("/password", v1.PutUserPwd)
//edit user info
v1UserGroup.POST("/changuserinfo", v1.Chang_User_Info)
//get user info
v1UserGroup.GET("/info", v1.UserInfo)
v1UserGroup.POST("/info", v1.PostUserChangeInfo)
v1UserGroup.PUT("/nick", v1.PutUserChangeNick)
v1UserGroup.PUT("/desc", v1.PutUserChangeDesc)
v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
v1UserGroup.GET("/shareid", v1.GetUserShareID)
}
v1ZiMaGroup := v1Group.Group("/zima")
@@ -68,56 +78,10 @@ func InitRouter() *gin.Engine {
//获取网络信息
v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
//获取网络信息
v1ZiMaGroup.GET("/getinfo", v1.Info)
//获取系统信息
v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
}
v1ZeroTierGroup := v1Group.Group("/zerotier")
v1ZeroTierGroup.Use()
{
//获取zerotier token
v1ZeroTierGroup.POST("/login", v1.ZeroTierGetToken)
//注册zerotier
v1ZeroTierGroup.POST("/register", v1.ZeroTierRegister)
//是否需要登录
v1ZeroTierGroup.GET("/islogin", v1.ZeroTierIsNeedLogin)
//获取网络列表
v1ZeroTierGroup.GET("/list", v1.ZeroTierGetNetworkList)
//加入网络
v1ZeroTierGroup.POST("/join/:id", v1.ZeroTierJoinNetwork)
//离开网络
v1ZeroTierGroup.POST("/leave/:id", v1.ZeroTierLeaveNetwork)
//详情
v1ZeroTierGroup.GET("/info/:id", v1.ZeroTierGetNetworkGetInfo)
////网络状态
//v1ZeroTierGroup.GET("/status", v1.ZeroTierGetNetworkGetStatus)
//修改网络类型
//v1ZeroTierGroup.PUT("/type/:id", v1.ZeroTierEditType)
//修改网络类型
//v1ZeroTierGroup.PUT("/name/:id", v1.ZeroTierEditName)
//修改v6 assign
//v1ZeroTierGroup.PUT("/v6assign/:id", v1.ZeroTierEditV6Assign)
//修改 broadcast
//v1ZeroTierGroup.PUT("/broadcast/:id", v1.ZeroTierEditBroadcast)
//create new network
v1ZeroTierGroup.POST("/create", v1.ZeroTierCreateNetwork)
//获取用户列表
v1ZeroTierGroup.GET("/member/:id", v1.ZeroTierMemberList)
//修改用户信息
//v1ZeroTierGroup.PUT("/members/:id/auth/:mId", v1.ZeroTierMemberAuth)
//修改网络用户name
//v1ZeroTierGroup.PUT("/members/:id/name/:mId", v1.ZeroTierMemberName)
v1ZeroTierGroup.DELETE("/members/:id/del/:mId", v1.ZeroTierMemberDelete)
v1ZeroTierGroup.DELETE("/network/:id/del", v1.ZeroTierDeleteNetwork)
//修改网络用户bridge功能
//v1ZeroTierGroup.PUT("/members/:id/bridge/:mId", v1.ZeroTierMemberBridge)
v1ZeroTierGroup.PUT("/edit/:id", v1.ZeroTierEdit)
v1ZeroTierGroup.GET("/joined/list", v1.ZeroTierJoinedList)
v1ZeroTierGroup.PUT("/member/:id/edit/:mId", v1.ZeroTierMemberEdit)
}
v1DDNSGroup := v1Group.Group("/ddns")
v1DDNSGroup.Use()
{
@@ -139,6 +103,8 @@ func InitRouter() *gin.Engine {
{
//获取我的已安装的列表
v1AppGroup.GET("/mylist", v1.MyAppList)
//
v1AppGroup.GET("/usage", v1.AppUsageList)
//app详情
v1AppGroup.GET("/appinfo/:id", v1.AppInfo)
//获取未安装的列表
@@ -174,7 +140,7 @@ func InitRouter() *gin.Engine {
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
//v1AppGroup.POST("/custom/install", v1.CustomInstallApp)
v1AppGroup.POST("/share", v1.ShareAppFile)
}
v1SysGroup := v1Group.Group("/sys")
@@ -186,9 +152,17 @@ func InitRouter() *gin.Engine {
v1SysGroup.GET("/sys", v1.Sys)
v1SysGroup.GET("/wsssh", v1.WsSsh)
v1SysGroup.GET("/config", v1.GetSystemConfig)
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
v1SysGroup.POST("/config", v1.PostSetSystemConfig)
v1SysGroup.GET("/widget/config", v1.GetWidgetConfig)
v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
v1SysGroup.GET("/info", v1.Info)
v1SysGroup.PUT("/usb/off", v1.PutSystemOffUSBAutoMount)
v1SysGroup.GET("/usb/on", v1.PutSystemOnUSBAutoMount)
v1SysGroup.GET("/usb", v1.GetSystemUSBAutoMount)
}
v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use()
@@ -197,34 +171,48 @@ func InitRouter() *gin.Engine {
v1FileGroup.PUT("/rename", v1.RenamePath)
v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/upload", v1.GetFileUpload)
v1FileGroup.GET("/dirpath", v1.DirPath)
//创建目录
//create folder
v1FileGroup.POST("/mkdir", v1.MkdirAll)
v1FileGroup.POST("/create", v1.PostCreateFile)
v1FileGroup.GET("/download", v1.GetDownloadFile)
v1FileGroup.GET("/new/download", v1.GetFileDownloadNew)
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
v1FileGroup.DELETE("/delete", v1.DeleteFile)
v1FileGroup.PUT("/update", v1.PutFileContent)
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
}
v1DiskGroup := v1Group.Group("/disk")
v1DiskGroup.Use()
{
//获取磁盘列表
v1DiskGroup.GET("/list", v1.GetPlugInDisk)
v1DiskGroup.GET("/check", v1.GetDiskCheck)
v1DiskGroup.GET("/list", v1.GetDiskList)
//获取磁盘详情
v1DiskGroup.GET("/info", v1.GetDiskInfo)
//格式化磁盘
//format storage
v1DiskGroup.POST("/format", v1.FormatDisk)
//添加分区
v1DiskGroup.POST("/addpart", 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)
}
v1ShareGroup := v1Group.Group("/share")
@@ -264,6 +252,36 @@ func InitRouter() *gin.Engine {
{
v1SearchGroup.GET("/search", v1.GetSearchList)
}
v1PersonGroup := v1Group.Group("/person")
v1PersonGroup.Use()
{
v1PersonGroup.GET("/test", v1.PersonTest)
v1PersonGroup.GET("/users", v1.GetPersonFriend)
v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
v1PersonGroup.GET("/directory", v1.GetPersonDirectory)
v1PersonGroup.GET("/file", v1.GetPersonFile)
v1PersonGroup.GET("/refile/:uuid", v1.GetPersonReFile)
v1PersonGroup.PUT("/remarks/:shareid", v1.PutPersonRemarks)
v1PersonGroup.GET("/list", v1.GetPersonDownloadList)
v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
v1PersonGroup.POST("/share", v1.PostPersonShare)
v1PersonGroup.GET("/share", v1.GetPersonShare)
v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
v1PersonGroup.GET("/public", v1.GetPersonPublic)
}
v1AnalyseGroup := v1Group.Group("/analyse")
v1AnalyseGroup.Use()
{
v1AnalyseGroup.POST("/app", v1.PostAppAnalyse)
}
v1Group.GET("/sync/config", v1.GetSyncConfig)
v1Group.Any("/syncthing/*url", v1.SyncToSyncthing)
}
return r
}

38
route/v1/analyse.go Normal file
View File

@@ -0,0 +1,38 @@
package v1
import (
"net/http"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
)
// @Summary post app analyse
// @Produce application/json
// @Accept multipart/form-data
// @Tags analyse
// @Param name formData string true "app name"
// @Param type formData string true "action" Enums(open,delete)
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /analyse/app [post]
func PostAppAnalyse(c *gin.Context) {
if config.SystemConfigInfo.Analyse == "False" {
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
return
}
name := c.PostForm("name")
t := c.PostForm("type")
language := c.GetHeader("Language")
if len(name) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
service.MyService.Casa().PushAppAnalyse(config.ServerInfo.Token, t, name, language)
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

@@ -1,15 +1,17 @@
package v1
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/sort"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
// @Summary 获取远程列表
@@ -29,20 +31,34 @@ func AppList(c *gin.Context) {
//service.MyService.Docker().DockerContainerCommit("test2")
index := c.DefaultQuery("index", "1")
size := c.DefaultQuery("size", "10")
size := c.DefaultQuery("size", "10000")
t := c.DefaultQuery("type", "rank")
categoryId := c.DefaultQuery("category_id", "0")
key := c.DefaultQuery("key", "")
list, count := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
for i := 0; i < len(list); i++ {
ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
if ct != nil {
list[i].State = ct.State
}
}
data := make(map[string]interface{}, 2)
data["count"] = count
data["items"] = list
language := c.GetHeader("Language")
recommend, list, community := service.MyService.Casa().GetServerList(index, size, t, categoryId, key, language)
// for i := 0; i < len(recommend); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
// if ct != nil {
// recommend[i].State = ct.State
// }
// }
// for i := 0; i < len(list); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
// if ct != nil {
// list[i].State = ct.State
// }
// }
// for i := 0; i < len(community); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
// if ct != nil {
// community[i].State = ct.State
// }
// }
data := make(map[string]interface{}, 3)
data["recommend"] = recommend
data["list"] = list
data["community"] = community
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
@@ -99,6 +115,18 @@ func MyAppList(c *gin.Context) {
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary my app hardware usage list
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/usage [get]
func AppUsageList(c *gin.Context) {
list := service.MyService.App().GetHardwareUsage()
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary 应用详情
// @Produce application/json
// @Accept application/json
@@ -110,51 +138,71 @@ func MyAppList(c *gin.Context) {
func AppInfo(c *gin.Context) {
id := c.Param("id")
info := service.MyService.App().GetServerAppInfo(id)
language := c.GetHeader("Language")
info := service.MyService.Casa().GetServerAppInfo(id, "", language)
if info.NetworkModel != "host" {
port, _ := port2.GetAvailablePort("tcp")
info.PortMap = uint(port)
for i := 0; i < len(info.Configures.TcpPorts); i++ {
info.Configures.TcpPorts[i].CommendPort, _ = port2.GetAvailablePort("tcp")
}
for i := 0; i < len(info.Configures.UdpPorts); i++ {
info.Configures.UdpPorts[i].CommendPort, _ = port2.GetAvailablePort("udp")
for i := 0; i < len(info.Ports); i++ {
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {
info.Ports[i].CommendPort = strconv.Itoa(p)
} else {
if info.Ports[i].Protocol == "tcp" {
if p, err := port2.GetAvailablePort("tcp"); err == nil {
info.Ports[i].CommendPort = strconv.Itoa(p)
}
} else if info.Ports[i].Protocol == "upd" {
if p, err := port2.GetAvailablePort("udp"); err == nil {
info.Ports[i].CommendPort = strconv.Itoa(p)
}
}
}
if info.Ports[i].Type == 0 {
info.PortMap = info.Ports[i].CommendPort
}
}
} else {
info.PortMap = info.TcpPort
}
for i := 0; i < len(info.Configures.Devices); i++ {
if !file.CheckNotExist(info.Configures.Devices[i].ContainerPath) {
info.Configures.Devices[i].Path = info.Configures.Devices[i].ContainerPath
for i := 0; i < len(info.Ports); i++ {
if info.Ports[i].Type == 0 {
info.PortMap = info.Ports[i].ContainerPort
break
}
}
}
portOrder := func(c1, c2 *model.Ports) bool {
return c1.Type < c2.Type
for i := 0; i < len(info.Devices); i++ {
if !file.CheckNotExist(info.Devices[i].ContainerPath) {
info.Devices[i].Path = info.Devices[i].ContainerPath
}
}
// if len(info.Tip) > 0 {
// info.Tip = env_helper.ReplaceStringDefaultENV(info.Tip)
// }
envOrder := func(c1, c2 *model.Envs) bool {
return c1.Type < c2.Type
}
// portOrder := func(c1, c2 *model.Ports) bool {
// return c1.Type < c2.Type
// }
volOrder := func(c1, c2 *model.Volume) bool {
return c1.Type < c2.Type
}
// envOrder := func(c1, c2 *model.Envs) bool {
// return c1.Type < c2.Type
// }
devOrder := func(c1, c2 *model.Devices) bool {
return c1.Type < c2.Type
}
// volOrder := func(c1, c2 *model.Volume) bool {
// return c1.Type < c2.Type
// }
// devOrder := func(c1, c2 *model.Devices) bool {
// return c1.Type < c2.Type
// }
//sort
if info.NetworkModel != "host" {
sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
}
// if info.NetworkModel != "host" {
// sort.PortsSort(portOrder).Sort(info.Configures.TcpPorts)
// sort.PortsSort(portOrder).Sort(info.Configures.UdpPorts)
// }
sort.EnvSort(envOrder).Sort(info.Configures.Envs)
sort.VolSort(volOrder).Sort(info.Configures.Volumes)
sort.DevSort(devOrder).Sort(info.Configures.Devices)
// sort.EnvSort(envOrder).Sort(info.Envs)
// sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap))
// sort.DevSort(devOrder).Sort(info.Devices)
info.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20
@@ -169,14 +217,38 @@ func AppInfo(c *gin.Context) {
// @Success 200 {string} string "ok"
// @Router /app/category [get]
func CategoryList(c *gin.Context) {
list := service.MyService.OAPI().GetServerCategoryList()
list := service.MyService.Casa().GetServerCategoryList()
var count uint = 0
for _, category := range list {
count += category.Count
}
rear := append([]model.ServerCategoryList{}, list[0:]...)
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All"})
list = append(list[:0], model.ServerCategoryList{Count: count, Name: "All", Font: "apps"})
list = append(list, rear...)
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary 分享该应用配置
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/share [post]
func ShareAppFile(c *gin.Context) {
str, _ := ioutil.ReadAll(c.Request.Body)
content := service.MyService.Casa().ShareAppFile(str)
c.JSON(http.StatusOK, json.RawMessage(content))
}
// @Summary Resource Usage
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/shares [post]
func AppListResourceUsage() {
}

View File

@@ -64,7 +64,7 @@ func DDNSAddConfig(c *gin.Context) {
})
return
}
var m model2.DDNSUpdataDBModel
var m model2.DDNSUpdateDBModel
c.Bind(&m)
if err := service.MyService.DDNS().SaveConfig(m); err != nil {
c.JSON(http.StatusOK,

View File

@@ -1,65 +1,163 @@
package v1
import (
"fmt"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/v3/disk"
"net/http"
"strconv"
)
// @Summary 获取磁盘列表
var diskMap = make(map[string]string)
// @Summary disk list
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/list [get]
func GetPlugInDisk(c *gin.Context) {
func GetDiskList(c *gin.Context) {
list := service.MyService.Disk().LSBLK(false)
dbList := service.MyService.Disk().GetSerialAll()
part := make(map[string]int64, len(dbList))
for _, v := range dbList {
part[v.MountPoint] = v.CreatedAt
}
findSystem := 0
//ls := service.MyService.Disk().GetPlugInDisk()
//fmt.Println(ls)
//dd, _ := disk.Partitions(true)
//fmt.Println(dd)
//
//dir, err := ioutil.ReadDir("/sys/block")
//if err != nil {
// panic(err)
//}
//
//files := make([]string, 0)
//
////fmt.Println(regexp.MatchString("sd[a-z]*[0-9]", "sda"))
//
//for _, f := range dir {
// if match, _ := regexp.MatchString("sd[a-z]", f.Name()); match {
// files = append(files, f.Name())
// }
//}
//fmt.Println(files)
//filess := make([]string, 0)
//for _, file := range files {
// dirs, _ := ioutil.ReadDir("/sys/block/" + file)
//
// for _, f := range dirs {
// if match, _ := regexp.MatchString("sd[a-z]*[0-9]", f.Name()); match {
// filess = append(filess, f.Name())
// }
// }
//}
//fmt.Println(filess)
//
//for _, s := range filess {
// fmt.Println(disk.Usage("/dev/" + s))
//}
disks := []model.Drive{}
storage := []model.Storage{}
avail := []model.Drive{}
for i := 0; i < len(list); i++ {
disk := model.Drive{}
if list[i].Rota {
disk.DiskType = "HDD"
} else {
disk.DiskType = "SSD"
}
disk.Serial = list[i].Serial
disk.Name = list[i].Name
disk.Size = list[i].Size
disk.Path = list[i].Path
disk.Model = list[i].Model
lst := service.MyService.Disk().LSBLK()
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: lst})
if len(list[i].Children) > 0 && findSystem == 0 {
for j := 0; j < len(list[i].Children); j++ {
if len(list[i].Children[j].Children) > 0 {
for _, v := range list[i].Children[j].Children {
if v.MountPoint == "/" {
stor := model.Storage{}
stor.Name = "System"
stor.MountPoint = v.MountPoint
stor.Size = v.FSSize
stor.Avail = v.FSAvail
stor.Path = v.Path
stor.Type = v.FsType
stor.DriveName = "System"
disk.Model = "System"
if strings.Contains(v.SubSystems, "mmc") {
disk.DiskType = "MMC"
} else if strings.Contains(v.SubSystems, "usb") {
disk.DiskType = "USB"
}
disk.Health = "true"
disks = append(disks, disk)
storage = append(storage, stor)
findSystem = 1
break
}
}
} else {
if list[i].Children[j].MountPoint == "/" {
stor := model.Storage{}
stor.Name = "System"
stor.MountPoint = list[i].Children[j].MountPoint
stor.Size = list[i].Children[j].FSSize
stor.Avail = list[i].Children[j].FSAvail
stor.Path = list[i].Children[j].Path
stor.Type = list[i].Children[j].FsType
stor.DriveName = "System"
disk.Model = "System"
if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
disk.DiskType = "MMC"
} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
disk.DiskType = "USB"
}
disk.Health = "true"
disks = append(disks, disk)
storage = append(storage, stor)
findSystem = 1
break
}
}
}
}
if findSystem == 1 {
findSystem += 1
continue
}
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
if reflect.DeepEqual(temp, model.SmartctlA{}) {
temp.SmartStatus.Passed = true
}
if len(list[i].Children) == 1 && len(list[i].Children[0].MountPoint) > 0 {
stor := model.Storage{}
stor.MountPoint = list[i].Children[0].MountPoint
stor.Size = list[i].Children[0].FSSize
stor.Avail = list[i].Children[0].FSAvail
stor.Path = list[i].Children[0].Path
stor.Type = list[i].Children[0].FsType
stor.DriveName = list[i].Name
pathArr := strings.Split(list[i].Children[0].MountPoint, "/")
if len(pathArr) == 3 {
stor.Name = pathArr[2]
}
if t, ok := part[list[i].Children[0].MountPoint]; ok {
stor.CreatedAt = t
}
storage = append(storage, stor)
} else {
//todo 长度有问题
if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" {
disk.NeedFormat = false
avail = append(avail, disk)
} else {
disk.NeedFormat = true
avail = append(avail, disk)
}
}
disk.Temperature = temp.Temperature.Current
disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
disks = append(disks, disk)
}
}
data := make(map[string]interface{}, 3)
data["drive"] = disks
data["storage"] = storage
data["avail"] = avail
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
}
// @Summary 获取磁盘列表
// @Summary get disk list
// @Produce application/json
// @Accept application/json
// @Tags disk
@@ -68,7 +166,7 @@ func GetPlugInDisk(c *gin.Context) {
// @Router /disk/lists [get]
func GetPlugInDisks(c *gin.Context) {
list := service.MyService.Disk().LSBLK()
list := service.MyService.Disk().LSBLK(true)
var result []*disk.UsageStat
for _, item := range list {
result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
@@ -76,12 +174,12 @@ func GetPlugInDisks(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
}
// @Summary 磁盘详情
// @Summary disk detail
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Param path query string true "要获取的磁盘详情 例如/dev/sda"
// @Param path query string true "for example /dev/sda"
// @Success 200 {string} string "ok"
// @Router /disk/info [get]
func GetDiskInfo(c *gin.Context) {
@@ -93,31 +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 磁盘详情
// @Summary format storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "磁盘路径 例如/dev/sda1"
// @Param path formData string true "e.g. /dev/sda1"
// @Param pwd formData string true "user password"
// @Param volume formData string true "mount point"
// @Success 200 {string} string "ok"
// @Router /disk/format [post]
func FormatDisk(c *gin.Context) {
path := c.PostForm("path")
t := "ext4"
pwd := c.PostForm("pwd")
volume := c.PostForm("volume")
t := c.PostForm("type")
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
return
}
if len(path) == 0 || len(t) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
//删除挂载点
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)
//格式化磁盘
service.MyService.Disk().FormatDisk(path, t)
//重新挂载
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)})
}
@@ -154,25 +267,231 @@ func RemovePartition(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary 添加分区
// @Summary add storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "磁盘路径 例如/dev/sda"
// @Param size formData string true "需要分区容量大小(MB)"
// @Param num formData string true "磁盘符号"
// @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")
size, _ := strconv.Atoi(c.DefaultPostForm("size", "0"))
num := c.DefaultPostForm("num", "9")
if len(path) == 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
}
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)
}
//size*1024*1024/512
service.MyService.Disk().AddPartition(path, num, uint64(size*1024*2))
formatBool := true
for formatBool {
currentDisk = service.MyService.Disk().GetDiskInfo(path)
fmt.Println(currentDisk.Children)
if len(currentDisk.Children) > 0 {
formatBool = false
break
}
time.Sleep(time.Second)
}
currentDisk = service.MyService.Disk().GetDiskInfo(path)
if len(currentDisk.Children) != 1 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
return
}
mountPath := "/DATA/" + name
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = currentDisk.Children[0].Path
m.UUID = currentDisk.Children[0].UUID
m.State = 0
m.CreatedAt = time.Now().Unix()
service.MyService.Disk().SaveMountPoint(m)
//mount dir
service.MyService.Disk().MountDisk(currentDisk.Children[0].Path, mountPath)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, path)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary add mount point
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "for example: /dev/sda1"
// @Param serial formData string true "disk id"
// @Success 200 {string} string "ok"
// @Router /disk/mount [post]
func PostMountDisk(c *gin.Context) {
// for example: path=/dev/sda1
path := c.PostForm("path")
serial := c.PostForm("serial")
mountPath := "/DATA/volume"
var list = service.MyService.Disk().GetSerialAll()
var pathMapList = make(map[string]string, len(list))
for _, v := range list {
pathMapList[v.MountPoint] = "1"
}
for i := 0; i < len(list)+1; i++ {
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
mountPath = mountPath + strconv.Itoa(i)
break
}
}
//mount dir
service.MyService.Disk().MountDisk(path, mountPath)
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path
m.UUID = serial
m.State = 0
//service.MyService.Disk().SaveMountPoint(m)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary remove mount point
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "e.g. /dev/sda1"
// @Param mount_point formData string true "e.g. /mnt/volume1"
// @Param pwd formData string true "user password"
// @Success 200 {string} string "ok"
// @Router /disk/umount [post]
func PostDiskUmount(c *gin.Context) {
path := c.PostForm("path")
mountPoint := c.PostForm("volume")
pwd := c.PostForm("pwd")
if len(path) == 0 || len(mountPoint) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
if pwd != config.UserInfo.PWD {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
return
}
if _, ok := diskMap[path]; ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
return
}
service.MyService.Disk().UmountPointAndRemoveDir(path)
//delete data
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
service.MyService.Disk().RemoveLSBLKCache()
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary confirm delete disk
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Param id path string true "id"
// @Success 200 {string} string "ok"
// @Router /disk/remove/{id} [delete]
func DeleteDisk(c *gin.Context) {
id := c.Param("id")
service.MyService.Disk().DeleteMount(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary check mount point
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/init [get]
func GetDiskCheck(c *gin.Context) {
dbList := service.MyService.Disk().GetSerialAll()
list := service.MyService.Disk().LSBLK(true)
mapList := make(map[string]string)
for _, v := range list {
mapList[v.Serial] = "1"
}
for _, v := range dbList {
if _, ok := mapList[v.UUID]; !ok {
//disk undefind
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
return
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary check mount point
// @Produce application/json
// @Accept application/json
// @Tags disk
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /disk/usb [get]
func GetUSBList(c *gin.Context) {
list := service.MyService.Disk().LSBLK(false)
data := []model.DriveUSB{}
for _, v := range list {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
data = append(data, temp)
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
}

View File

@@ -2,6 +2,7 @@ package v1
import (
"bytes"
"encoding/json"
json2 "encoding/json"
"net/http"
"reflect"
@@ -10,6 +11,7 @@ import (
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
@@ -25,6 +27,8 @@ import (
"github.com/gorilla/websocket"
"github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid"
"github.com/tidwall/gjson"
"golang.org/x/crypto/ssh"
)
var upgrader = websocket.Upgrader{
@@ -65,19 +69,46 @@ func DockerTerminal(c *gin.Context) {
//打开本机的ssh接口
func WsSsh(c *gin.Context) {
wsConn, _ := upgrader.Upgrade(c.Writer, c.Request, nil)
defer wsConn.Close()
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
client, _ := docker.NewSshClient()
defer client.Close()
ssConn, _ := docker.NewSshConn(cols, rows, client)
defer ssConn.Close()
quitChan := make(chan bool, 3)
var logBuff = new(bytes.Buffer)
quitChan := make(chan bool, 3)
user := ""
password := ""
var login int = 1
cols, _ := strconv.Atoi(c.DefaultQuery("cols", "200"))
rows, _ := strconv.Atoi(c.DefaultQuery("rows", "32"))
var client *ssh.Client
for login != 0 {
var err error
wsConn.WriteMessage(websocket.TextMessage, []byte("login:"))
user = docker.ReceiveWsMsgUser(wsConn, logBuff)
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
wsConn.WriteMessage(websocket.TextMessage, []byte("password:"))
password = docker.ReceiveWsMsgPassword(wsConn, logBuff)
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
client, err = docker.NewSshClient(user, password)
if err != nil && client == nil {
wsConn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
wsConn.WriteMessage(websocket.TextMessage, []byte("\r\n\x1b[0m"))
} else {
login = 0
}
}
if client != nil {
defer client.Close()
}
ssConn, _ := docker.NewSshConn(cols, rows, client)
defer ssConn.Close()
go ssConn.ReceiveWsMsg(wsConn, logBuff, quitChan)
go ssConn.SendComboOutput(wsConn, quitChan)
go ssConn.SessionWait(quitChan)
<-quitChan
}
@@ -115,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)
@@ -144,7 +176,7 @@ func InstallApp(c *gin.Context) {
dockerImageVersion = "latest"
}
if m.Origin != "custom" {
appInfo = service.MyService.App().GetServerAppInfo(appId)
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "", language)
} else {
@@ -188,14 +220,24 @@ func InstallApp(c *gin.Context) {
}
}
if m.Origin == "custom" {
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
return
}
for _, device := range m.Devices {
if file.CheckNotExist(device.Path) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
return
}
} else {
dev := []model.PathMap{}
for _, device := range dev {
if !file.CheckNotExist(device.Path) {
dev = append(dev, device)
}
}
m.Devices = dev
}
//restart := c.PostForm("restart") //always 总是重启, unless-stopped 除非用户手动停止容器,否则总是重新启动, on-failure:仅当容器退出代码非零时重新启动
//if len(restart) > 0 {
//
@@ -210,13 +252,14 @@ func InstallApp(c *gin.Context) {
var relyMap = make(map[string]string)
go func() {
installLog := model2.AppNotify{}
installLog.CustomId = id
installLog.State = 0
installLog.CustomId = id
installLog.Message = "installing rely"
installLog.Speed = 10
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 {
@@ -239,11 +282,11 @@ func InstallApp(c *gin.Context) {
rely.ContainerId = mysqlContainerId
rely.CustomId = mid
rely.ContainerCustomId = id
var msqlConfig model2.MysqlConfigs
var mysqlConfig model2.MysqlConfigs
//结构体转换
copier.Copy(&msqlConfig, &mc)
rely.Config = msqlConfig
copier.Copy(&mysqlConfig, &mc)
rely.Config = mysqlConfig
service.MyService.Rely().Create(rely)
relyMap["mysql"] = mid
@@ -251,16 +294,13 @@ func InstallApp(c *gin.Context) {
} else {
docker_base.MysqlDelete(mysqlContainerId)
installLog.State = 0
installLog.Speed = 30
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
}
}
}
}
installLog.Speed = 50
installLog.Message = "pulling"
service.MyService.Notify().UpdateLog(installLog)
@@ -268,7 +308,6 @@ func InstallApp(c *gin.Context) {
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
if err != nil {
installLog.State = 0
installLog.Speed = 70
installLog.Message = err.Error()
installLog.Type = types.NOTIFY_TYPE_ERROR
service.MyService.Notify().UpdateLog(installLog)
@@ -295,35 +334,34 @@ func InstallApp(c *gin.Context) {
// return
// }
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
installLog.ContainerId = containerId
installLog.Name = appInfo.Title
installLog.Icon = appInfo.Icon
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
installLog.State = 0
installLog.Speed = 80
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
installLog.Speed = 80
installLog.Message = "starting"
service.MyService.Notify().UpdateLog(installLog)
}
// echo -e "hellow\nworld" >>
//step启动容器
err = service.MyService.Docker().DockerContainerStart(id)
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
installLog.State = 0
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Speed = 90
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
installLog.Speed = 90
if m.Origin != CUSTOM {
installLog.Message = "setting upnp"
} else {
@@ -368,13 +406,11 @@ func InstallApp(c *gin.Context) {
if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
installLog.State = 0
installLog.Speed = 95
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
installLog.Speed = 95
installLog.Message = "checking"
service.MyService.Notify().UpdateLog(installLog)
}
@@ -386,14 +422,12 @@ func InstallApp(c *gin.Context) {
if err != nil && container.ContainerJSONBase.State.Running {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
installLog.State = 0
installLog.Speed = 100
installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog)
return
} else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
installLog.Speed = 100
installLog.Message = "installed"
service.MyService.Notify().UpdateLog(installLog)
}
@@ -401,10 +435,18 @@ func InstallApp(c *gin.Context) {
rely := model.MapStrings{}
copier.Copy(&rely, &relyMap)
// if m.Origin != "custom" {
// for i := 0; i < len(m.Volumes); i++ {
// m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
// }
// }
portsStr, _ := json2.Marshal(m.Ports)
envsStr, _ := json2.Marshal(m.Envs)
volumesStr, _ := json2.Marshal(m.Volumes)
devicesStr, _ := json2.Marshal(m.Devices)
cmd, _ := json2.Marshal(m.Cmd)
capAdd, _ := json.Marshal(m.CapAdd)
//step: 保存数据到数据库
md := model2.AppListDBModel{
CustomId: id,
@@ -432,14 +474,19 @@ func InstallApp(c *gin.Context) {
Memory: m.Memory,
Devices: string(devicesStr),
//Rely: rely,
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
Origin: m.Origin,
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
Cmd: string(cmd),
CapAdd: string(capAdd),
HostName: m.HostName,
Privileged: m.Privileged,
}
//if appInfo.NetworkModel == "host" {
// m.PortMap = m.Port
//}
service.MyService.App().SaveContainer(md)
config.CasaOSGlobalVariables.AppChange = true
}()
@@ -654,7 +701,7 @@ func UnInstallApp(c *gin.Context) {
}
//step删除容器
err = service.MyService.Docker().DockerContainerRemove(appId)
err = service.MyService.Docker().DockerContainerRemove(appId, false)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
return
@@ -669,10 +716,15 @@ func UnInstallApp(c *gin.Context) {
if info.Origin != "custom" {
//step: 删除文件夹
service.MyService.App().DelAppConfigDir(appId)
vol := gjson.Get(info.Volumes, "#.host")
for _, v := range vol.Array() {
if strings.Contains(v.String(), appId) {
service.MyService.App().DelAppConfigDir(v.String())
}
}
//step: 删除install log
service.MyService.Notify().DelLog(appId)
//service.MyService.Notify().DelLog(appId)
// for k, v := range info.Rely {
//
@@ -711,6 +763,13 @@ func UnInstallApp(c *gin.Context) {
// }
//}
}
config.CasaOSGlobalVariables.AppChange = true
unInstallLog := model2.AppNotify{}
unInstallLog.State = 0
unInstallLog.CustomId = appId
unInstallLog.Message = "uninstalled"
unInstallLog.Id = uuid.NewV4().String()
service.MyService.Notify().UpdateLog(unInstallLog)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
@@ -774,7 +833,6 @@ func ContainerLog(c *gin.Context) {
func GetInstallSpeed(c *gin.Context) {
id := c.Param("id")
b := service.MyService.Notify().GetLog(id)
b.Id = b.CustomId
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
}
@@ -884,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
@@ -901,7 +961,7 @@ func UpdateSetting(c *gin.Context) {
return
}
err = service.MyService.Docker().DockerContainerRemove(id)
err = service.MyService.Docker().DockerContainerRemove(id, true)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
@@ -1002,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)
@@ -1097,25 +1161,32 @@ 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 需要自定义错误
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
return
}
var port model.PortArrey
var port model.PortArray
json2.Unmarshal([]byte(appInfo.Ports), &port)
var envs model.EnvArrey
var envs model.EnvArray
json2.Unmarshal([]byte(appInfo.Envs), &envs)
var vol model.PathArrey
var vol model.PathArray
json2.Unmarshal([]byte(appInfo.Volumes), &vol)
var dir model.PathArrey
for i := 0; i < len(vol); i++ {
vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
}
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{}
@@ -1137,6 +1208,11 @@ func ContainerUpdateInfo(c *gin.Context) {
m.EnableUPNP = appInfo.EnableUPNP
m.Position = appInfo.Position
m.CapAdd = capAdd
m.Cmd = cmd
m.HostName = appInfo.HostName
m.Privileged = appInfo.Privileged
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
}

View File

@@ -7,14 +7,18 @@ import (
"io"
"io/ioutil"
"net/http"
url2 "net/url"
"os"
"path"
"strconv"
"strings"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin"
"github.com/spf13/afero"
)
func downloadReadFile(c *gin.Context) {
@@ -125,12 +129,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) {
@@ -155,15 +159,57 @@ func GetDownloadFile(c *gin.Context) {
//获取文件的名称
fileName := path.Base(filePath)
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename="+fileName)
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.Header("Content-Transfer-Encoding", "binary")
c.Header("Cache-Control", "no-cache")
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename="+fileName)
c.Header("Content-Transfer-Encoding", "binary")
c.File(filePath)
return
}
// @Summary download
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "path of file"
// @Success 200 {string} string "ok"
// @Router /file/new/download [get]
func GetFileDownloadNew(c *gin.Context) {
filePath := c.Query("path")
if len(filePath) == 0 {
c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.INVALID_PARAMS,
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
})
return
}
if !file.Exists(filePath) {
c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.FILE_DOES_NOT_EXIST,
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
})
return
}
//打开文件
fileStat, _ := os.Stat(filePath)
var AppFs = afero.NewOsFs()
fileT, _ := AppFs.Open(filePath)
//fileTmp, _ := os.Open(filePath)
//defer fileTmp.Close()
//获取文件的名称
//fileName := path.Base(filePath)
//c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
//在线
//c.Header("Content-Disposition", "inline")
// extraHeaders := map[string]string{
// "Content-Disposition": `attachment; filename="` + url2.PathEscape(fileName) + `"`,
// }
//c.Header("Cache-Control", "private")
//c.Header("Content-Type", "application/octet-stream")
http.ServeContent(c.Writer, c.Request, fileStat.Name(), fileStat.ModTime(), fileT)
}
// @Summary 获取目录列表
@@ -175,18 +221,58 @@ 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)
if path == "/DATA/AppData" {
list := service.MyService.App().GetAllDBApps()
apps := make(map[string]string, len(list))
for _, v := range list {
apps[v.CustomId] = v.Label
}
for i := 0; i < len(info); i++ {
if v, ok := apps[info[i].Name]; ok {
info[i].Label = v
info[i].Type = "application"
}
}
} else if path == "/DATA" {
disk := make(map[string]string)
lsblk := service.MyService.Disk().LSBLK(true)
for _, v := range lsblk {
if len(v.Children) > 0 {
t := v.Tran
for _, c := range v.Children {
if len(c.Children) > 0 {
for _, gc := range c.Children {
if len(gc.MountPoint) > 0 {
disk[gc.MountPoint] = t
}
}
}
if len(c.MountPoint) > 0 {
disk[c.MountPoint] = t
}
}
}
}
for i := 0; i < len(info); i++ {
if v, ok := disk[info[i].Path]; ok {
info[i].Type = v
}
}
}
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) {
@@ -196,16 +282,16 @@ func RenamePath(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
service.MyService.ZiMa().RenameFile(op, np)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
success, err := service.MyService.ZiMa().RenameFile(op, np)
c.JSON(http.StatusOK, model.Result{Success: success, Message: oasis_err2.GetMsg(success), Data: err})
}
// @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) {
@@ -219,7 +305,7 @@ func MkdirAll(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
}
// @Summary 创建文件
// @Summary create file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
@@ -238,21 +324,201 @@ 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]
func PostFileUpload(c *gin.Context) {
file, _, _ := c.Request.FormFile("file")
//file.Read()
// @Router /file/upload [get]
func GetFileUpload(c *gin.Context) {
relative := c.Query("relativePath")
fileName := c.Query("filename")
chunkNumber := c.Query("chunkNumber")
totalChunks, _ := strconv.Atoi(c.DefaultQuery("totalChunks", "0"))
path := c.Query("path")
//上传文件
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
defer out.Close()
io.Copy(out, file)
dirPath := ""
hash := file.GetHashByContent([]byte(fileName))
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName)
tempDir += dirPath
file.MkDir(path + "/" + dirPath)
}
tempDir += chunkNumber
if !file.CheckNotExist(tempDir) {
c.JSON(200, model.Result{Success: 200, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
c.JSON(204, model.Result{Success: 204, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary upload file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param path formData string false "file path"
// @Param file formData file true "file"
// @Success 200 {string} string "ok"
// @Router /file/upload [post]
func PostFileUpload(c *gin.Context) {
f, _, _ := c.Request.FormFile("file")
relative := c.PostForm("relativePath")
fileName := c.PostForm("filename")
totalChunks, _ := strconv.Atoi(c.DefaultPostForm("totalChunks", "0"))
chunkNumber := c.PostForm("chunkNumber")
dirPath := ""
path := c.PostForm("path")
hash := file.GetHashByContent([]byte(fileName))
if len(path) == 0 {
c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName)
tempDir += dirPath
file.MkDir(path + "/" + dirPath)
}
path += "/" + relative
if !file.CheckNotExist(tempDir + chunkNumber) {
file.RMDir(tempDir + chunkNumber)
}
if totalChunks > 1 {
file.IsNotExistMkDir(tempDir)
out, _ := os.OpenFile(tempDir+chunkNumber, os.O_WRONLY|os.O_CREATE, 0644)
defer out.Close()
_, err := io.Copy(out, f)
if err != nil {
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
} else {
out, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
defer out.Close()
_, err := io.Copy(out, f)
if err != nil {
c.JSON(oasis_err2.ERROR, 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)})
return
}
fileNum, err := ioutil.ReadDir(tempDir)
if err != nil {
c.JSON(oasis_err2.ERROR, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
if totalChunks == len(fileNum) {
file.SpliceFiles(tempDir, path, totalChunks, 1)
file.RMDir(tempDir)
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary copy or move file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param from formData string true "from path"
// @Param to formData string true "to path"
// @Param type formData string true "action" Enums(move,copy)
// @Success 200 {string} string "ok"
// @Router /file/operate [post]
func PostOperateFileOrDir(c *gin.Context) {
from := c.PostForm("from")
to := c.PostForm("to")
t := c.PostForm("type")
if len(from) == 0 || len(t) == 0 || len(to) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if t == "move" {
lastPath := from[strings.LastIndex(from, "/")+1:]
if !file.CheckNotExist(to + "/" + lastPath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_OR_DIR_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
err := os.Rename(from, to+"/"+lastPath)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
} else if t == "copy" {
err := file.CopyDir(from, to)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
} else {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary delete file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "path"
// @Success 200 {string} string "ok"
// @Router /file/delete [delete]
func DeleteFile(c *gin.Context) {
path := c.Query("path")
//err := os.Remove(path)
err := os.RemoveAll(path)
if err != nil {
fmt.Println(err)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary update file
// @Produce application/json
// @Accept multipart/form-data
// @Tags file
// @Security ApiKeyAuth
// @Param path formData string true "path"
// @Param content formData string true "content"
// @Success 200 {string} string "ok"
// @Router /file/update [put]
func PutFileContent(c *gin.Context) {
path := c.PostForm("path")
content := c.PostForm("content")
if !file.Exists(path) {
c.JSON(oasis_err2.FILE_ALREADY_EXISTS, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
//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
}
err = file.CreateFileAndWriteContent(path, content)
if err != nil {
fmt.Println(err)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

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

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

@@ -0,0 +1,496 @@
package v1
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
)
func PersonTest(c *gin.Context) {
token := c.Query("token")
_, err := uuid.FromString(token)
fmt.Println(err)
//service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9")
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = token
msg.UUId = uuid.NewV4().String()
dd, err := service.Dial(msg, true)
if err == nil {
fmt.Println(err)
}
fmt.Println(dd)
user := service.MyService.Casa().GetUserInfoByShareId(token)
if reflect.DeepEqual(user, model.UserInfo{}) {
fmt.Println("空数据")
}
fmt.Println(user)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Retry the file that failed to download
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param uui path string true "download uuid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/refile/{uuid} [get]
func GetPersonReFile(c *gin.Context) {
uid := c.Param("uuid")
_, err := uuid.FromString(uid)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
task := service.MyService.Download().GetDownloadById(uid)
if reflect.DeepEqual(task, model2.PersonDownloadDBModel{}) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
return
}
token := task.From
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
return
}
m := model.MessageModel{}
m.Data = task.Path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDOWNLOAD
m.UUId = uid
go service.Dial(m, false)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary download file
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param share_id query string true "opponent share_id"
// @Param path query string true "file path"
// @Param file_name query string true "file name"
// @Param local_path query string true "local_path"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/file [get]
func GetPersonFile(c *gin.Context) {
path := c.Query("path")
localPath := c.Query("local_path")
token := c.Query("share_id")
fileName := c.Query("file_name")
_, err := uuid.FromString(token)
if len(path) == 0 || err != nil || len(localPath) == 0 || len(fileName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if file.CheckNotExist(localPath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
return
}
// task id
uuid := uuid.NewV4().String()
task := model2.PersonDownloadDBModel{}
task.UUID = uuid
task.Name = fileName
task.Length = 0
task.From = token
task.Path = path
task.Size = 0
task.State = types.DOWNLOADAWAIT
task.Created = time.Now().Unix()
task.Type = 0
task.LocalPath = localPath
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
return
}
service.MyService.Download().AddDownloadTask(task)
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDOWNLOAD
m.UUId = uuid
go service.Dial(m, false)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary delete download file records
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param uuid path string true "download uuid"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/file/{uuid} [delete]
func DeletePersonDownloadFile(c *gin.Context) {
id := c.Param("uuid")
_, err := uuid.FromString(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
task := service.MyService.Download().GetDownloadById(id)
if task.State == types.DOWNLOADING {
m := model.MessageModel{}
m.Data = ""
m.From = config.ServerInfo.Token
m.To = task.From
m.Type = types.PERSONCANCEL
m.UUId = task.UUID
service.CancelList[task.UUID] = task.UUID
service.Dial(m, false)
}
service.MyService.Download().DelDownload(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Get file download list
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param state query int false "wait:0,downloading:1,pause:2,finish:3,error:4,finished:5" Enums(0,1,2,3,4,5)
// @Security ApiKeyAuth
// @Success 200 {object} []model2.PersonDownloadDBModel
// @Router /person/list [get]
func GetPersonDownloadList(c *gin.Context) {
state := c.DefaultQuery("state", "")
list := service.MyService.Download().GetDownloadListByState(state)
//if it is downloading, it need to add 'already'
for i := 0; i < len(list); i++ {
if list[i].State == types.DOWNLOADING {
tempDir := config.AppInfo.RootPath + "/temp" + "/" + list[i].UUID
files, err := ioutil.ReadDir(tempDir)
if err == nil {
list[i].Already = len(files)
}
}
list[i].Duration = time.Now().Unix() - list[i].Created
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary edit friend's remarks
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param remarks formData string true "remarks name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/remarks/{shareid} [put]
func PutPersonRemarks(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
mark := c.PostForm("remarks")
if err != nil || len(mark) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
friend.Mark = mark
service.MyService.Friend().EditFriendMark(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary get my friend list
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {object} []model2.FriendModel
// @Router /person/users [get]
func GetPersonFriend(c *gin.Context) {
list := service.MyService.Friend().GetFriendList()
for i := 0; i < len(list); i++ {
if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
list[i].OnLine = true
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary add friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/user/{shareids} [post]
func PostAddPersonFriend(c *gin.Context) {
token := c.Param("shareids")
tokenList := strings.Split(token, ",")
for _, v := range tokenList {
_, err := uuid.FromString(v)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if v == config.ServerInfo.Token {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_MYSELF, Message: oasis_err2.GetMsg(oasis_err2.PERSON_MYSELF)})
return
}
udb := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: v})
if !reflect.DeepEqual(udb, model2.FriendModel{Token: v}) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_FRIEND, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_FRIEND)})
return
}
user := service.MyService.Casa().GetUserInfoByShareId(v)
if reflect.DeepEqual(user, model.UserInfo{}) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_NOT_EXIST_USER, Message: oasis_err2.GetMsg(oasis_err2.PERSON_NOT_EXIST_USER)})
return
}
message := model.MessageModel{}
message.Type = types.PERSONCONNECTION
message.Data = v
message.From = config.ServerInfo.Token
message.To = v
message.UUId = uuid.NewV4().String()
go service.Dial(message, true)
friend := model2.FriendModel{}
friend.Token = v
friend.Avatar = user.Avatar
friend.Block = false
friend.NickName = user.NickName
friend.Profile = user.Desc
friend.Version = user.Version
service.MyService.Friend().AddFriend(friend)
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Get a list of directories
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param share_id query string true "Opponent share_id"
// @Param path query string true "dir path"
// @Security ApiKeyAuth
// @Success 200 {object} []model.Path
// @Router /person/directory [get]
func GetPersonDirectory(c *gin.Context) {
path := c.Query("path")
token := c.Query("share_id")
_, err := uuid.FromString(token)
if len(path) == 0 || err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if _, ok := service.UDPAddressMap[token]; !ok {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_REMOTE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.PERSON_REMOTE_ERROR)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONDIRECTORY
m.UUId = uuid
result, err := service.Dial(m, false)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
dataModel := []model.Path{}
if uuid == m.UUId {
dataModelByte, _ := json.Marshal(result.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: 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), Data: dataModel})
}
// @Summary Modify the download storage directory
// @Produce application/json
// @Accept multipart/form-data
// @Tags person
// @Security ApiKeyAuth
// @Param path formData string true "path"
// @Success 200 {string} string "ok"
// @Router /person/down/dir [post]
func PostPersonDownDir(c *gin.Context) {
downPath := c.PostForm("path")
if len(downPath) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if file.CheckNotExist(downPath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DIR_NOT_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.DIR_NOT_EXISTS)})
return
}
config.Cfg.Section("file").Key("DownloadDir").SetValue(downPath)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
config.FileSettingInfo.DownloadDir = downPath
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Get the download storage directory
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/down/dir [get]
func GetPersonDownDir(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.DownloadDir})
}
// @Summary Modify the shared directory
// @Produce application/json
// @Accept multipart/form-data
// @Tags person
// @Security ApiKeyAuth
// @Param share formData string true "share"
// @Success 200 {string} string "ok"
// @Router /person/share [post]
func PostPersonShare(c *gin.Context) {
share := c.PostForm("share")
if len(share) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
var list []string
json.Unmarshal([]byte(share), &list)
if len(list) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
for _, v := range list {
if !file.Exists(v) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
}
config.Cfg.Section("file").Key("ShareDir").SetValue(strings.Join(list, "|"))
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
config.FileSettingInfo.ShareDir = list
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Get the shared directory
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/share [get]
func GetPersonShare(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.ShareDir})
}
// @Summary Modify disabled status
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param block formData bool false "Disable or not,Default:false "
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/block/{shareid} [put]
func PutPersonBlock(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
block, _ := strconv.ParseBool(c.PostForm("block"))
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
friend.Block = block
service.MyService.Friend().EditFriendBlock(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Delete my friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/user/{shareid} [delete]
func DeletePersonFriend(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
service.MyService.Friend().DeleteFriend(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary Get public person
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/public [delete]
func GetPersonPublic(c *gin.Context) {
list := service.MyService.Casa().GetPersonPublic()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}

35
route/v1/sync.go Normal file
View File

@@ -0,0 +1,35 @@
package v1
import (
"net/http"
"net/http/httputil"
"net/url"
"strings"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/gin-gonic/gin"
)
func SyncToSyncthing(c *gin.Context) {
u := c.Param("url")
target := "http://" + strings.Split(c.Request.Host, ":")[0] + ":" + config.SystemConfigInfo.SyncPort
remote, err := url.Parse(target)
if err != nil {
return
}
proxy := httputil.NewSingleHostReverseProxy(remote)
c.Request.Header.Add("X-API-Key", config.SystemConfigInfo.SyncKey)
//c.Request.Header.Add("X-API-Key", config.SystemConfigInfo.SyncKey)
c.Request.URL.Path = u
proxy.ServeHTTP(c.Writer, c.Request)
}
func GetSyncConfig(c *gin.Context) {
data := make(map[string]string)
data["key"] = config.SystemConfigInfo.SyncKey
data["port"] = config.SystemConfigInfo.SyncPort
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
}

View File

@@ -4,12 +4,18 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"reflect"
"strconv"
"strings"
"time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
"github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -28,13 +34,12 @@ func CheckVersion(c *gin.Context) {
need, version := version.IsNeedUpdate()
if need {
installLog := model2.AppNotify{}
installLog.CustomId = ""
installLog.State = 0
installLog.Message = "New version " + version.Version + " is ready, ready to upgrade"
installLog.Speed = 100
installLog.Type = types.NOTIFY_TYPE_NEED_CONFIRM
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.Name = "CasaOS System"
service.MyService.Notify().AddLog(installLog)
}
data := make(map[string]interface{}, 1)
@@ -65,14 +70,26 @@ func GetSystemConfig(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(config.SystemConfigInfo.ConfigStr)})
}
// @Summary get logs
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/error/logs [get]
func GetCasaOSErrorLogs(c *gin.Context) {
line, _ := strconv.Atoi(c.DefaultQuery("line", "100"))
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: service.MyService.System().GetCasaOSLogs(line)})
}
// @Summary 修改配置文件
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param file formData file true "用户头像"
// @Tags sys
// @Param config formData string true "config json string"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/changhead [post]
// @Router /sys/changhead [post]
func PostSetSystemConfig(c *gin.Context) {
buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf)
@@ -91,9 +108,33 @@ func GetSystemConfigDebug(c *gin.Context) {
array := service.MyService.System().GetSystemConfigDebug()
disk := service.MyService.ZiMa().GetDiskInfo()
array = append(array, fmt.Sprintf("disk,totle:%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()
@@ -114,8 +155,9 @@ func GetWidgetConfig(c *gin.Context) {
func PostSetWidgetConfig(c *gin.Context) {
buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf)
fmt.Println("错误", strconv.Itoa(n))
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
fmt.Println("错误1", string(buf[0:n]))
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
@@ -124,6 +166,58 @@ func PostSetWidgetConfig(c *gin.Context) {
})
}
// @Summary get casaos server port
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/port [get]
func GetCasaOSPort(c *gin.Context) {
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
Data: config.ServerInfo.HttpPort,
})
}
// @Summary edit casaos server port
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Param port formData string true "port"
// @Success 200 {string} string "ok"
// @Router /sys/port [put]
func PutCasaOSPort(c *gin.Context) {
port, err := strconv.Atoi(c.PostForm("port"))
if err != nil {
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.ERROR,
Message: err.Error(),
})
return
}
isAvailable := port2.IsPortAvailable(port, "tcp")
if !isAvailable {
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.PORT_IS_OCCUPIED,
Message: oasis_err.GetMsg(oasis_err.PORT_IS_OCCUPIED),
})
return
}
service.MyService.System().UpSystemPort(strconv.Itoa(port))
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
})
}
// @Summary 检查是否进入引导状态
// @Produce application/json
// @Accept application/json
@@ -133,7 +227,7 @@ func PostSetWidgetConfig(c *gin.Context) {
// @Router /guide/check [get]
func GetGuideCheck(c *gin.Context) {
initUser := false
if config.UserInfo.UserName == "admin" && config.UserInfo.PWD == "zimaboard" && version.VersionCompared("0.1.7", types.CURRENTVERSION) {
if !config.UserInfo.Initialized {
initUser = true
}
data := make(map[string]interface{}, 1)
@@ -145,3 +239,203 @@ func GetGuideCheck(c *gin.Context) {
Data: data,
})
}
// @Summary active killing casaos
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/kill [post]
func PostKillCasaOS(c *gin.Context) {
os.Exit(0)
}
// @Summary Turn off usb auto-mount
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/usg/off [put]
func PutSystemOffUSBAutoMount(c *gin.Context) {
service.MyService.System().UpdateUSBAutoMount("False")
service.MyService.System().ExecUSBAutoMountShell("False")
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
})
}
// @Summary Turn off usb auto-mount
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/usb [get]
func GetSystemUSBAutoMount(c *gin.Context) {
state := "True"
if config.ServerInfo.USBAutoMount == "False" {
state = "False"
}
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
Data: state,
})
}
// @Summary Turn off usb auto-mount
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/usb/on [put]
func PutSystemOnUSBAutoMount(c *gin.Context) {
service.MyService.System().UpdateUSBAutoMount("True")
service.MyService.System().ExecUSBAutoMountShell("True")
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
})
}
// @Summary system info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/info [get]
func Info(c *gin.Context) {
var data = make(map[string]interface{}, 6)
list := service.MyService.Disk().LSBLK(true)
summary := model.Summary{}
healthy := true
findSystem := 0
for i := 0; i < len(list); i++ {
if len(list[i].Children) > 0 && findSystem == 0 {
for j := 0; j < len(list[i].Children); j++ {
if len(list[i].Children[j].Children) > 0 {
for _, v := range list[i].Children[j].Children {
if v.MountPoint == "/" {
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
findSystem = 1
break
}
}
} else {
if list[i].Children[j].MountPoint == "/" {
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
findSystem = 1
break
}
}
}
}
if findSystem == 1 {
findSystem += 1
continue
}
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
if reflect.DeepEqual(temp, model.SmartctlA{}) {
continue
}
//list[i].Temperature = temp.Temperature.Current
if !temp.SmartStatus.Passed {
healthy = false
}
if len(list[i].Children) > 0 {
for _, v := range list[i].Children {
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
}
}
}
}
summary.Health = healthy
data["disk"] = summary
usbList := service.MyService.Disk().LSBLK(false)
usb := []model.DriveUSB{}
for _, v := range usbList {
if v.Tran == "usb" {
temp := model.DriveUSB{}
temp.Model = v.Model
temp.Name = v.Name
temp.Size = v.Size
mountTemp := true
if len(v.Children) == 0 {
mountTemp = false
}
for _, child := range v.Children {
if len(child.MountPoint) > 0 {
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
temp.Avail += avail
used, _ := strconv.ParseUint(child.FSUsed, 10, 64)
temp.Used += used
} else {
mountTemp = false
}
}
temp.Mount = mountTemp
usb = append(usb, temp)
}
}
data["usb"] = usb
cpu := service.MyService.ZiMa().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum()
cpuData := make(map[string]interface{})
cpuData["percent"] = cpu
cpuData["num"] = num
data["cpu"] = cpuData
data["mem"] = service.MyService.ZiMa().GetMemInfo()
//拼装网络信息
netList := service.MyService.ZiMa().GetNetInfo()
newNet := []model.IOCountersStat{}
nets := service.MyService.ZiMa().GetNet(true)
for _, n := range netList {
for _, netCardName := range nets {
if n.Name == netCardName {
item := *(*model.IOCountersStat)(unsafe.Pointer(&n))
item.State = strings.TrimSpace(service.MyService.ZiMa().GetNetState(n.Name))
item.Time = time.Now().Unix()
newNet = append(newNet, item)
break
}
}
}
data["net"] = newNet
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/config"
jwt2 "github.com/IceWhaleTech/CasaOS/pkg/utils/jwt"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/pkg/utils/version"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
@@ -35,13 +34,13 @@ func Set_Name_Pwd(c *gin.Context) {
username := c.PostForm("username")
pwd := c.PostForm("pwd")
//老用户名是否存在即新用户名和密码的验证
if (!(config.UserInfo.UserName == "admin" && config.UserInfo.PWD == "zimaboard" && version.VersionCompared("0.1.7", types.CURRENTVERSION)) && len(config.UserInfo.UserName) > 0) || len(username) == 0 || len(pwd) == 0 {
if config.UserInfo.Initialized || len(username) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK,
model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
//开始设置
err := user_service.SetUser(username, pwd, "", "", "")
err := user_service.SetUser(username, pwd, "", "", "", "")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: fmt.Sprintf("%v", err)})
return
@@ -103,7 +102,7 @@ func Login(c *gin.Context) {
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/changhead [post]
func Up_Load_Head(c *gin.Context) {
func PostUserHead(c *gin.Context) {
file, _, _ := c.Request.FormFile("file")
user_service.UpLoadFile(file, config.UserInfo.Head)
c.JSON(http.StatusOK,
@@ -112,7 +111,6 @@ func Up_Load_Head(c *gin.Context) {
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
Data: config.UserInfo.Head,
})
return
}
// @Summary 修改用户名
@@ -123,17 +121,20 @@ func Up_Load_Head(c *gin.Context) {
// @Param oldname formData string true "Old user name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/changusername [put]
func Chang_User_Name(c *gin.Context) {
// @Router /user/username [put]
func PutUserName(c *gin.Context) {
if config.ServerInfo.LockAccount {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
return
}
oldname := c.PostForm("oldname")
username := c.PostForm("username")
if len(username) == 0 || config.UserInfo.UserName != oldname {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
user_service.SetUser(username, "", "", "", "")
user_service.SetUser(username, "", "", "", "", "")
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
return
}
// @Summary 修改密码
@@ -141,68 +142,160 @@ func Chang_User_Name(c *gin.Context) {
// @Accept multipart/form-data
// @Tags user
// @Param pwd formData string true "Password"
// @Param oldpwd formData string true "Old password"
// @Param old_pwd formData string true "Old password"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/changuserpwd [put]
func Chang_User_Pwd(c *gin.Context) {
oldpwd := c.PostForm("oldpwd")
// @Router /user/password [put]
func PutUserPwd(c *gin.Context) {
oldPwd := c.PostForm("old_pwd")
pwd := c.PostForm("pwd")
if len(pwd) == 0 || config.UserInfo.PWD != oldpwd {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
if config.UserInfo.PWD != oldPwd {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID_OLD, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID_OLD)})
return
}
user_service.SetUser("", pwd, "", "", "")
if config.ServerInfo.LockAccount {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ACCOUNT_LOCK, Message: oasis_err2.GetMsg(oasis_err2.ACCOUNT_LOCK)})
return
}
if len(pwd) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_IS_EMPTY, Message: oasis_err2.GetMsg(oasis_err2.PWD_IS_EMPTY)})
return
}
user_service.SetUser("", pwd, "", "", "", "")
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
return
}
// @Summary 修改用户信息
// @Summary edit user info
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param username formData string false "User Name"
// @Param user_name formData string false "User Name"
// @Param email formData string false "Email"
// @Param description formData string false "Description"
// @Param pwd formData string false "Password"
// @Param oldpwd formData string false "Old password"
// @Param old_pwd formData string false "Old password"
// @Param nick_name formData string false "nick name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/changuserinfo [post]
func Chang_User_Info(c *gin.Context) {
username := c.PostForm("username")
// @Router /user/info [post]
func PostUserChangeInfo(c *gin.Context) {
username := c.PostForm("user_name")
email := c.PostForm("email")
description := c.PostForm("description")
oldpwd := c.PostForm("oldpwd")
nickName := c.PostForm("nick_name")
oldpwd := c.PostForm("old_pwd")
pwd := c.PostForm("pwd")
if len(pwd) > 0 && config.UserInfo.PWD != oldpwd {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PWD_INVALID, Message: oasis_err2.GetMsg(oasis_err2.PWD_INVALID)})
return
}
user_service.SetUser(username, pwd, "", email, description)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
return
user_service.SetUser(username, pwd, "", email, description, nickName)
data := make(map[string]string, 4)
data["token"] = jwt2.GetToken(username, pwd)
data["user_name"] = username
data["head"] = config.UserInfo.Head
data["nick_name"] = config.UserInfo.NickName
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary 获取用户详情
// @Summary edit user nick
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param nick_name formData string false "nick name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/nick [put]
func PutUserChangeNick(c *gin.Context) {
nickName := c.PostForm("nick_name")
if len(nickName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
user_service.SetUser("", "", "", "", "", nickName)
data := make(map[string]string, 1)
data["nick_name"] = config.UserInfo.NickName
go service.MyService.Casa().PushUserInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary edit user description
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param description formData string false "Description"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/desc [put]
func PutUserChangeDesc(c *gin.Context) {
desc := c.PostForm("description")
if len(desc) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
user_service.SetUser("", "", "", "", desc, "")
data := make(map[string]string, 1)
data["description"] = config.UserInfo.Description
go service.MyService.Casa().PushUserInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary Modify user person information (Initialization use)
// @Produce application/json
// @Accept multipart/form-data
// @Tags user
// @Param nick_name formData string false "user nick name"
// @Param description formData string false "Description"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/person/info [post]
func PostUserPersonInfo(c *gin.Context) {
desc := c.PostForm("description")
nickName := c.PostForm("nick_name")
if len(desc) == 0 || len(nickName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
user_service.SetUser("", "", "", "", desc, nickName)
data := make(map[string]string, 2)
data["description"] = config.UserInfo.Description
data["nick_name"] = config.UserInfo.NickName
go service.MyService.Casa().PushUserInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary get user info
// @Produce application/json
// @Accept mapplication/json
// @Tags user
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/info [get]
func UserInfo(c *gin.Context) {
var u = make(map[string]string, 2)
func GetUserInfo(c *gin.Context) {
var u = make(map[string]string, 5)
u["user_name"] = config.UserInfo.UserName
u["token"] = config.UserInfo.Token
u["head"] = config.UserInfo.Head
u["email"] = config.UserInfo.Email
u["description"] = config.UserInfo.Description
u["nick_name"] = config.UserInfo.NickName
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err2.SUCCESS,
Message: oasis_err2.GetMsg(oasis_err2.SUCCESS),
Data: u,
})
return
}
// @Summary Get my shareId
// @Produce application/json
// @Accept application/json
// @Tags user
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /user/shareid [get]
func GetUserShareID(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.ServerInfo.Token})
}

View File

@@ -1,459 +0,0 @@
package v1
import (
json2 "encoding/json"
"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
// @Produce application/json
// @Accept multipart/form-data
// @Tags zerotier
// @Param username formData string true "User name"
// @Param pwd formData string true "password"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/login [post]
func ZeroTierGetToken(c *gin.Context) {
username := c.PostForm("username")
pwd := c.PostForm("pwd")
if len(username) == 0 || len(pwd) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
errInfo := service.MyService.ZeroTier().GetToken(username, pwd)
if len(errInfo) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.GET_TOKEN_ERROR)})
} else {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
}
// @Summary 注册zerotier
// @Produce application/json
// @Accept multipart/form-data
// @Tags zerotier
// @Param firstName formData string true "first name"
// @Param pwd formData string true "password"
// @Param email formData string true "email"
// @Param lastName formData string true "last name"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/register [post]
func ZeroTierRegister(c *gin.Context) {
firstName := c.PostForm("firstName")
pwd := c.PostForm("pwd")
email := c.PostForm("email")
lastName := c.PostForm("lastName")
if len(firstName) == 0 || len(pwd) == 0 || len(email) == 0 || len(lastName) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
errInfo := service.MyService.ZeroTier().ZeroTierRegister(email, lastName, firstName, pwd)
if len(errInfo) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} else {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: errInfo})
}
}
// @Summary 是否需要登录zerotier
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Success 200 {string} string "false:需要登录true:不需要登录"
// @Router /zerotier/islogin [get]
func ZeroTierIsNeedLogin(c *gin.Context) {
if len(config.ZeroTierInfo.Token) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: false})
} else {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: true})
}
}
// @Summary 获取zerotier网络列表
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/list [get]
func ZeroTierGetNetworkList(c *gin.Context) {
jsonList, joined := service.MyService.ZeroTier().ZeroTierNetworkList(config.ZeroTierInfo.Token)
rdata := make(map[string]interface{})
rdata["network_list"] = jsonList
rdata["joined"] = joined
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
}
// @Summary 获取zerotier网络详情
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Success 200 {string} string "ok"
// @Router /zerotier/info/{id} [get]
func ZeroTierGetNetworkGetInfo(c *gin.Context) {
id := c.Param("id")
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info, joined := service.MyService.ZeroTier().ZeroTierGetInfo(config.ZeroTierInfo.Token, id)
rdata := make(map[string]interface{})
rdata["info"] = info
rdata["joined"] = joined
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: rdata})
}
//// @Summary 获取zerotier网络状态
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Success 200 {string} string "ok"
//// @Router /zerotier/status [get]
//func ZeroTierGetNetworkGetStatus(c *gin.Context) {
// status := service.MyService.ZeroTier().ZeroTierGetStatus(config.ZeroTierInfo.Token)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: status})
//}
//// @Summary 修改网络类型
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param type formData string true "Private true/false"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/type/{id} [put]
//func ZeroTierEditType(c *gin.Context) {
// id := c.Param("id")
// t := c.PostForm("type")
// if len(id) == 0 || len(t) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"config":{"private":` + t + `}}`
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
//// @Summary 修改名称
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param name formData string true "需要过滤特殊字符串"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/name/{id} [put]
//func ZeroTierEditName(c *gin.Context) {
// id := c.Param("id")
// name := c.PostForm("name")
// if len(id) == 0 || len(name) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"config":{"name":"` + name + `"}}`
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
//// @Summary V6Assign (注意三个属性需要一起传过来,不传的会被zerotier设置成false)
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param v6plan formData string false "true/false"
//// @Param rfc formData string false "true/false"
//// @Param auto formData string false "true/false"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/v6assign/{id} [put]
//func ZeroTierEditV6Assign(c *gin.Context) {
// id := c.Param("id")
// v6plan := c.PostForm("v6plan")
// rfc := c.PostForm("rfc")
// auto := c.PostForm("auto")
// if len(id) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// var spicing string
// if len(v6plan) > 0 {
// spicing = `"6plane":` + v6plan
// }
// if len(rfc) > 0 {
// if len(spicing) > 0 {
// spicing += ","
// }
// spicing += `"rfc4193":` + rfc
// }
//
// if len(auto) > 0 {
// if len(spicing) > 0 {
// spicing += ","
// }
// spicing += `"zt":` + auto
// }
// postData := `{"config":{"v6AssignMode":{` + spicing + `}}}`
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
//// @Summary Broadcast
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param broadcast formData string true "true/false"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/broadcast/{id} [put]
//func ZeroTierEditBroadcast(c *gin.Context) {
// id := c.Param("id")
// broadcast := c.PostForm("broadcast")
// if len(id) == 0 || len(broadcast) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"config":{"enableBroadcast":` + broadcast + `}}`
// info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, postData, id)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
// @Summary 网络列表
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Success 200 {string} string "ok"
// @Router /zerotier/member/{id} [get]
func ZeroTierMemberList(c *gin.Context) {
id := c.Param("id")
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.ZeroTier().MemberList(config.ZeroTierInfo.Token, id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary create new network
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/create [post]
func ZeroTierCreateNetwork(c *gin.Context) {
info := service.MyService.ZeroTier().CreateNetwork(config.ZeroTierInfo.Token)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
//// @Summary 通过/拒绝客户端
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param mId path string true "member_id"
//// @Param auth formData string true "true/false"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/member/{id}/auth/{mId} [put]
//func ZeroTierMemberAuth(c *gin.Context) {
// id := c.Param("id")
// mId := c.Param("mId")
// auth := c.PostForm("auth")
// if len(id) == 0 || len(mId) == 0 || len(auth) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"config":{"authorized":` + auth + `}}`
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
//// @Summary 修改名字
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param mId path string true "member_id"
//// @Param name formData string true "name"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/member/{id}/name/{mId} [put]
//func ZeroTierMemberName(c *gin.Context) {
// id := c.Param("id")
// mId := c.Param("mId")
// name := c.PostForm("name")
// if len(id) == 0 || len(mId) == 0 || len(name) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"name":"` + name + `"}`
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
//// @Summary 修改桥接
//// @Produce application/json
//// @Accept application/json
//// @Tags zerotier
//// @Security ApiKeyAuth
//// @Param id path string true "network id"
//// @Param mId path string true "member_id"
//// @Param bridge formData string true "true/false"
//// @Success 200 {string} string "ok"
//// @Router /zerotier/member/{id}/bridge/{mId} [put]
//func ZeroTierMemberBridge(c *gin.Context) {
// id := c.Param("id")
// mId := c.Param("mId")
// bridge := c.PostForm("bridge")
// if len(id) == 0 || len(mId) == 0 || len(bridge) == 0 {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// postData := `{"config":{"activeBridge":` + bridge + `}}`
// info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, postData, id, mId)
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
//}
// @Summary 修改网络
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Param json formData string true "json数据"
// @Success 200 {string} string "ok"
// @Router /zerotier/edit/{id} [put]
func ZeroTierEdit(c *gin.Context) {
id := c.Param("id")
json := c.PostForm("json")
if len(id) == 0 || len(json) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.ZeroTier().EditNetwork(config.ZeroTierInfo.Token, json, id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary 获取已加入的网络
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/joined/list [get]
func ZeroTierJoinedList(c *gin.Context) {
info := service.MyService.ZeroTier().GetJoinNetworks()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: json2.RawMessage(info)})
}
// @Summary 修改网络用户信息
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Param mId path string true "mId"
// @Param json formData string true "json数据"
// @Success 200 {string} string "ok"
// @Router /zerotier/member/{id}/edit/{mId} [put]
func ZeroTierMemberEdit(c *gin.Context) {
id := c.Param("id")
mId := c.Param("mId")
json := c.PostForm("json")
if len(id) == 0 || len(json) == 0 || len(mId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.ZeroTier().EditNetworkMember(config.ZeroTierInfo.Token, json, id, mId)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary 删除网络中的用户
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Param mId path string true "member_id"
// @Success 200 {string} string "ok"
// @Router /zerotier/member/{id}/del/{mId} [delete]
func ZeroTierMemberDelete(c *gin.Context) {
id := c.Param("id")
mId := c.Param("mId")
if len(id) == 0 || len(mId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.ZeroTier().DeleteMember(config.ZeroTierInfo.Token, id, mId)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary 删除网络
// @Produce application/json
// @Accept application/json
// @Tags zerotier
// @Security ApiKeyAuth
// @Param id path string true "network id"
// @Success 200 {string} string "ok"
// @Router /zerotier/network/{id}/del [delete]
func ZeroTierDeleteNetwork(c *gin.Context) {
id := c.Param("id")
if len(id) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
info := service.MyService.ZeroTier().DeleteNetwork(config.ZeroTierInfo.Token, id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
}
// @Summary 加入网络
// @Produce application/json
// @Accept multipart/form-data
// @Tags zerotier
// @Param id path string true "network id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/join/{id} [post]
func ZeroTierJoinNetwork(c *gin.Context) {
networkId := c.Param("id")
service.MyService.ZeroTier().ZeroTierJoinNetwork(networkId)
if len(networkId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary 获取zerotier网络列表
// @Produce application/json
// @Accept multipart/form-data
// @Tags zerotier
// @Param id path string true "network id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zerotier/leave/{id} [post]
func ZeroTierLeaveNetwork(c *gin.Context) {
networkId := c.Param("id")
service.MyService.ZeroTier().ZeroTierLeaveNetwork(networkId)
if len(networkId) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

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

View File

@@ -2,35 +2,41 @@ package service
import (
"context"
json2 "encoding/json"
"encoding/json"
"io"
"io/ioutil"
"runtime"
"strings"
"sync"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
client2 "github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/tidwall/gjson"
"gorm.io/gorm"
"strings"
"time"
)
type AppService interface {
GetMyList(index, size int, position bool) *[]model2.MyAppList
SaveContainer(m model2.AppListDBModel)
GetServerAppInfo(id string) model.ServerAppList
GetUninstallInfo(id string) model2.AppListDBModel
RemoveContainerById(id string)
GetContainerInfo(name string) (types.Container, error)
GetAppDBInfo(id string) model2.AppListDBModel
UpdateApp(m model2.AppListDBModel)
GetSimpleContainerInfo(name string) (types.Container, error)
DelAppConfigDir(id string)
DelAppConfigDir(path string)
GetSystemAppList() *[]model2.MyAppList
GetHardwareUsageSteam()
GetHardwareUsage() []model.DockerStatsModel
GetAppStats(id string) string
GetAllDBApps() []model2.AppListDBModel
}
type appStruct struct {
@@ -41,7 +47,7 @@ type appStruct struct {
//获取我的应用列表
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
}
@@ -52,11 +58,10 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
}
//获取本地数据库应用
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan").Find(&lm)
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image").Find(&lm)
list := []model2.MyAppList{}
lMap := make(map[string]interface{})
@@ -69,11 +74,70 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
lMap[dbModel.ContainerId] = dbModel
}
}
for _, container := range containers {
if lMap[container.ID] != nil && container.Labels["origin"] != "system" {
m := lMap[container.ID].(model2.AppListDBModel)
if len(m.Label) == 0 {
m.Label = m.Title
}
// info, err := cli.ContainerInspect(context.Background(), container.ID)
// var tm string
// if err != nil {
// tm = time.Now().String()
// } else {
// tm = info.State.StartedAt
//}
list = append(list, model2.MyAppList{
Name: m.Label,
Icon: m.Icon,
State: container.State,
CustomId: strings.ReplaceAll(container.Names[0], "/", ""),
Port: m.PortMap,
Index: m.Index,
//UpTime: tm,
Image: m.Image,
Slogan: m.Slogan,
//Rely: m.Rely,
})
}
}
return &list
}
//system application list
func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
//获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
}
defer cli.Close()
fts := filters.NewArgs()
fts.Add("label", "origin=system")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
a.log.Error("获取docker容器失败", "app.sys", "line:123", err)
}
//获取本地数据库应用
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
list := []model2.MyAppList{}
lMap := make(map[string]interface{})
for _, dbModel := range lm {
lMap[dbModel.ContainerId] = dbModel
}
for _, container := range containers {
if lMap[container.ID] != nil {
var m model2.AppListDBModel
m = lMap[container.ID].(model2.AppListDBModel)
m := lMap[container.ID].(model2.AppListDBModel)
if len(m.Label) == 0 {
m.Label = m.Title
}
@@ -93,16 +157,22 @@ func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppLis
Port: m.PortMap,
Index: m.Index,
UpTime: tm,
Image: m.Image,
Slogan: m.Slogan,
Volumes: m.Volumes,
//Rely: m.Rely,
})
}
}
return &list
}
func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image").Find(&lm)
return lm
}
//获取我的应用列表
func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
@@ -115,7 +185,7 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
filters.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err)
}
if len(containers) > 0 {
@@ -135,6 +205,10 @@ func (a *appStruct) GetSimpleContainerInfo(name string) (types.Container, error)
filters := filters.NewArgs()
filters.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil {
return types.Container{}, err
}
if len(containers) > 0 {
return containers[0], nil
}
@@ -155,27 +229,6 @@ func (a *appStruct) GetUninstallInfo(id string) model2.AppListDBModel {
return m
}
func (a *appStruct) GetServerAppInfo(id string) model.ServerAppList {
head := make(map[string]string)
t := make(chan string)
go func() {
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
t <- gjson.Get(str, "data").String()
}()
head["Authorization"] = <-t
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/info/"+id, head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
return info
}
//创建容器成功后保存容器
func (a *appStruct) SaveContainer(m model2.AppListDBModel) {
a.db.Table(model2.CONTAINERTABLENAME).Create(&m)
@@ -185,14 +238,125 @@ func (a *appStruct) UpdateApp(m model2.AppListDBModel) {
a.db.Table(model2.CONTAINERTABLENAME).Save(&m)
}
func (a *appStruct) DelAppConfigDir(id string) {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + docker.GetDir(id, "/config"))
func (a *appStruct) DelAppConfigDir(path string) {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + path)
}
func (a *appStruct) RemoveContainerById(id string) {
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
}
var dataStats sync.Map
var isFinish bool = false
func (a *appStruct) GetAppStats(id string) string {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return ""
}
defer cli.Close()
con, err := cli.ContainerStats(context.Background(), id, false)
if err != nil {
return err.Error()
}
defer con.Body.Close()
c, _ := ioutil.ReadAll(con.Body)
return string(c)
}
func (a *appStruct) GetHardwareUsage() []model.DockerStatsModel {
steam := true
for !isFinish {
if steam {
steam = false
go func() {
a.GetHardwareUsageSteam()
}()
}
runtime.Gosched()
}
list := []model.DockerStatsModel{}
dataStats.Range(func(key, value interface{}) bool {
list = append(list, value.(model.DockerStatsModel))
return true
})
return list
}
func (a *appStruct) GetHardwareUsageSteam() {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return
}
defer cli.Close()
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
for i := 0; i < 100; i++ {
if config.CasaOSGlobalVariables.AppChange {
lm = []model2.AppListDBModel{}
config.CasaOSGlobalVariables.AppChange = false
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
dataApps := dataStats
dataStats.Range(func(key, value interface{}) bool {
dataStats.Delete(key)
return true
})
for _, v := range lm {
m, _ := dataApps.Load(v.ContainerId)
if m != nil {
dataStats.Store(v.ContainerId, m)
}
}
}
var wg sync.WaitGroup
for _, v := range lm {
wg.Add(1)
go func(v model2.AppListDBModel, i int) {
defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
if err != nil {
return
}
decode := json.NewDecoder(stats.Body)
var data interface{}
if err := decode.Decode(&data); err == io.EOF {
return
}
m, _ := dataStats.Load(v.ContainerId)
dockerStats := model.DockerStatsModel{}
if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data
}
dockerStats.Data = data
dockerStats.Icon = v.Icon
if len(v.Label) > 0 {
dockerStats.Title = v.Label
} else {
dockerStats.Title = v.Title
}
dataStats.Store(v.ContainerId, dockerStats)
if i == 99 {
stats.Body.Close()
}
}(v, i)
}
wg.Wait()
isFinish = true
time.Sleep(time.Second * 3)
}
isFinish = false
cancel()
}
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService {
return &appStruct{db: db, log: logger}
}

233
service/casa.go Normal file
View File

@@ -0,0 +1,233 @@
package service
import (
"encoding/json"
json2 "encoding/json"
"fmt"
"strconv"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/tidwall/gjson"
)
type CasaService interface {
GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList)
GetServerCategoryList() []model.ServerCategoryList
GetTaskList(size int) []model2.TaskDBModel
GetServerAppInfo(id, t string, language string) model.ServerAppList
ShareAppFile(body []byte) string
PushHeart(id, t string, language string)
PushAppAnalyse(uuid, t string, name, language string)
PushConnectionStatus(uuid, err string, from, to, event string)
PushUserInfo()
GetUserInfoByShareId(shareId string) model.UserInfo
GetPersonPublic() (list []model.FriendsModel)
}
type casaService struct {
}
func (o *casaService) ShareAppFile(body []byte) string {
head := make(map[string]string)
head["Authorization"] = GetToken()
content := httper2.Post(config.ServerInfo.ServerApi+"/v1/community/add", body, "application/json", head)
return content
}
func (o *casaService) GetTaskList(size int) []model2.TaskDBModel {
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/task/list/"+strconv.Itoa(size), head)
list := []model2.TaskDBModel{}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
return list
}
func (o *casaService) GetServerList(index, size, tp, categoryId, key, language string) (recommend, list, community []model.ServerAppList) {
keyName := fmt.Sprintf("list_%s_%s_%s_%s_%s", index, size, tp, categoryId, language)
if result, ok := Cache.Get(keyName); ok {
res, ok := result.(string)
if ok {
json2.Unmarshal([]byte(gjson.Get(res, "data.list").String()), &list)
json2.Unmarshal([]byte(gjson.Get(res, "data.recommend").String()), &recommend)
json2.Unmarshal([]byte(gjson.Get(res, "data.community").String()), &community)
return
}
}
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/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)
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community)
if len(list) > 0 {
Cache.SetDefault(keyName, listS)
}
return
}
func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
list := []model.ServerCategoryList{}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
return list
}
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+"?t="+t+"&language="+language, head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
return info
}
func GetToken() string {
t := make(chan string)
keyName := "casa_token"
var auth string
if result, ok := Cache.Get(keyName); ok {
auth, ok = result.(string)
if ok {
return auth
}
}
go func() {
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
t <- gjson.Get(str, "data").String()
}()
auth = <-t
Cache.SetDefault(keyName, auth)
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 (o *casaService) PushAppAnalyse(uuid, t string, name, language string) {
m := model.AppAnalyse{}
m.UUId = uuid
m.Type = t
m.Name = name
m.Language = language
b, _ := json.Marshal(m)
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/app", b, "application/json", head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
}
func (o *casaService) PushConnectionStatus(uuid, err string, from, to, event string) {
m := model.ConnectionStatus{}
m.UUId = uuid
m.Error = err
m.From = from
m.To = to
m.Event = event
b, _ := json.Marshal(m)
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/analyse/connect", b, "application/json", head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
}
func (o *casaService) PushUserInfo() {
m := model.UserInfo{}
m.Desc = config.UserInfo.Description
m.Avatar = config.UserInfo.Avatar
m.NickName = config.UserInfo.NickName
m.ShareId = config.ServerInfo.Token
b, _ := json.Marshal(m)
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Post(config.ServerInfo.ServerApi+"/v1/user/info", b, "application/json", head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
}
func (o *casaService) GetUserInfoByShareId(shareId string) model.UserInfo {
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v1/user/info/"+shareId, head)
info := model.UserInfo{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)
return info
}
func (o *casaService) GetPersonPublic() (list []model.FriendsModel) {
head := make(map[string]string)
head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/person/public", head)
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
return list
}
func NewCasaService() CasaService {
return &casaService{}
}

View File

@@ -0,0 +1 @@
package service

View File

@@ -1,12 +1,13 @@
package service
import (
"os/exec"
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service/ddns"
"github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
"os/exec"
)
type ddnsStruct struct {
@@ -20,17 +21,15 @@ type DDNSService interface {
GetConfigList() *[]model.DDNSList
DeleteConfig(id uint) bool
GetType(name string) (uint, string)
SaveConfig(model model.DDNSUpdataDBModel) error
SaveConfig(model model.DDNSUpdateDBModel) error
}
//判断当前添加的是否存在
func (d *ddnsStruct) IsExis(t int, domain string, host string) bool {
var count int64
d.db.Table(model.DDNSLISTTABLENAME).Where("type=? AND domain=? AND host=?", t, domain, host).Count(&count)
if count > 0 {
return true
}
return false
return count > 0
}
//前台获取已配置的ddns列表
@@ -41,7 +40,7 @@ func (d *ddnsStruct) GetConfigList() *[]model.DDNSList {
}
func (d *ddnsStruct) DeleteConfig(id uint) bool {
d.db.Delete(&model.DDNSUpdataDBModel{Id: id})
d.db.Delete(&model.DDNSUpdateDBModel{Id: id})
return true
}
@@ -66,12 +65,12 @@ func (d *ddnsStruct) GetType(name string) (uint, string) {
}
//保存配置到数据库
func (d *ddnsStruct) GetDockerRootDir(model model.DDNSUpdataDBModel) error {
func (d *ddnsStruct) GetDockerRootDir(model model.DDNSUpdateDBModel) error {
return d.db.Create(&model).Error
}
//保存配置到数据库
func (d *ddnsStruct) SaveConfig(model model.DDNSUpdataDBModel) error {
func (d *ddnsStruct) SaveConfig(model model.DDNSUpdateDBModel) error {
return d.db.Create(&model).Error
}
@@ -87,7 +86,7 @@ func chackPing(b chan bool, url string) {
}
//更新列表
func UpdataDDNSList(db *gorm.DB) {
func UpdateDDNSList(db *gorm.DB) {
var s []model.DDNSCoreList
db.Table(model.DDNSLISTTABLENAME).Select("o_ddns_type.name as name,o_ddns_type.api_host as api_host,o_ddns.id,`host`,domain,user_name,`password`,`key`,secret,type").Joins("left join o_ddns_type on o_ddns.type=o_ddns_type.id").Scan(&s)
for _, item := range s {

View File

@@ -31,4 +31,3 @@ func SetOauth(request *http.Request, value string) {
func SetXFilter(request *http.Request, value string) {
request.Header.Set("X-Filter", value)
}

View File

@@ -3,28 +3,73 @@ package service
import (
json2 "encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/shirou/gopsutil/v3/disk"
"github.com/tidwall/gjson"
"strconv"
"strings"
"gorm.io/gorm"
)
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, num string, size uint64) string
AddPartition(path string) string
GetDiskInfoByPath(path string) *disk.UsageStat
MountDisk(path, volume string)
GetSerialAll() []model2.SerialDisk
SaveMountPoint(m model2.SerialDisk)
DeleteMountPoint(path, mountPoint string)
DeleteMount(id string)
UpdateMountPoint(m model2.SerialDisk)
RemoveLSBLKCache()
}
type diskService struct {
log loger2.OLog
db *gorm.DB
}
func (d *diskService) RemoveLSBLKCache() {
key := "system_lsblk"
Cache.Delete(key)
}
func (d *diskService) SmartCTL(path string) model.SmartctlA {
key := "system_smart_" + path
if result, ok := Cache.Get(key); ok {
res, ok := result.(model.SmartctlA)
if ok {
return res
}
}
var m model.SmartctlA
str := command2.ExecSmartCTLByPath(path)
if str == nil {
d.log.Error("smartctl exec error,smartctl")
return m
}
err := json2.Unmarshal([]byte(str), &m)
if err != nil {
d.log.Error("json ummarshal error", err)
}
if !reflect.DeepEqual(m, model.SmartctlA{}) {
Cache.Add(key, m, time.Second*10)
}
return m
}
//通过脚本获取外挂磁盘
@@ -33,18 +78,15 @@ func (d *diskService) GetPlugInDisk() []string {
}
//格式化硬盘
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
}
//删除分区
@@ -54,46 +96,44 @@ func (d *diskService) DelPartition(path, num string) string {
return ""
}
//添加分区
func (d *diskService) AddPartition(path, num string, size uint64) string {
var maxSector uint64 = 0
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + path)
if len(chiList) == 0 {
d.log.Error("chiList length error")
}
for i := 0; i < len(chiList); i++ {
tempArr := strings.Split(chiList[i], ",")
tempSector, _ := strconv.ParseUint(tempArr[2], 10, 64)
if tempSector > maxSector {
maxSector = tempSector
}
}
r := command2.ExecResultStrArray("source ./shell/helper.sh ;AddPartition " + path + " " + num + " " + strconv.FormatUint(maxSector+1, 10) + " " + strconv.FormatUint(size+maxSector+1, 10))
fmt.Println(r)
//part
func (d *diskService) AddPartition(path string) string {
command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
return ""
}
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
}
//获取磁盘信息
func (d *diskService) LSBLK() []model.LSBLKModel {
//get disk details
func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
key := "system_lsblk"
var n []model.LSBLKModel
if result, ok := Cache.Get(key); ok && isUseCache {
res, ok := result.([]model.LSBLKModel)
if ok {
return res
}
}
str := command2.ExecLSBLK()
if str == nil {
d.log.Error("lsblk exec error")
d.log.Error("lsblk exec error,lsblk")
return nil
}
var m []model.LSBLKModel
@@ -102,15 +142,13 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
d.log.Error("json ummarshal error", err)
}
var n []model.LSBLKModel
var c []model.LSBLKModel
var fsused uint64
var health = true
for _, i := range m {
if i.Children != nil {
if i.Type != "loop" && !i.RO {
fsused = 0
for _, child := range i.Children {
if child.RM {
@@ -133,7 +171,9 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
i.Children = c
if fsused > 0 {
i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
fmt.Println(err)
if err != nil {
d.log.Fatal("diskservice_lsblk_fsused", err)
}
}
n = append(n, i)
health = true
@@ -141,15 +181,19 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
fsused = 0
}
}
if len(n) > 0 {
Cache.Add(key, n, time.Second*100)
}
return n
}
func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
str := command2.ExecLSBLKByPath(path)
if str == nil {
d.log.Error("lsblk exec error")
d.log.Error("lsblk exec error,str")
return model.LSBLKModel{}
}
var ml []model.LSBLKModel
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
if err != nil {
@@ -157,9 +201,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 {
@@ -170,7 +218,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], ",")
@@ -179,13 +226,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 {
//添加可以分区情况
@@ -196,17 +243,38 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
return m
}
//func GetDiskInfo(path string) *disk.UsageStat {
// diskInfo, _ := disk.Usage(path)
// diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
// diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
// return diskInfo
//}
//func (d *diskService) GetPlugInDisk() []string {
// return disk.Partitions(false)
//}
func NewDiskService(log loger2.OLog) DiskService {
return &diskService{log: log}
func (d *diskService) MountDisk(path, volume string) {
r := command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_mount " + path + " " + volume)
fmt.Print(r)
}
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)
}
func (d *diskService) DeleteMountPoint(path, mountPoint string) {
d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
}
func (d *diskService) GetSerialAll() []model2.SerialDisk {
var m []model2.SerialDisk
d.db.Find(&m)
return m
}
func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService {
return &diskService{log: log, db: db}
}

View File

@@ -7,7 +7,7 @@ import (
"encoding/binary"
json2 "encoding/json"
"fmt"
"regexp"
"reflect"
"syscall"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -20,6 +20,7 @@ import (
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/docker"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
@@ -51,7 +52,7 @@ type DockerService interface {
DockerListByImage(image, version string) (*types.Container, error)
DockerContainerInfo(name string) (*types.ContainerJSON, error)
DockerImageRemove(name string) error
DockerContainerRemove(name string) error
DockerContainerRemove(name string, update bool) error
DockerContainerStop(id string) error
DockerContainerUpdateName(name, id string) (err error)
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
@@ -60,6 +61,7 @@ type DockerService interface {
DockerNetworkModelList() []types.NetworkResource
DockerImageInfo(image string)
GetNetWorkNameByNetWorkID(id string) (string, error)
ContainerExecShell(container_id string) string
}
type dockerService struct {
@@ -67,15 +69,20 @@ type dockerService struct {
log loger2.OLog
}
func DockerPs() {
func (ds *dockerService) ContainerExecShell(container_id string) string {
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{
User: "1000:1000",
Cmd: []string{"echo -e \"hellow\nworld\" >> /a.txt"},
})
if err != nil {
os.Exit(5)
}
for _, container := range containers {
fmt.Printf("%s %s\n", container.ID[:10], container.Image)
err = cli.ContainerExecStart(context.Background(), exec.ID, types.ExecStartCheck{})
if err != nil {
fmt.Println("exec script error ", err)
}
return exec.ID
}
//创建默认网络
@@ -99,7 +106,7 @@ func (ds *dockerService) GetNetWorkNameByNetWorkID(id string) (string, error) {
defer cli.Close()
filter := filters.NewArgs()
filter.Add("id", id)
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{filter})
d, err := cli.NetworkList(context.Background(), types.NetworkListOptions{Filters: filter})
if err == nil && len(d) > 0 {
return d[0].Name, nil
}
@@ -150,7 +157,7 @@ func DockerEx() {
importResponse.Close()
println(string(response))
if string(response) != "response" {
fmt.Println("expected response to contain 'response', got %s", string(response))
fmt.Printf("expected response to contain 'response', got %s", string(response))
}
}
@@ -179,7 +186,6 @@ func (ds *dockerService) DockerImageInfo(image string) {
if err != nil {
fmt.Print(err)
}
}
func MsqlExec(container string) error {
@@ -258,6 +264,8 @@ func DockerLogs() {
if err != nil {
log.Fatal(err)
}
defer i.Close()
hdr := make([]byte, 8)
for {
_, err := i.Read(hdr)
@@ -276,7 +284,6 @@ func DockerLogs() {
_, err = i.Read(dat)
fmt.Fprint(w, string(dat))
}
defer i.Close()
}
//正式内容
@@ -325,11 +332,13 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
}
break
}
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG
m.State = 0
m.Speed = 70
m.Message = string(buf[:n])
MyService.Notify().UpdateLog(m)
if !reflect.DeepEqual(m, model2.AppNotify{}) {
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG
m.State = 0
m.Message = string(buf[:n])
MyService.Notify().UpdateLog(m)
}
}
return err
}
@@ -342,7 +351,7 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
//param udp 容器其他udp端口
func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) {
if len(net) == 0 {
net = "oasis"
net = "bridge"
}
cli, err := client2.NewClientWithOpts(client2.FromEnv)
@@ -356,18 +365,18 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
// if net != "host" {
// portMaps[nat.Port(fmt.Sprint(m.Port)+"/tcp")] = []nat.PortBinding{{HostIP: "", HostPort: m.PortMap}}
// }
port := ""
//port := ""
for _, portMap := range m.Ports {
if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
port = portMap.ContainerPort
}
// if portMap.CommendPort == m.PortMap && portMap.Protocol == "tcp" || portMap.Protocol == "both" {
// port = portMap.ContainerPort
// }
if portMap.Protocol == "tcp" {
tContainer, _ := strconv.Atoi(portMap.ContainerPort)
if tContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
if net != "host" {
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
}
}
} else if portMap.Protocol == "both" {
@@ -376,7 +385,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
if tContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/tcp")] = struct{}{}
if net != "host" {
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
portMaps[nat.Port(portMap.ContainerPort+"/tcp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
}
}
@@ -384,7 +393,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
if uContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
if net != "host" {
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
}
}
@@ -393,7 +402,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
if uContainer > 0 {
ports[nat.Port(portMap.ContainerPort+"/udp")] = struct{}{}
if net != "host" {
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: portMap.CommendPort}}
portMaps[nat.Port(portMap.ContainerPort+"/udp")] = []nat.PortBinding{{HostPort: portMap.CommendPort}}
}
}
}
@@ -402,6 +411,10 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
var envArr []string
for _, e := range m.Envs {
if strings.HasPrefix(e.Value, "$") {
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
continue
}
if len(e.Value) > 0 {
if e.Value == "port_map" {
envArr = append(envArr, e.Name+"="+m.PortMap)
@@ -420,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{}
@@ -429,26 +442,28 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
for _, v := range m.Volumes {
path := v.Path
if len(path) == 0 {
path = docker.GetDir(containerDbId, v.ContainerPath)
path = docker.GetDir(containerDbId, v.Path)
if len(path) == 0 {
continue
}
}
reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
result1 := reg1.FindAllStringSubmatch(path, -1)
if len(result1) == 0 {
err = file.IsNotExistMkDir(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
} else {
err = file.IsNotExistCreateFile(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
path = strings.ReplaceAll(path, "$AppID", containerDbId)
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
//result1 := reg1.FindAllStringSubmatch(path, -1)
//if len(result1) == 0 {
err = file.IsNotExistMkDir(path)
if err != nil {
ds.log.Error("mkdir error", err)
continue
}
//}
// else {
// err = file.IsNotExistCreateFile(path)
// if err != nil {
// ds.log.Error("mkdir error", err)
// continue
// }
// }
volumes = append(volumes, mount.Mount{
Type: mount.TypeBind,
@@ -464,25 +479,29 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
if len(m.Restart) > 0 {
rp.Name = m.Restart
}
//fmt.Print(port)
healthTest := []string{}
if len(port) > 0 {
healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
}
// healthTest := []string{}
// if len(port) > 0 {
// healthTest = []string{"CMD-SHELL", "curl -f http://localhost:" + port + m.Index + " || exit 1"}
// }
health := &container.HealthConfig{
Test: healthTest,
//Test: []string{},
StartPeriod: 0,
Retries: 1000,
// health := &container.HealthConfig{
// Test: healthTest,
// StartPeriod: 0,
// Retries: 1000,
// }
// fmt.Print(health)
if len(m.HostName) == 0 {
m.HostName = m.Label
}
config := &container.Config{
Image: imageName,
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin},
Env: envArr,
Healthcheck: health,
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
@@ -501,7 +520,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
}
//删除容器
func (ds *dockerService) DockerContainerRemove(name string) error {
func (ds *dockerService) DockerContainerRemove(name string, update bool) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return err
@@ -510,9 +529,11 @@ func (ds *dockerService) DockerContainerRemove(name string) error {
err = cli.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{})
//路径处理
path := docker.GetDir(name, "/config")
if !file.CheckNotExist(path) {
file.RMDir(path)
if !update {
path := docker.GetDir(name, "/config")
if !file.CheckNotExist(path) {
file.RMDir(path)
}
}
if err != nil {
@@ -738,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 {
@@ -773,7 +794,7 @@ func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
return networks
}
func NewDcokerService(log loger2.OLog) DockerService {
func NewDockerService(log loger2.OLog) DockerService {
return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`), log: log}
}
@@ -817,7 +838,6 @@ func Containerd() {
)
if err != nil {
fmt.Println("333")
fmt.Println(err)
}
defer container.Delete(ctx, containerd.WithSnapshotCleanup)
@@ -825,7 +845,6 @@ func Containerd() {
// create a task from the container
task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
if err != nil {
fmt.Println("444")
fmt.Println(err)
}
defer task.Delete(ctx)
@@ -838,7 +857,6 @@ func Containerd() {
// call start on the task to execute the redis server
if err = task.Start(ctx); err != nil {
fmt.Println("555")
fmt.Println(err)
}
@@ -848,7 +866,6 @@ func Containerd() {
// kill the process and get the exit status
if err = task.Kill(ctx, syscall.SIGTERM); err != nil {
fmt.Println("666")
fmt.Println(err)
}
@@ -857,7 +874,6 @@ func Containerd() {
status := <-exitStatusC
code, _, err := status.Result()
if err != nil {
fmt.Println("777")
fmt.Println(err)
}
fmt.Printf("redis-server exited with status: %d\n", code)

View File

@@ -3,7 +3,7 @@ package docker_base
import "github.com/IceWhaleTech/CasaOS/model"
//过滤mysql关键字
func MysqlFilter(c MysqlConfig, envs model.EnvArrey) model.EnvArrey {
func MysqlFilter(c MysqlConfig, envs model.EnvArray) model.EnvArray {
for i := 0; i < len(envs); i++ {
switch envs[i].Value {
case "$MYSQL_HOST":

View File

@@ -7,5 +7,3 @@ type MysqlConfig struct {
DataBasePassword string `json:"data_base_password"`
DataBaseDB string `json:"data_base_db"`
}

66
service/download.go Normal file
View File

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

85
service/file.go Normal file
View File

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

81
service/file_test.go Normal file
View File

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

64
service/friend.go Normal file
View File

@@ -0,0 +1,64 @@
package service
import (
"reflect"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type FriendService interface {
AddFriend(m model2.FriendModel)
DeleteFriend(m model2.FriendModel)
EditFriendMark(m model2.FriendModel)
EditFriendBlock(m model2.FriendModel)
GetFriendById(m model2.FriendModel) model2.FriendModel
GetFriendList() (list []model2.FriendModel)
UpdateAddFriendType(m model2.FriendModel)
UpdateOrCreate(m model2.FriendModel)
}
type friendService struct {
db *gorm.DB
}
func (p *friendService) AddFriend(m model2.FriendModel) {
p.db.Create(&m)
}
func (p *friendService) DeleteFriend(m model2.FriendModel) {
p.db.Where("token = ?", m.Token).Delete(&m)
}
func (p *friendService) EditFriendMark(m model2.FriendModel) {
p.db.Model(&m).Where("token = ?", m.Token).Update("mark", m.Mark)
}
func (p *friendService) EditFriendBlock(m model2.FriendModel) {
p.db.Model(&m).Where("token = ?", m.Token).Update("block", m.Block)
}
func (p *friendService) GetFriendById(m model2.FriendModel) model2.FriendModel {
p.db.Model(m).Where("token = ?", m.Token).First(&m)
return m
}
func (p *friendService) GetFriendList() (list []model2.FriendModel) {
p.db.Select("nick_name", "avatar", "profile", "token", "state", "mark", "block", "version").Find(&list)
return list
}
func (p *friendService) UpdateOrCreate(m model2.FriendModel) {
friend := model2.FriendModel{}
p.db.Where("token = ?", m.Token).First(&friend)
if reflect.DeepEqual(friend, model2.FriendModel{}) {
p.db.Create(&m)
} else {
p.db.Model(&m).Updates(m)
}
}
func (p *friendService) UpdateAddFriendType(m model2.FriendModel) {
p.db.Model(&m).Updates(m)
}
func NewFriendService(db *gorm.DB) FriendService {
return &friendService{db: db}
}

View File

@@ -26,14 +26,10 @@ type AppListDBModel struct {
PortMap string `json:"port_map"`
Label string `json:"label"`
EnableUPNP bool `json:"enable_upnp"`
//Envs model.EnvArrey `json:"envs" bson:"envs"`
//Ports model.PortArrey `json:"ports" bson:"ports"`
//Volumes model.PathArrey `json:"volumes" bson:"volumes"`
//Devices model.PathArrey `json:"devices" bson:"devices"`
Envs string `json:"envs"`
Ports string `json:"ports"`
Volumes string `json:"volumes"`
Devices string `json:"devices"`
Envs string `json:"envs"`
Ports string `json:"ports"`
Volumes string `json:"volumes"`
Devices string `json:"devices"`
//Envs []model.Env `json:"envs"`
//Ports []model.PortMap `gorm:"type:json" json:"ports"`
//Volumes []model.PathMap `gorm:"type:json" json:"volumes"`
@@ -44,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 {
@@ -61,4 +61,6 @@ type MyAppList struct {
UpTime string `json:"up_time"`
Slogan string `json:"slogan"`
Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
Image string `json:"image"`
Volumes string `json:"volumes"`
}

View File

@@ -2,11 +2,11 @@ package model
import "time"
func (p *DDNSUpdataDBModel) TableName() string {
func (p *DDNSUpdateDBModel) TableName() string {
return "o_ddns"
}
type DDNSUpdataDBModel struct {
type DDNSUpdateDBModel struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
Ipv4 string `gorm:"-"`
Ipv6 string `gorm:"-"`
@@ -17,8 +17,8 @@ type DDNSUpdataDBModel struct {
Secret string `json:"secret" form:"secret"`
UserName string `json:"user_name" form:"user_name"`
Password string `json:"password" form:"password"`
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
}
const DDNSLISTTABLENAME = "o_ddns"
@@ -39,9 +39,9 @@ type DDNSList struct {
//定时任务使用
type DDNSCoreList struct {
Id uint `gorm:"column:id;primary_key" json:"id"`
Id uint `gorm:"column:id;primary_key" json:"id"`
Domain string `json:"domain" form:"domain"`
Name string `json:"domain" form:"name"`
Name string `json:"name" form:"name"`
Type uint `json:"type"`
Key string `json:"key"`
Message string `json:"message"`

15
service/model/o_disk.go Normal file
View File

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

View File

@@ -0,0 +1,24 @@
package model
type PersonDownloadDBModel struct {
UUID string `gorm:"column:uuid;primary_key" json:"uuid"`
State int `json:"state"` //
Type int `json:"type"` //defult 1
Name string `json:"name"` //file name
Size int64 `json:"size"` //file size
BlockSize int `json:"block_size"` //Size of each file block
Length int `json:"length"` //slice length
Hash string `json:"hash"` //File hash value
Error string `json:"error"` //
From string `json:"from"` //Error message
Path string `json:"path"` //Full path to the file
Already int `json:"already" gorm:"-"` //Folder blocks that have been downloaded
LocalPath string `json:"local_path"` //The address where the file is saved after download
Duration int64 `json:"duration" gorm:"-"` //Length of time
Created int64 `gorm:"autoCreateTime" json:"created"`
Updated int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated"`
}
func (p *PersonDownloadDBModel) TableName() string {
return "o_person_download"
}

19
service/model/o_friend.go Normal file
View File

@@ -0,0 +1,19 @@
package model
type FriendModel struct {
State int `json:"state"` //Reserved
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
NickName string `json:"nick_name"`
Mark string `json:"mark"` //Remarks
Block bool `json:"block"` //Disable or not
Avatar string `json:"avatar"` //User avatar
Token string `gorm:"column:token;primary_key" json:"token"`
Profile string `json:"profile"` //Description
OnLine bool `json:"on_line" gorm:"-"`
Version int `json:"version"`
}
func (p *FriendModel) TableName() string {
return "o_friend"
}

View File

@@ -1,15 +1,16 @@
package model
type AppNotify struct {
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
ContainerId string `json:"container_id,omitempty"`
State int `json:"state"` //0:一直在变动的未读消息 1:未读 2:已读
Message string `json:"message"`
CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"`
UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"`
Speed int `json:"speed"`
Id string `gorm:"-" json:"id"`
Type int `json:"type"` // 1:显示即为已读 2:必须手动点掉 3:error
State int `json:"state"` //0:一直在变动的未读消息 1:未读 2:已读
Message string `json:"message"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Id string `json:"id"`
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"`
}
func (p *AppNotify) TableName() string {

View File

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

View File

@@ -1,89 +0,0 @@
package service
import (
json2 "encoding/json"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/tidwall/gjson"
"strconv"
)
type OasisService interface {
GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64)
GetServerCategoryList() []model.ServerCategoryList
GetTaskList(size int) []model2.TaskDBModel
}
type oasisService struct {
}
func (o *oasisService) GetTaskList(size int) []model2.TaskDBModel {
head := make(map[string]string)
t := make(chan string)
go func() {
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
t <- gjson.Get(str, "data").String()
}()
head["Authorization"] = <-t
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/task/list/"+strconv.Itoa(size), head)
list := []model2.TaskDBModel{}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
return list
}
func (o *oasisService) GetServerList(index, size, tp, categoryId, key string) ([]model.ServerAppList, int64) {
head := make(map[string]string)
t := make(chan string)
go func() {
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
t <- gjson.Get(str, "data").String()
}()
head["Authorization"] = <-t
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/list?index="+index+"&size="+size+"&type="+tp+"&category_id="+categoryId+"&key="+key, head)
list := []model.ServerAppList{}
count := gjson.Get(listS, "data.count").Int()
json2.Unmarshal([]byte(gjson.Get(listS, "data.items").String()), &list)
return list, count
}
func (o *oasisService) GetServerCategoryList() []model.ServerCategoryList {
head := make(map[string]string)
t := make(chan string)
go func() {
str := httper2.Get(config.ServerInfo.ServerApi+"/token", nil)
t <- gjson.Get(str, "data").String()
}()
head["Authorization"] = <-t
listS := httper2.Get(config.ServerInfo.ServerApi+"/v1/app/category", head)
list := []model.ServerCategoryList{}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
return list
}
func NewOasisService() OasisService {
return &oasisService{}
}

360
service/person.go Normal file
View File

@@ -0,0 +1,360 @@
package service
import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
"net"
"os"
"reflect"
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go"
"gorm.io/gorm"
)
type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error)
}
type personService struct {
db *gorm.DB
}
var IpInfo model.PersionModel
var CancelList map[string]string
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 NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db}
}
//=======================================================================================================================================================================
var StreamList map[string]quic.Stream
var ServiceMessage chan model.MessageModel
func UDPService() {
port := 0
if len(config.ServerInfo.UDPPort) > 0 {
port, _ = strconv.Atoi(config.ServerInfo.UDPPort)
if port != 0 && !port2.IsPortAvailable(port, "udp") {
port = 0
}
}
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: port}
var err error
UDPConn, err = net.ListenUDP("udp", srcAddr)
if err != nil {
fmt.Println(err)
}
listener, err := quic.Listen(UDPConn, quic_helper.GetGenerateTLSConfig(config.ServerInfo.Token), quic_helper.GetQUICConfig())
if err != nil {
fmt.Println(err)
}
defer listener.Close()
ctx := context.Background()
acceptFailures := 0
const maxAcceptFailures = 10
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
}
session, err := listener.Accept(ctx)
if err != nil {
fmt.Println("Listen (BEP/quic): Accepting connection:", err)
acceptFailures++
if acceptFailures > maxAcceptFailures {
// Return to restart the listener, because something
// seems permanently damaged.
fmt.Println(err)
return
}
// Slightly increased delay for each failure.
time.Sleep(time.Duration(acceptFailures) * time.Second)
continue
}
acceptFailures = 0
streamCtx, cancel := context.WithTimeout(ctx, time.Second*10)
stream, err := session.AcceptStream(streamCtx)
cancel()
if err != nil {
fmt.Println("failed to accept stream from %s: %v", session.RemoteAddr(), err)
_ = session.CloseWithError(1, err.Error())
continue
}
// prefixByte := make([]byte, 4)
// c1, err := io.ReadFull(stream, prefixByte)
// fmt.Println(c1, err)
// prefixLength, err := strconv.Atoi(string(prefixByte))
// if err != nil {
// fmt.Println(err)
// }
// messageByte := make([]byte, prefixLength)
// t, err := io.ReadFull(stream, messageByte)
// fmt.Println(t, err)
// m := model.MessageModel{}
// err = json.Unmarshal(messageByte, &m)
// if err != nil {
// fmt.Println(err)
// }
go ProcessingContent(stream)
}
}
//处理内容
func ProcessingContent(stream quic.Stream) {
for {
prefixByte := make([]byte, 6)
_, err := io.ReadFull(stream, prefixByte)
if err != nil {
fmt.Println(err)
return
}
prefixLength, err := strconv.Atoi(string(prefixByte))
if err != nil {
fmt.Println(err)
}
messageByte := make([]byte, prefixLength)
_, err = io.ReadFull(stream, messageByte)
if err != nil {
return
}
m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m)
if err != nil {
fmt.Println(err)
}
if m.Type == types.PERSONHELLO {
//nothing
continue
} else if m.Type == types.PERSONDIRECTORY {
friend := model2.FriendModel{}
friend.Token = m.From
var list []model.Path
rFriend := MyService.Friend().GetFriendById(friend)
if !reflect.DeepEqual(rFriend, model2.FriendModel{Token: m.From}) && !rFriend.Block {
if m.Data.(string) == "" || m.Data.(string) == "/" {
for _, v := range config.FileSettingInfo.ShareDir {
//tempList := MyService.ZiMa().GetDirPath(v)
temp := MyService.ZiMa().GetDirPathOne(v)
list = append(list, temp)
}
} else {
list = MyService.ZiMa().GetDirPath(m.Data.(string))
}
} else {
list = []model.Path{}
}
m.To = m.From
m.Data = list
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == types.PERSONDOWNLOAD {
SendFileData(stream, m.Data.(string), m.From, m.UUId)
break
} else if m.Type == types.PERSONADDFRIEND {
fmt.Println("有用户来请求加好友", m)
friend := model2.FriendModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &friend)
if err != nil {
fmt.Println(err)
continue
}
go MyService.Friend().UpdateOrCreate(friend)
mi := model2.FriendModel{}
mi.Avatar = config.UserInfo.Avatar
mi.Profile = config.UserInfo.Description
mi.NickName = config.UserInfo.NickName
m.To = m.From
m.Data = mi
m.Type = types.PERSONADDFRIEND
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == types.PERSONCONNECTION {
if len(m.Data.(string)) > 0 {
UDPAddressMap[m.From] = m.Data.(string)
} else {
delete(UDPAddressMap, m.From)
}
// mi := model2.FriendModel{}
// mi.Avatar = config.UserInfo.Avatar
// mi.Profile = config.UserInfo.Description
// mi.NickName = config.UserInfo.NickName
// mi.Token = config.ServerInfo.Token
user := MyService.Casa().GetUserInfoByShareId(m.From)
friend := model2.FriendModel{}
friend.Token = m.From
friend.Avatar = user.Avatar
friend.Block = false
friend.NickName = user.NickName
friend.Profile = user.Avatar
friend.Version = user.Version
MyService.Friend().AddFriend(friend)
msg := model.MessageModel{}
msg.Type = types.PERSONHELLO
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
Dial(msg, false)
break
} else if m.Type == types.PERSONCANCEL {
CancelList[m.UUId] = "cancel"
break
} else {
//不应有不做返回的数据
//ServiceMessage <- m
break
}
}
stream.Close()
}
//文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
summary := model.FileSummaryModel{}
msg := model.MessageModel{}
msg.Type = types.PERSONSUMMARY
msg.From = config.ServerInfo.Token
msg.To = to
msg.UUId = uuid
fStat, err := os.Stat(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
blockSize, length := file.GetBlockInfo(fStat.Size())
f, err := os.Open(filePath)
if err != nil {
summary.Message = err.Error()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
return err
}
//send file summary first
summary.BlockSize = blockSize
summary.Hash = file.GetHashByPath(filePath)
summary.Length = length
summary.Name = fStat.Name()
summary.Size = fStat.Size()
msg.Data = summary
summaryByte, _ := json.Marshal(msg)
summaryPrefixLength := file.PrefixLength(len(summaryByte))
summaryData := append(summaryPrefixLength, summaryByte...)
stream.Write(summaryData)
bufferedReader := bufio.NewReader(f)
buf := make([]byte, blockSize)
defer stream.Close()
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
n, err := bufferedReader.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
}
tran.Hash = file.GetHashByContent(buf[:n])
tran.Index = i
tran.Length = length
fileMsg := model.MessageModel{}
fileMsg.Type = types.PERSONDOWNLOAD
fileMsg.Data = tran
fileMsg.From = config.ServerInfo.Token
fileMsg.To = to
fileMsg.UUId = uuid
b, _ := json.Marshal(fileMsg)
prefixLength := file.PrefixLength(len(b))
dataLength := file.DataLength(len(buf[:n]))
data := append(append(append(prefixLength, b...), dataLength...), buf[:n]...)
if _, ok := CancelList[uuid]; ok {
delete(CancelList, uuid)
return nil
}
stream.Write(data)
}
return nil
}

View File

@@ -2,20 +2,27 @@ package service
import (
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gorilla/websocket"
"github.com/patrickmn/go-cache"
"gorm.io/gorm"
)
var Cache *cache.Cache
var MyService Repository
var WebSocketConns []*websocket.Conn
var SocketRun bool
type Repository interface {
App() AppService
DDNS() DDNSService
User() UserService
Docker() DockerService
//Redis() RedisService
ZeroTier() ZeroTierService
ZiMa() ZiMaService
OAPI() OasisService
Casa() CasaService
Disk() DiskService
Notify() NotifyServer
ShareDirectory() ShareDirService
@@ -24,19 +31,22 @@ type Repository interface {
System() SystemService
Shortcuts() ShortcutsService
Search() SearchService
Person() PersonService
Friend() FriendService
Download() DownloadService
}
func NewService(db *gorm.DB, log loger2.OLog) Repository {
return &store{
app: NewAppService(db, log),
ddns: NewDDNSService(db, log),
user: NewUserService(),
docker: NewDcokerService(log),
docker: NewDockerService(log),
//redis: NewRedisService(rp),
zerotier: NewZeroTierService(),
zima: NewZiMaService(),
oapi: NewOasisService(),
disk: NewDiskService(log),
casa: NewCasaService(),
disk: NewDiskService(log, db),
notify: NewNotifyService(db),
shareDirectory: NewShareDirService(db, log),
task: NewTaskService(db, log),
@@ -44,6 +54,9 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
system: NewSystemService(log),
shortcuts: NewShortcutsService(db),
search: NewSearchService(),
person: NewPersonService(db),
friend: NewFriendService(db),
download: NewDownloadService(db),
}
}
@@ -53,9 +66,8 @@ type store struct {
ddns DDNSService
user UserService
docker DockerService
zerotier ZeroTierService
zima ZiMaService
oapi OasisService
casa CasaService
disk DiskService
notify NotifyServer
shareDirectory ShareDirService
@@ -64,14 +76,26 @@ type store struct {
system SystemService
shortcuts ShortcutsService
search SearchService
person PersonService
friend FriendService
download DownloadService
}
func (c *store) Download() DownloadService {
return c.download
}
func (c *store) Friend() FriendService {
return c.friend
}
func (c *store) Rely() RelyService {
return c.rely
}
func (c *store) Shortcuts() ShortcutsService {
return c.shortcuts
}
func (c *store) Person() PersonService {
return c.person
}
func (c *store) System() SystemService {
return c.system
}
@@ -96,14 +120,11 @@ func (c *store) Docker() DockerService {
return c.docker
}
func (c *store) ZeroTier() ZeroTierService {
return c.zerotier
}
func (c *store) ZiMa() ZiMaService {
return c.zima
}
func (c *store) OAPI() OasisService {
return c.oapi
func (c *store) Casa() CasaService {
return c.casa
}
func (c *store) Disk() DiskService {

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