Compare commits

..

33 Commits

Author SHA1 Message Date
link
94d0efdb12 Dev (#285)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI

* Merge sockets to transfer data

* Conflict Resolution

* Update send data interval

* Update UI

* fixed bug

- Fix the problem of application opening failure on non-80 ports
- Modify port failure problem
- Modify environment variables disappearing problem
2022-06-13 20:43:19 +08:00
link
1e821d1c10 Dev (#277)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI

* Merge sockets to transfer data

* Conflict Resolution

* Update send data interval

* Update UI
2022-06-10 15:32:27 +08:00
link
2c80b53ee8 Dev (#276)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI

* Merge sockets to transfer data

* Conflict Resolution

* Update send data interval
2022-06-10 15:16:56 +08:00
link
c33af66c6e Dev (#275)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI

* Merge sockets to transfer data

* Conflict Resolution

* Update send data interval
2022-06-10 14:47:50 +08:00
link
9d47874ae3 Dev (#274)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI

* Merge sockets to transfer data

* Conflict Resolution
2022-06-10 13:33:53 +08:00
link
c7b7a30210 Dev (#264)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate

* Update UI
2022-06-08 19:44:05 +08:00
link
fde665cd4d Dev (#263)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate
2022-06-08 19:32:05 +08:00
link
eaf2341a2a Dev (#262)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI

* add cancel file operate
2022-06-08 19:31:01 +08:00
link
d4bed3e5c7 Dev (#261)
* fix bug

* updata UI

* 0.3.2

### Added

- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))

### Changed

- [Apps] Hide the display of non-essential environment variables in the application.
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
### Fixed

- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))

* Modify log help class

* Fix some bugs in 0.3.2

* Solve the operation file queue problem

* Exclude web folders

* update UI
2022-06-08 18:19:45 +08:00
Tiger Wang (王豫)
fcb2b3f5a5 Create config.yml 2022-06-02 20:30:00 -04:00
link
60349c941a Update demo.yml 2022-05-18 16:59:43 +08:00
link
11bc70a710 Update demo.yml 2022-05-18 16:58:33 +08:00
link
665766019f Update demo.yml 2022-05-18 16:39:59 +08:00
link
57cef9624c Dev (#199)
* fix bug

* updata UI
2022-05-17 16:31:23 +08:00
link
6bd41ad016 fix bug (#198) 2022-05-17 12:57:34 +08:00
link
05425d638f Update CHANGELOG.md 2022-05-16 20:45:38 +08:00
link
bd5a2e35d4 update ui (#192) 2022-05-16 15:57:54 +08:00
link
123e7e8758 Merge pull request #183 from IceWhaleTech/dev
Update UI
2022-05-13 20:27:53 +08:00
LinkLeong
1ec3e2e9fb Update UI 2022-05-13 20:27:26 +08:00
link
0719c3cc0c Merge pull request #182 from IceWhaleTech/dev
update api url
2022-05-13 19:11:28 +08:00
LinkLeong
0a4ceb7c4c update api url 2022-05-13 19:09:35 +08:00
link
655f59f00a Merge pull request #181 from IceWhaleTech/dev
Dev
2022-05-13 18:56:35 +08:00
LinkLeong
5289f471d6 Update .gitignore 2022-05-13 18:55:52 +08:00
LinkLeong
59597befb6 delete github.com 2022-05-13 18:55:34 +08:00
link
df2477a12f Merge pull request #179 from IceWhaleTech/dev
Dev
2022-05-13 18:21:44 +08:00
LinkLeong
b709abe682 Merge branch 'main' into dev 2022-05-13 18:15:56 +08:00
LinkLeong
d0f3dc806e New Feature
- [Apps] This is a feature that has been highly requested by the community. Import the original Docker application into CasaOS. Now it's easy to import with just a few clicks!
- [Apps] App list supports a custom sorting function! You can arrange apps in different orders by dragging the icons.
- [Apps] App custom installation supports Docker Compose configuration import in YAML format.
- [Files] Added thumbnail preview function for image files.
- [Connect] Multiple CasaConenct devices in the LAN will be transmitted through the LAN network.
- [System] Added a switch for auto-mounting USB disk devices.

🎈 Enhancement
- [System] Optimized the system update alert, you will see the new version update log from the next version.
- [Apps] Added live preview for icons in custom installed apps.
- [Apps] Optimized the input of WebUI.
- [Files] Completely updated the image preview, now it supports switching all images in the same folder, as well as dragging, zooming, rotating and resetting.
- [Widgets] Added color levels for CPU and RAM charts.
- [Conenct] Optimized the display of the right-click menu of the Connect friends list.

🎈 Changed
- [Files] Change the initial display directory to /DATA

🐞 Fixed
- [System] Fixed an issue with Raspberry Pi devices failing to boot using USB disks. (Achieved by disabling USB disk auto-mount)
- [Apps] Fixed the issue that some Docker CLI commands failed to import.
- [Apps] Fixed the issue that the app is not easily recognized in /DATA/AppData directory and docker command line after installation, it will be shown as the app name. (Newly installed apps only)
- [Apps] Fixed the issue that Pi-hole cannot be launched after installation in the app store.
- [Apps] Fixed the issue that apps cannot be updated with WatchTower.
- [Files] Fixed the issue that when there is an upload task, the task status is lost after closing Files.
2022-05-13 18:12:26 +08:00
LinkLeong
92d085acf9 update changelog 2022-05-05 13:46:55 +08:00
link
20dbae21c8 Update github.go 2022-04-24 17:53:57 +08:00
link
9258cb4b9e Merge pull request #151 from IceWhaleTech/dev
Update UI
2022-04-08 14:44:28 +08:00
link
d9794851f9 Update UI 2022-04-08 14:44:02 +08:00
link
1fcb530ff2 Merge pull request #149 from IceWhaleTech/dev
Update UI
2022-04-07 16:20:19 +08:00
link
364d411438 Update UI 2022-04-07 16:17:47 +08:00
335 changed files with 10263 additions and 24712 deletions

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions, Ideas, Discussions
url: https://github.com/IceWhaleTech/CasaOS/discussions
about: Ask questions, propose ideas, or discuss anything related to CasaOS

View File

@@ -33,7 +33,7 @@ jobs:
- name: Get old instance and snapshot name, create new instance name - name: Get old instance and snapshot name, create new instance name
run: | 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_SNAPSHOT_NAME=$(aws lightsail get-instance-snapshots | grep '"name": "CasaOS-Demo-Snapshot-1652856810' | 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 "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 echo "NEW_INSTANCE_NAME=CasaOS-Demo-$(date +%s)" >> $GITHUB_ENV
@@ -43,7 +43,7 @@ jobs:
--instance-snapshot-name ${{ env.OLD_INSTANCE_SNAPSHOT_NAME }} \ --instance-snapshot-name ${{ env.OLD_INSTANCE_SNAPSHOT_NAME }} \
--instance-names ${{ env.NEW_INSTANCE_NAME }} \ --instance-names ${{ env.NEW_INSTANCE_NAME }} \
--availability-zone us-west-2a \ --availability-zone us-west-2a \
--bundle-id large_2_0 --bundle-id medium_2_0
- name: Wait for new instance running - name: Wait for new instance running
run: | run: |

2
.gitignore vendored
View File

@@ -29,7 +29,9 @@ gen
/out/ /out/
/db/ /db/
/docs/ /docs/
/web/
/conf/conf.ini /conf/conf.ini
__debug_bin __debug_bin
main main
CasaOS CasaOS
github.com

399
CHANGELOG.md Normal file
View File

@@ -0,0 +1,399 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
### Changed
### Removed
### Security
### Fixed
## [0.3.2.1] - 2022-06-13
### Fixed
- Fix the problem of application opening failure on non-80 ports ([#283](https://github.com/IceWhaleTech/CasaOS/issues/283) [#280](https://github.com/IceWhaleTech/CasaOS/issues/280))
- Modify port failure problem ([#282](https://github.com/IceWhaleTech/CasaOS/issues/282))
- Modify environment variables disappearing problem([#284](https://github.com/IceWhaleTech/CasaOS/issues/284))
## [0.3.2] - 2022-06-10
### Added
- [Files] Files can now be selected multiple files and downloaded, deleted, moved, etc.
- [Apps] Support to modify the application opening address.([#204](https://github.com/IceWhaleTech/CasaOS/issues/204))
### Changed
- [Apps] Hide the display of non-essential environment variables in the application.([#196](https://github.com/IceWhaleTech/CasaOS/issues/196))
- [System] Network, disk, cpu, memory, etc. information is modified to be pushed via socket.
- [System] Optimize opening speed.([#214](https://github.com/IceWhaleTech/CasaOS/issues/214))
- [Language] Update language pack [zarevskaya](https://github.com/zarevskaya) [patrickhilker](https://github.com/patrickhilker)
- [System] Interface path adjustment
### Removed
- [Files] Remove the online preview function of PDF files
### Fixed
- [System] Fixed the problem that sync data cannot submit the device ID ([#68](https://github.com/IceWhaleTech/CasaOS/issues/68))
- [Files] Fixed the code editor center alignment display problem.([#210](https://github.com/IceWhaleTech/CasaOS/issues/210))
- [Files] Fixed the problem of wrong name when downloading files.([#240](https://github.com/IceWhaleTech/CasaOS/issues/240))
- [System] Fixed the network display as a negative number problem.([#224](https://github.com/IceWhaleTech/CasaOS/issues/224))
- [System] Fixed the problem of wireless network card traffic display.([#222](https://github.com/IceWhaleTech/CasaOS/issues/222))
## [0.3.1.1] - 2022-05-17
### Fixed
- Fix the data loss problem when importing local applications
## [0.3.1] - 2022-05-16
### Added
- CasaConnect and file add image thumbnail function
- Import of docker applications
- List support custom sorting function
- CasaConnect gives priority to LAN connections
- USB auto-mount switch (Raspberry Pi is off by default)
- Application custom installation supports Docker Compose configuration import in YAML format
- You will see the new version changelog from the next version
- Added live preview for icons in custom installed applications
### Changed
- Application data is no longer saved to the database
- Optimize app store speed issues
- Optimize the way WebUI is filled in
- Image preview has been completely upgraded and now supports switching between all images in the same folder, as well as dragging, zooming, rotating and resetting.
- Added color levels to the CPU and RAM charts
- Optimized the display of the Connect friends list right-click menu
- Change the initial display directory to /DATA
### Removed
- Historical Application Data
### Fixed
- Fixed the problem that some Docker CLI commands failed to import
- Fix the problem that the application is not easily recognized in /DATA/AppData directory and docker command line after installation, it will be shown as application name
- Fix Pi-hole installation failure
- Fixed the issue that the app could not be updated using WatchTower
- Fixed the problem that the task status was lost after closing Files when there was an upload task
## [0.3.0] - 2022-04-08
### Added
- Add CasaConnect function, now you can share private files peer-to-peer with your friends.
- Add a widget for network traffic monitoring.
- 12 new popular apps added to App Center
### Changed
- Updated the sidebar of Files.
- Updated the initial directory of Files to the Root directory.
- Armbian 22.02 armhf/arm64/amd64 platform tests passed [@igorpecovnik ](https://github.com/igorpecovnik)
- Elementary OS 6.1 Jólnir amd64 platform tests passed [@alvarosamudio ](https://github.com/alvarosamudio)
### Fixed
- Fix an issue in Files where the backspace button would trigger a return to the previous level of the directory when creating a folder.
- Fix the display problem of application list in CPU widget.
- Fix the problem that the ipv6 of the application cannot be opened
### Removed
- Interfaces related to "zerotier"
## [0.2.10] - 2022-03-10
### Added
- 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.
### Changed
- Optimized the rendering performance of the home page.
- Optimized the internationalization display of the time widget.
- Show the icon of the stopped application as gray.
- Unify the animation of the drop-down menu.
- Optimize the display of the application drop-down menu.
- Replaced the default font to optimize the display.
### Fixed
- Fix the problem of failed to create storage space
## [0.2.9] - 2022-02-18
### Added
- Add a simple notification function
### Changed
- Custom installation of new parameters(Capabilities,Hostname,Privileged)
- Update front-end translation [@SemVer](https://github.com/zarevskaya) [@koboldMaki](https://github.com/koboldMaki) [@sgastol](https://github.com/sgastol) [@delki8](https://github.com/delki8)
- Modify the default location and name of the usb mount
### Fixed
- Fix the problem of being indexed by search engines
- Fix some style display issues
- Solve hard drive can't be formatted, can't finish adding storage
## [0.2.8] - 2022-01-30
### Added
- Add USB disk device display
### Changed
- Update translation [@baptiste313](https://github.com/baptiste313) [@thueske](https://github.com/thueske)
- Compatible with more types of drives
### Fixed
- Fix the language initialization bug
- Fix the problem that the login page could not be displayed
- Fix missing translated content
## [0.2.7] - 2022.01.26
### Changed
- Apply multilingual support
### Security
- Fix an injectable execution bug
## [0.2.6] - 2022.01.26
### Added
- Add a bug report panel.
- App Store apps start supporting multiple languages
### Fixed
- Fix a disk that cannot be formatted under certain circumstances
## [0.2.5] - 2022.01.24
### Added
- Storage Manager
### Changed
- Update Disk widget
- Update language files [@ImOstrovskiy](https://github.com/ImOstrovskiy) [@baptiste313](https://github.com/baptiste313)
### Fixed
- File synchronization issues
- Fix the app store classification problem
## [0.2.4] - 2021.12.30
### Changed
- Brand new App Store
- Optimize request method
### Fixed
- Fix Sync panel width display error.
- Fix App panel width display error.
## [0.2.3] - 2021.12.11
### Added
- Add detailed CPU and memory statistics.
- Add the multi-language function and add Chinese translation.
- Add the function to modify the search engine.
- Add the function of modifying the WebUI port
### Changed
- Update update script
- Preprocessing usb automounting
### Fixed
- Volume path problem when customizing the installation of applications
- Fix Cpu and Ram usage display error
- Fix translation errors
- Fixed an error when importing and exporting appfile.
## [0.2.2] - 2021.12.02
### Changed
- UI adjustment
### Fixed
- Fix the problem of data display error when manually installing apps
- Fix some spelling problems
- Fix the bug of synchronization module
## [0.2.1] - 2021.11.25
### Fixed
- Fix Sync display error
- Fix Sync Downoad url error
- Fix Smart Block display error
- Fix widgets settings dispaly error
- Fix application installation path error
## [0.2.0] - 2021.11.25
### Added
- Add sync function
## [0.1.11] - 2021.11.10
### Changed
- Adaptation of cell phone terminals
- Optimize user experience
- Replaced the default background
- Optimized the display performance and fixed some bugs
### Fixed
- Resolve application installation path errors
## [0.1.10] - 2021.11.04
### Added
- Add application terminal
- Add application logs
- Add system logs
- Add App Store for installation
## [0.1.9] - 2021.11.01 [YANKED]
## [0.1.8] - 2021.10.27
### Added
- Add system terminal
- Add the ability to modify the user name and password
### Changed
- Experience optimization
- Improve single user management function
- Fixed Disk widget display error
- Fixed Username display error after change
- Adaptation for mobile access
## [0.1.7] - 2021.10.22
### Added
- Add user authentication module, Login page and initialization page.
### Fixed
- Fix the problem that the application could not start after the system restarted.
- Home storage space data display exception
- Script override causes application loss after installation
- Fix docker network error
## [0.1.6] - 2021.10.19
### Added
- Add app icon auto-fill via docker image name.
- Add a file selector for app install.
### Changed
- Modify import reminder.
- Optimize the application installation process
### Fixed
- Fixed an issue with the app were it would disappear when the app was modified.
- Fixed device selector default dir to /dev
## [0.1.5] - 2021.10.15
### Added
- Add CPU RAM Status with widget
- Add Disk Info with widget
- Realize automatic loading of widgets
### Changed
- Enhance the Docker cli import experience and automatically fill in the folders that need to be mounted
### Removed
- Remove Weather widget.
### Fixed
- AppFile upload does not pass verification
- The setting menu of the app is displayed abnormally when the browser window is too narrow
- The port is occupied and the program cannot start
- Fix display bugs when windows size less than 1024px
## [0.1.4] - 2021.09.30
### Added
- Import and export of application configuration files
- Automatic parsing of docker commands
### Changed
- Improve the program release process
- Application installation process UX/UI optimization
### Fixed
- Authentication failure during the operation, resulting in the need to re-login
## [0.1.3] - 2021.09.29 [YANKED]
## [0.1.2] - 2021.09.28
### Fixed
- Application modification and new creation failure issues
## [0.1.1] - 2021.09.27
## [0.1.0] - 2021.09.26
### Added
- Application Center

2
UI

Submodule UI updated: 74fa1f8920...62a6bd44d5

View File

@@ -16,32 +16,16 @@ RootPath = /casaOS
HttpPort = 8089 HttpPort = 8089
UDPPort = UDPPort =
RunMode = release RunMode = release
ServerApi = https://api.casaos.zimaboard.com ServerApi = https://api.casaos.io/casaos-api
Handshake = socket.casaos.io Handshake = socket.casaos.io
Token = Token =
USBAutoMount = true USBAutoMount =
[user]
UserName = admin
PWD = zimaboard
Email = user@gmail.com
Description = description
Initialized = false
Avatar =
NickName =
[redis]
Host = 127.0.0.1:6379
Password =
MaxIdle = 30
MaxActive = 30
IdleTimeout = 200
[system] [system]
ConfigStr = ConfigStr =
WidgetList = WidgetList =
Analyse =
[file] [file]
ShareDir = ShareDir =

13
go.mod
View File

@@ -3,16 +3,22 @@ module github.com/IceWhaleTech/CasaOS
go 1.16 go 1.16
require ( require (
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
github.com/Microsoft/go-winio v0.5.0 // indirect github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/Microsoft/hcsshim v0.8.22 // indirect 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/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/ambelovsky/go-structs v1.1.0 // indirect
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 // indirect
github.com/bits-and-blooms/bitset v1.2.1 // indirect github.com/bits-and-blooms/bitset v1.2.1 // indirect
github.com/containerd/containerd v1.5.7 github.com/containerd/containerd v1.5.7
github.com/containerd/continuity v0.2.0 // indirect github.com/containerd/continuity v0.2.0 // indirect
github.com/disintegration/imaging v1.6.2
github.com/docker/distribution v2.8.0+incompatible // indirect github.com/docker/distribution v2.8.0+incompatible // indirect
github.com/docker/docker v20.10.7+incompatible github.com/docker/docker v20.10.7+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b github.com/forease/gotld v0.0.0-20190808124948-c50ff635576b
github.com/gin-contrib/gzip v0.0.2 github.com/gin-contrib/gzip v0.0.2
github.com/gin-gonic/gin v1.7.2 github.com/gin-gonic/gin v1.7.2
@@ -26,6 +32,7 @@ require (
github.com/gomodule/redigo v1.8.5 github.com/gomodule/redigo v1.8.5
github.com/google/go-github/v36 v36.0.0 github.com/google/go-github/v36 v36.0.0
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/googollee/go-socket.io v1.6.2
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/jinzhu/copier v0.3.2 github.com/jinzhu/copier v0.3.2
@@ -36,6 +43,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.11 // indirect github.com/mattn/go-sqlite3 v1.14.11 // indirect
github.com/mholt/archiver/v3 v3.5.1
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
@@ -50,13 +58,13 @@ require (
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/smartystreets/assertions v1.2.0 // indirect github.com/smartystreets/assertions v1.2.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/spf13/afero v1.2.2
github.com/swaggo/gin-swagger v1.3.0 github.com/swaggo/gin-swagger v1.3.0
github.com/swaggo/swag v1.7.3 github.com/swaggo/swag v1.7.3
github.com/tidwall/gjson v1.10.2 github.com/tidwall/gjson v1.10.2
github.com/tklauser/go-sysconf v0.3.6 // indirect github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/ugorji/go v1.2.6 // indirect github.com/ugorji/go v1.2.6 // indirect
go.opencensus.io v0.23.0 // indirect go.opencensus.io v0.23.0 // indirect
go.uber.org/zap v1.10.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/mod v0.5.0 // indirect golang.org/x/mod v0.5.0 // indirect
golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect
@@ -70,6 +78,7 @@ require (
google.golang.org/grpc v1.41.0 // indirect google.golang.org/grpc v1.41.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/driver/sqlite v1.2.6 gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.22.5 gorm.io/gorm v1.22.5

72
go.sum
View File

@@ -54,8 +54,11 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d h1:62lEBImTxZ83pgzywgDNIrPPuQ+j4ep9QjqrWBn1hrU=
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d/go.mod h1:lW9x+yEjqKdPbE3+cf2fGPJXCw/hChX3Omi9QHTLFsQ=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
@@ -82,8 +85,6 @@ github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/goquery v1.7.0 h1:O5SP3b9JWqMSVMG69zMfj577zwkSNpxrFf7ybS74eiw=
github.com/PuerkitoBio/goquery v1.7.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -99,8 +100,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= 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/ambelovsky/go-structs v1.1.0 h1:LXj4/mHnYw0qhXQhOo96+ULGQ88H8qMcZd5SHef8boY=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/ambelovsky/go-structs v1.1.0/go.mod h1:zN3RBXQvxgjjq/Q/WZS7p5AEK+qC9mNg7ycnvoQ63Ak=
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109 h1:Tp8GVfUOEmJftBqi4+/aXTwJzm24POo6wIHeuTqaT+Y=
github.com/ambelovsky/gosf v0.0.0-20201109201340-237aea4d6109/go.mod h1:MUREokfMKREm1fOm2babarrkYdk/dGHWY+ITC3qHHPQ=
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19 h1:suVCm9PiIhz7ftTbWQNe7u2YjVfr8AEuUiNWKWApdMM=
github.com/ambelovsky/gosf-socketio v0.0.0-20201109193639-add9d32f8b19/go.mod h1:o0+8DH+3X+FEOgSdNud0+8jJAsjtR9H3hF+O10Zcj/c=
github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -269,6 +276,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 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/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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= 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 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-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -289,6 +298,21 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b h1:NgNuLvW/gAFKU30ULWW0gtkCt56JfB7FrZ2zyo0wT8I=
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
@@ -330,6 +354,9 @@ 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/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= 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-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -386,6 +413,7 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
@@ -400,6 +428,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -435,6 +466,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 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/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -481,6 +515,8 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googollee/go-socket.io v1.6.2 h1:olKLLHJtHz1IkL/OrTyNriZZvVQYEORNkJAqsOwPask=
github.com/googollee/go-socket.io v1.6.2/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
@@ -516,6 +552,7 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 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/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/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.3.2 h1:QdBOCbaouLDYaIPFfi1bKv5F5tPpeTwXe4sD0jqtz5w= 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/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 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@@ -544,10 +581,15 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
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.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.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/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -600,10 +642,13 @@ github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsF
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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.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/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= 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/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/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= 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 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
@@ -632,6 +677,8 @@ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= 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/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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 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 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -692,6 +739,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 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.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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-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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -794,7 +843,6 @@ github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:Udh
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= 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/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.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.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/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.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
@@ -856,6 +904,9 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 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.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.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@@ -874,6 +925,8 @@ github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -900,8 +953,11 @@ go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/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/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= 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/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
@@ -935,6 +991,8 @@ 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/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-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/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/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-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-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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -957,7 +1015,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -991,6 +1048,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 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-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@@ -1329,6 +1387,7 @@ gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/R
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 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.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
@@ -1342,6 +1401,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

75
main.go
View File

@@ -4,13 +4,13 @@ import (
"flag" "flag"
"fmt" "fmt"
"net/http" "net/http"
"runtime"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/cache" "github.com/IceWhaleTech/CasaOS/pkg/cache"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/sqlite" "github.com/IceWhaleTech/CasaOS/pkg/sqlite"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/route" "github.com/IceWhaleTech/CasaOS/route"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
@@ -21,47 +21,35 @@ import (
var sqliteDB *gorm.DB var sqliteDB *gorm.DB
var configFlag = flag.String("c", "", "config address") var configFlag = flag.String("c", "", "config address")
var dbFlag = flag.String("db", "", "db path")
var showUserInfo = flag.Bool("show-user-info", false, "show user info") var showUserInfo = flag.Bool("show-user-info", false, "show user info")
func init() { func init() {
flag.Parse() flag.Parse()
config.InitSetup(*configFlag) config.InitSetup(*configFlag)
config.UpdateSetup() config.UpdateSetup()
loger2.LogSetup() loger.LogInit()
sysType := runtime.GOOS if len(*dbFlag) == 0 {
if sysType == "windows" { *dbFlag = config.AppInfo.ProjectPath + "/db"
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" { sqliteDB = sqlite.GetDb(*dbFlag)
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), //gredis.GetRedisConn(config.RedisInfo),
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger()) service.MyService = service.NewService(sqliteDB)
service.Cache = cache.Init() service.Cache = cache.Init()
go service.UDPService() go service.UDPService()
fmt.Println("token", service.GetToken()) fmt.Println("t", service.GetToken())
service.UDPAddressMap = make(map[string]string) service.UDPAddressMap = make(map[string]string)
//go service.SocketConnect() //go service.SocketConnect()
service.CancelList = make(map[string]string) service.CancelList = make(map[string]string)
service.InternalInspection = make(map[string][]string)
service.NewVersionApp = make(map[string]string)
route.InitFunction() route.InitFunction()
go service.SendIPToServer() go service.SendIPToServer()
go service.LoopFriend() // go service.LoopFriend()
// go service.MyService.App().CheckNewImage()
} }
@@ -77,12 +65,22 @@ func init() {
// @name Authorization // @name Authorization
// @BasePath /v1 // @BasePath /v1
func main() { func main() {
service.NotifyMsg = make(chan notify.Message, 10)
if *showUserInfo { if *showUserInfo {
fmt.Println("CasaOS User Info") fmt.Println("CasaOS User Info")
fmt.Println("UserName:" + config.UserInfo.UserName) fmt.Println("UserName:" + config.UserInfo.UserName)
fmt.Println("Password:" + config.UserInfo.PWD) fmt.Println("Password:" + config.UserInfo.PWD)
return return
} }
go route.SocketInit(service.NotifyMsg)
go func() {
for i := 0; i < 1000; i++ {
time.Sleep(2 * time.Second)
//service.NotifyMsg <- strconv.Itoa(i)
}
}()
//model.Setup() //model.Setup()
//gredis.Setup() //gredis.Setup()
r := route.InitRouter() r := route.InitRouter()
@@ -97,20 +95,24 @@ func main() {
service.SendIPToServer() service.SendIPToServer()
service.LoopFriend() service.LoopFriend()
//service.MyService.App().CheckNewImage()
})
if err != nil {
fmt.Println(err)
}
err = cron2.AddFunc("0/5 * * * * *", func() {
if service.ClientCount > 0 {
// route.SendNetINfoBySocket()
// route.SendCPUBySocket()
// route.SendMemBySocket()
// route.SendDiskBySocket()
// route.SendUSBBySocket()
route.SendAllHardwareStatusBySocket()
}
}) })
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
// err = cron2.AddFunc("0/1 * * * * *", func() {
// //service.SendIPToServer()
// //service.LoopNet()
// })
// if err != nil {
// fmt.Println(err)
// }
cron2.Start() cron2.Start()
defer cron2.Stop() defer cron2.Stop()
s := &http.Server{ s := &http.Server{
@@ -123,4 +125,7 @@ func main() {
s.ListenAndServe() s.ListenAndServe()
// if err := r.Run(fmt.Sprintf(":%v", config.ServerInfo.HttpPort)); err != nil {
// fmt.Println("failed run app: ", err)
// }
} }

View File

@@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-10-08 10:29:08
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-25 19:17:45
* @FilePath: /CasaOS/middleware/gin.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package middleware package middleware
import ( import (
@@ -10,20 +20,16 @@ import (
func Cors() gin.HandlerFunc { func Cors() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
method := c.Request.Method method := c.Request.Method
//origin := c.Request.Header.Get("Origin") //请求头部
//if origin != "" {
//接收客户端发送的origin (重要!)
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Origin", "*")
//服务器支持的所有跨域请求的方法
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段 //允许跨域设置可以返回其他子段,可以自定义字段
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language") c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,Language")
// 允许浏览器(客户端)可以解析的头部 (重要) // 允许浏览器(客户端)可以解析的头部 (重要)
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers") c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//c.Writer.Header().Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Content-Length, X-CSRF-Token, Token, session, Origin, Host, Connection, Accept-Encoding, Accept-Language, X-Requested-With")
//设置缓存时间 //设置缓存时间
c.Header("Access-Control-Max-Age", "172800") c.Header("Access-Control-Max-Age", "172800")
//允许客户端传递校验信息比如 cookie (重要)
c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Allow-Credentials", "true")
c.Set("content-type", "application/json") c.Set("content-type", "application/json")
//} //}

View File

@@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-03-18 11:40:55
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-13 14:48:01
* @FilePath: /CasaOS/model/app-analyse.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model package model
type AppAnalyse struct { type AppAnalyse struct {
@@ -5,6 +15,7 @@ type AppAnalyse struct {
Type string `json:"type"` Type string `json:"type"`
UUId string `json:"uuid"` UUId string `json:"uuid"`
Language string `json:"language"` Language string `json:"language"`
Version string `json:"version"`
} }
type ConnectionStatus struct { type ConnectionStatus struct {

View File

@@ -1,5 +1,18 @@
/*
* @Author: link a624669980@163.com
* @Date: 2022-05-16 17:37:08
* @LastEditors: link a624669980@163.com
* @LastEditTime: 2022-06-07 17:12:30
* @FilePath: \CasaOS\model\category.go
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
package model package model
// type ServerCategoryList struct {
// Version string `json:"version"`
// Item []CategoryList `json:"item"`
// }
type ServerCategoryList struct { type ServerCategoryList struct {
Id uint `gorm:"column:id;primary_key" json:"id"` Id uint `gorm:"column:id;primary_key" json:"id"`
//CreatedAt time.Time `json:"created_at"` //CreatedAt time.Time `json:"created_at"`

33
model/file.go Normal file
View File

@@ -0,0 +1,33 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-20 16:27:12
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-09 18:18:46
* @FilePath: /CasaOS/model/file.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model
type FileOperate struct {
Type string `json:"type" binding:"required"`
Item []FileItem `json:"item" binding:"required"`
TotalSize int64 `json:"total_size"`
ProcessedSize int64 `json:"processed_size"`
To string `json:"to" binding:"required"`
Style string `json:"style"`
Finished bool `json:"finished"`
}
type FileItem struct {
From string `json:"from" binding:"required"`
Finished bool `json:"finished"`
Size int64 `json:"size"`
ProcessedSize int64 `json:"processed_size"`
}
type FileUpdate struct {
FilePath string `json:"path" binding:"required"`
FileContent string `json:"content" binding:"required"`
}

View File

@@ -104,6 +104,7 @@ func (p *PathArray) Scan(input interface{}) error {
//} //}
type CustomizationPostData struct { type CustomizationPostData struct {
CustomId string `json:"custom_id"`
Origin string `json:"origin"` Origin string `json:"origin"`
NetworkModel string `json:"network_model"` NetworkModel string `json:"network_model"`
Index string `json:"index"` Index string `json:"index"`
@@ -126,4 +127,6 @@ type CustomizationPostData struct {
Privileged bool `json:"privileged"` Privileged bool `json:"privileged"`
CapAdd []string `json:"cap_add"` CapAdd []string `json:"cap_add"`
Cmd []string `json:"cmd"` Cmd []string `json:"cmd"`
Protocol string `json:"protocol"`
Host string `json:"host"`
} }

View File

@@ -0,0 +1,21 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-27 15:01:58
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-31 14:51:21
* @FilePath: /CasaOS/model/notify/application.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
type Application struct {
Name string `json:"name"`
State string `json:"state"`
Type string `json:"type"`
Icon string `json:"icon"`
Message string `json:"message"`
Finished bool `json:"finished"`
Success bool `json:"success"`
}

22
model/notify/file.go Normal file
View File

@@ -0,0 +1,22 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-26 14:21:57
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-02 11:14:15
* @FilePath: /CasaOS/model/notify/file.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
type File struct {
Finished bool `json:"finished"`
ProcessedSize int64 `json:"processed_size"`
ProcessingPath string `json:"processing_path"`
Status string `json:"status"`
TotalSize int64 `json:"total_size"`
Id string `json:"id"`
To string `json:"to"`
Type string `json:"type"`
}

20
model/notify/message.go Normal file
View File

@@ -0,0 +1,20 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-26 14:39:22
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-26 19:08:52
* @FilePath: /CasaOS/model/notify/message.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
import (
f "github.com/ambelovsky/gosf"
)
type Message struct {
Path string `json:"path"`
Msg f.Message `json:"msg"`
}

16
model/notify/person.go Normal file
View File

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

18
model/notify/result.go Normal file
View File

@@ -0,0 +1,18 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-26 14:21:11
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-27 11:15:59
* @FilePath: /CasaOS/model/notify/result.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package notify
// Notify struct for Notify
type NotifyModel struct {
Data interface{} `json:"data"`
State string `json:"state"`
}

1
model/receive/app.go Normal file
View File

@@ -0,0 +1 @@
package receive

View File

@@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-30 16:43:59
* @FilePath: /CasaOS/model/sys_common.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model package model
import "time" import "time"
@@ -18,6 +28,7 @@ type UserModel struct {
Initialized bool Initialized bool
Avatar string Avatar string
NickName string NickName string
Public string
} }
//服务配置 //服务配置
@@ -30,6 +41,7 @@ type ServerModel struct {
Token string Token string
UDPPort string UDPPort string
USBAutoMount string USBAutoMount string
SocketPort string
} }
//服务配置 //服务配置

View File

@@ -4,7 +4,7 @@ import "time"
type Version struct { type Version struct {
Id uint `gorm:"column:id;primary_key" json:"id"` Id uint `gorm:"column:id;primary_key" json:"id"`
ChangLog string `json:"chang_log"` ChangeLog string `json:"change_log"`
Version string `json:"version"` Version string `json:"version"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`

View File

@@ -1,9 +0,0 @@
package model
type ZeroTierUpData struct {
Config ZeroTierConfig `json:"config"`
}
type ZeroTierConfig struct {
Private bool `json:"private"`
}

View File

@@ -10,4 +10,5 @@ type Path struct {
Size int64 `json:"size"` //File Size Size int64 `json:"size"` //File Size
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Label string `json:"label,omitempty"` Label string `json:"label,omitempty"`
Write bool `json:"write"`
} }

View File

@@ -22,8 +22,7 @@ var UserInfo = &model.UserModel{}
//用户相关 //用户相关
var AppInfo = &model.APPModel{} var AppInfo = &model.APPModel{}
//redis相关配置 //var RedisInfo = &model.RedisModel{}
var RedisInfo = &model.RedisModel{}
//server相关 //server相关
var ServerInfo = &model.ServerModel{} var ServerInfo = &model.ServerModel{}
@@ -53,7 +52,7 @@ func InitSetup(config string) {
mapTo("user", UserInfo) mapTo("user", UserInfo)
mapTo("app", AppInfo) mapTo("app", AppInfo)
mapTo("redis", RedisInfo) //mapTo("redis", RedisInfo)
mapTo("server", ServerInfo) mapTo("server", ServerInfo)
mapTo("system", SystemConfigInfo) mapTo("system", SystemConfigInfo)
mapTo("file", FileSettingInfo) mapTo("file", FileSettingInfo)

View File

@@ -9,7 +9,7 @@ import (
func GetGithubClient() *github.Client { func GetGithubClient() *github.Client {
ctx := context.Background() ctx := context.Background()
ts := oauth2.StaticTokenSource( ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "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"}, &oauth2.Token{AccessToken: ""},
) )
tc := oauth2.NewClient(ctx, ts) tc := oauth2.NewClient(ctx, ts)
client := github.NewClient(tc) client := github.NewClient(tc)

View File

@@ -12,15 +12,15 @@ import (
var gdb *gorm.DB var gdb *gorm.DB
func GetDb(projectPath string) *gorm.DB { func GetDb(dbPath string) *gorm.DB {
if gdb != nil { if gdb != nil {
return gdb return gdb
} }
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情 // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
//dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName) //dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
//db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{}) //db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
file.IsNotExistMkDir(projectPath + "/db/") file.IsNotExistMkDir(dbPath)
db, err := gorm.Open(sqlite.Open(projectPath+"/db/casaOS.db"), &gorm.Config{}) db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
c, _ := db.DB() c, _ := db.DB()
c.SetMaxIdleConns(10) c.SetMaxIdleConns(10)
c.SetMaxOpenConns(100) c.SetMaxOpenConns(100)
@@ -31,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
return nil return nil
} }
gdb = db gdb = db
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{}) err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersonDownloadDBModel{}, model2.FriendModel{}, model2.PersonDownRecordDBModel{}, model2.ApplicationModel{})
if err != nil { if err != nil {
fmt.Println("检查和创建数据库出错", err) fmt.Println("检查和创建数据库出错", err)
} }

View File

@@ -2,9 +2,11 @@ package file
import ( import (
"bufio" "bufio"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"mime/multipart" "mime/multipart"
"os" "os"
"path" "path"
@@ -12,6 +14,8 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/mholt/archiver/v3"
) )
// GetSize get the file size // GetSize get the file size
@@ -182,7 +186,7 @@ func ReadFullFile(path string) []byte {
} }
// File copies a single file from src to dst // File copies a single file from src to dst
func CopyFile(src, dst string) error { func CopyFile(src, dst, style string) error {
var err error var err error
var srcfd *os.File var srcfd *os.File
var dstfd *os.File var dstfd *os.File
@@ -193,20 +197,13 @@ func CopyFile(src, dst string) error {
if !strings.HasSuffix(dst, "/") { if !strings.HasSuffix(dst, "/") {
dst += "/" dst += "/"
} }
dstPath := dst
dst += lastPath dst += lastPath
for i := 0; Exists(dst); i++ { if Exists(dst) {
name := strings.Split(lastPath, ".") if style == "skip" {
nameIndex := 0 return nil
if len(name) > 2 { } else {
nameIndex = len(name) - 2 os.Remove(dst)
} }
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 { if srcfd, err = os.Open(src); err != nil {
@@ -240,7 +237,7 @@ func GetNoDuplicateFileName(fullPath string) string {
} }
// Dir copies a whole directory recursively // Dir copies a whole directory recursively
func CopyDir(src string, dst string) error { func CopyDir(src string, dst string, style string) error {
var err error var err error
var fds []os.FileInfo var fds []os.FileInfo
var srcinfo os.FileInfo var srcinfo os.FileInfo
@@ -249,16 +246,23 @@ func CopyDir(src string, dst string) error {
return err return err
} }
if !srcinfo.IsDir() { if !srcinfo.IsDir() {
if err = CopyFile(src, dst); err != nil { if err = CopyFile(src, dst, style); err != nil {
fmt.Println(err) fmt.Println(err)
} }
return nil return nil
} }
dstPath := dst //dstPath := dst
lastPath := src[strings.LastIndex(src, "/")+1:] lastPath := src[strings.LastIndex(src, "/")+1:]
dst += "/" + lastPath dst += "/" + lastPath
for i := 0; Exists(dst); i++ { // for i := 0; Exists(dst); i++ {
dst = dstPath + "/" + lastPath + strconv.Itoa(i+1) // dst = dstPath + "/" + lastPath + strconv.Itoa(i+1)
// }
if Exists(dst) {
if style == "skip" {
return nil
} else {
os.Remove(dst)
}
} }
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil { if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err return err
@@ -271,11 +275,11 @@ func CopyDir(src string, dst string) error {
dstfp := dst //path.Join(dst, fd.Name()) dstfp := dst //path.Join(dst, fd.Name())
if fd.IsDir() { if fd.IsDir() {
if err = CopyDir(srcfp, dstfp); err != nil { if err = CopyDir(srcfp, dstfp, style); err != nil {
fmt.Println(err) fmt.Println(err)
} }
} else { } else {
if err = CopyFile(srcfp, dstfp); err != nil { if err = CopyFile(srcfp, dstfp, style); err != nil {
fmt.Println(err) fmt.Println(err)
} }
} }
@@ -283,7 +287,6 @@ func CopyDir(src string, dst string) error {
return nil return nil
} }
//文件写入临时目录
func WriteToPath(data []byte, path, name string) error { func WriteToPath(data []byte, path, name string) error {
fullPath := path fullPath := path
if strings.HasSuffix(path, "/") { if strings.HasSuffix(path, "/") {
@@ -333,3 +336,149 @@ func SpliceFiles(dir, path string, length int, startPoint int) error {
return nil return nil
} }
func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
switch t {
case "zip", "":
return ".zip", archiver.NewZip(), nil
case "tar":
return ".tar", archiver.NewTar(), nil
case "targz":
return ".tar.gz", archiver.NewTarGz(), nil
case "tarbz2":
return ".tar.bz2", archiver.NewTarBz2(), nil
case "tarxz":
return ".tar.xz", archiver.NewTarXz(), nil
case "tarlz4":
return ".tar.lz4", archiver.NewTarLz4(), nil
case "tarsz":
return ".tar.sz", archiver.NewTarSz(), nil
default:
return "", nil, errors.New("format not implemented")
}
}
func AddFile(ar archiver.Writer, path, commonPath string) error {
info, err := os.Stat(path)
if err != nil {
return err
}
if !info.IsDir() && !info.Mode().IsRegular() {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if path != commonPath {
filename := info.Name()
err = ar.Write(archiver.File{
FileInfo: archiver.FileInfo{
FileInfo: info,
CustomName: filename,
},
ReadCloser: file,
})
if err != nil {
return err
}
}
if info.IsDir() {
names, err := file.Readdirnames(0)
if err != nil {
return err
}
for _, name := range names {
err = AddFile(ar, filepath.Join(path, name), commonPath)
if err != nil {
log.Printf("Failed to archive %v", err)
}
}
}
return nil
}
func CommonPrefix(sep byte, paths ...string) string {
// Handle special cases.
switch len(paths) {
case 0:
return ""
case 1:
return path.Clean(paths[0])
}
// Note, we treat string as []byte, not []rune as is often
// done in Go. (And sep as byte, not rune). This is because
// most/all supported OS' treat paths as string of non-zero
// bytes. A filename may be displayed as a sequence of Unicode
// runes (typically encoded as UTF-8) but paths are
// not required to be valid UTF-8 or in any normalized form
// (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
// file names.
c := []byte(path.Clean(paths[0]))
// We add a trailing sep to handle the case where the
// common prefix directory is included in the path list
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
// path.Clean will have cleaned off trailing / separators with
// the exception of the root directory, "/" (in which case we
// make it "//", but this will get fixed up to "/" bellow).
c = append(c, sep)
// Ignore the first path since it's already in c
for _, v := range paths[1:] {
// Clean up each path before testing it
v = path.Clean(v) + string(sep)
// Find the first non-common byte and truncate c
if len(v) < len(c) {
c = c[:len(v)]
}
for i := 0; i < len(c); i++ {
if v[i] != c[i] {
c = c[:i]
break
}
}
}
// Remove trailing non-separator characters and the final separator
for i := len(c) - 1; i >= 0; i-- {
if c[i] == sep {
c = c[:i]
break
}
}
return string(c)
}
func GetFileOrDirSize(path string) (int64, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return 0, err
}
if fileInfo.IsDir() {
return DirSizeB(path + "/")
}
return fileInfo.Size(), nil
}
//getFileSize get file size by path(B)
func DirSizeB(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if !info.IsDir() {
size += info.Size()
}
return err
})
return size, err
}

84
pkg/utils/file/image.go Normal file
View File

@@ -0,0 +1,84 @@
package file
import (
"bytes"
"fmt"
"io"
"os"
"github.com/disintegration/imaging"
"github.com/dsoprea/go-exif/v3"
exifcommon "github.com/dsoprea/go-exif/v3/common"
)
func GetImage(path string, width, height int) ([]byte, error) {
if thumbnail, err := GetThumbnailByOwnerPhotos(path); err == nil {
return thumbnail, nil
} else {
return GetThumbnailByWebPhoto(path, width, height)
}
}
func GetThumbnailByOwnerPhotos(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
buff := &bytes.Buffer{}
defer file.Close()
offset := 0
offsets := []int{12, 30}
head := make([]byte, 0xffff)
r := io.TeeReader(file, buff)
_, err = r.Read(head)
if err != nil {
return nil, err
}
for _, offset = range offsets {
if _, err = exif.ParseExifHeader(head[offset:]); err == nil {
break
}
}
if err != nil {
return nil, err
}
im, err := exifcommon.NewIfdMappingWithStandard()
if err != nil {
return nil, err
}
_, index, err := exif.Collect(im, exif.NewTagIndex(), head[offset:])
if err != nil {
return nil, err
}
ifd := index.RootIfd.NextIfd()
if ifd == nil {
return nil, exif.ErrNoThumbnail
}
thumbnail, err := ifd.Thumbnail()
if err != nil {
return nil, err
}
return thumbnail, nil
}
func GetThumbnailByWebPhoto(path string, width, height int) ([]byte, error) {
src, err := imaging.Open(path)
if err != nil {
fmt.Println(err)
return nil, err
}
img := imaging.Resize(src, width, 0, imaging.Lanczos)
f, err := imaging.FormatFromFilename(path)
if err != nil {
return nil, err
}
buf := bytes.Buffer{}
imaging.Encode(&buf, img, f)
return buf.Bytes(), nil
}

View File

@@ -2,7 +2,6 @@ package httper
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@@ -23,6 +22,42 @@ func Get(url string, head map[string]string) (response string) {
for k, v := range head { for k, v := range head {
req.Header.Add(k, v) req.Header.Add(k, v)
} }
if err != nil {
return ""
}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
//需要错误日志的处理
//loger.Error(error)
return ""
//panic(error)
}
defer resp.Body.Close()
var buffer [512]byte
result := bytes.NewBuffer(nil)
for {
n, err := resp.Body.Read(buffer[0:])
result.Write(buffer[0:n])
if err != nil && err == io.EOF {
break
} else if err != nil {
//loger.Error(err)
return ""
// panic(err)
}
}
response = result.String()
return
}
//发送GET请求
//url:请求地址
//response:请求返回的内容
func PersonGet(url string) (response string) {
client := &http.Client{Timeout: 5 * time.Second}
req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
return "" return ""
} }
@@ -78,88 +113,6 @@ func Post(url string, data []byte, contentType string, head map[string]string) (
return return
} }
//发送POST请求
//url:请求地址data:POST请求提交的数据,contentType:请求体格式application/json
//content:请求放回的内容
func ZeroTierPost(url string, data map[string]string, head map[string]string, cookies []*http.Cookie) (content string, code int) {
b, _ := json.Marshal(data)
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
for _, cookie := range cookies {
req.AddCookie(cookie)
}
for k, v := range head {
req.Header.Add(k, v)
}
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 20 * time.Second}
resp, error := client.Do(req)
if error != nil {
panic(error)
}
defer resp.Body.Close()
code = resp.StatusCode
result, _ := ioutil.ReadAll(resp.Body)
content = string(result)
return
}
//发送POST请求
//url:请求地址data:POST请求提交的数据,contentType:请求体格式application/json
//content:请求放回的内容
func ZeroTierPostJson(url string, data string, head map[string]string) (content string, code int) {
var postData *bytes.Buffer
jsonStr := []byte(data)
postData = bytes.NewBuffer(jsonStr)
req, err := http.NewRequest("POST", url, postData)
for k, v := range head {
req.Header.Add(k, v)
}
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 20 * time.Second}
resp, error := client.Do(req)
if error != nil {
panic(error)
}
defer resp.Body.Close()
result, _ := ioutil.ReadAll(resp.Body)
content = string(result)
code = resp.StatusCode
return
}
func ZeroTierDelete(url string, head map[string]string) (content string, code int) {
req, err := http.NewRequest("DELETE", url, nil)
for k, v := range head {
req.Header.Add(k, v)
}
if err != nil {
panic(err)
}
client := &http.Client{Timeout: 20 * time.Second}
resp, error := client.Do(req)
if error != nil {
panic(error)
}
defer resp.Body.Close()
result, _ := ioutil.ReadAll(resp.Body)
content = string(result)
code = resp.StatusCode
return
}
//发送POST请求 //发送POST请求
//url:请求地址data:POST请求提交的数据,contentType:请求体格式application/json //url:请求地址data:POST请求提交的数据,contentType:请求体格式application/json
//content:请求放回的内容 //content:请求放回的内容

View File

@@ -1,9 +1,10 @@
package ip_helper package ip_helper
import ( import (
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"net" "net"
"strings" "strings"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
) )
func IsIPv4(address string) bool { func IsIPv4(address string) bool {
@@ -39,3 +40,35 @@ func GetLoclIp() string {
} }
return "127.0.0.1" return "127.0.0.1"
} }
func GetDeviceAllIP(port string) []string {
var address []string
addrs, err := net.InterfaceAddrs()
if err != nil {
return address
}
for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To16() != nil {
address = append(address, ipNet.IP.String()+":"+port)
}
}
}
return address
}
func HasLocalIP(ip net.IP) bool {
if ip.IsLoopback() {
return true
}
ip.String()
ip4 := ip.To4()
if ip4 == nil {
return false
}
return ip4[0] == 10 || // 10.0.0.0/8
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
}

View File

@@ -2,6 +2,7 @@ package ip_helper
import ( import (
"fmt" "fmt"
"net"
"testing" "testing"
) )
@@ -20,3 +21,7 @@ func TestGetExternalIPV6(t *testing.T) {
func TestGetLoclIp(t *testing.T) { func TestGetLoclIp(t *testing.T) {
fmt.Println(GetLoclIp()) fmt.Println(GetLoclIp())
} }
func TestHasLocalIP(t *testing.T) {
fmt.Println("dddd")
fmt.Println(HasLocalIP(net.ParseIP("192.168.2.10")))
}

View File

@@ -1,109 +1,92 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-06-02 15:09:38
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-02 17:43:38
* @FilePath: /CasaOS/pkg/utils/loger/log.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package loger package loger
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file" "go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
) )
//定义一个int的别名 var loggers *zap.Logger
type Level int
type OLog interface { func getFileLogWriter() (writeSyncer zapcore.WriteSyncer) {
Debug(v ...interface{}) // 使用 lumberjack 实现 log rotate
Info(v ...interface{}) lumberJackLogger := &lumberjack.Logger{
Warn(v ...interface{}) Filename: filepath.Join(config.AppInfo.LogSavePath, fmt.Sprintf("%s.%s",
Error(v ...interface{}) config.AppInfo.LogSaveName,
Fatal(v ...interface{}) config.AppInfo.LogFileExt,
Path() string )),
} MaxSize: 100,
MaxBackups: 60,
type oLog struct { MaxAge: 1,
} Compress: true,
var (
F *os.File
DefaultPrefix = ""
DefaultCallerDepth = 2
logger *log.Logger
logPrefix = ""
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
//iota在const关键字出现时将被重置为0(const内部的第一行之前)const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。
const (
DEBUG Level = iota
INFO
WARN
ERROR
FATAL
)
//日志初始化
func LogSetup() {
var err error
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
fileName := fmt.Sprintf("%s.%s",
config.AppInfo.LogSaveName,
config.AppInfo.LogFileExt,
)
F, err = file2.MustOpen(fileName, filePath)
if err != nil {
log.Fatalf("logging.Setup err: %v", err)
} }
logger = log.New(F, DefaultPrefix, log.LstdFlags) return zapcore.AddSync(lumberJackLogger)
} }
func (o *oLog) Path() string {
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath) func LogInit() {
fileName := fmt.Sprintf("%s.%s", encoderConfig := zap.NewProductionEncoderConfig()
config.AppInfo.LogSaveName, encoderConfig.EncodeTime = zapcore.EpochTimeEncoder
config.AppInfo.LogFileExt, encoder := zapcore.NewJSONEncoder(encoderConfig)
fileWriteSyncer := getFileLogWriter()
core := zapcore.NewTee(
zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel),
zapcore.NewCore(encoder, fileWriteSyncer, zapcore.DebugLevel),
) )
return filePath + fileName loggers = zap.New(core)
}
func (o *oLog) Debug(v ...interface{}) {
setPrefix(DEBUG)
logger.Println(v)
} }
func (o *oLog) Info(v ...interface{}) { func Info(message string, fields ...zap.Field) {
setPrefix(INFO) callerFields := getCallerInfoForLog()
logger.Println(v) fields = append(fields, callerFields...)
loggers.Info(message, fields...)
} }
func (o *oLog) Warn(v ...interface{}) { func Debug(message string, fields ...zap.Field) {
setPrefix(WARN) callerFields := getCallerInfoForLog()
logger.Println(v) fields = append(fields, callerFields...)
loggers.Debug(message, fields...)
} }
func (o *oLog) Error(v ...interface{}) { func Error(message string, fields ...zap.Field) {
setPrefix(ERROR) callerFields := getCallerInfoForLog()
logger.Println(v) fields = append(fields, callerFields...)
loggers.Error(message, fields...)
} }
func (o *oLog) Fatal(v ...interface{}) { func Warn(message string, fields ...zap.Field) {
setPrefix(FATAL) callerFields := getCallerInfoForLog()
logger.Println(v) fields = append(fields, callerFields...)
loggers.Warn(message, fields...)
} }
func setPrefix(level Level) { func getCallerInfoForLog() (callerFields []zap.Field) {
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
if ok { pc, file, line, ok := runtime.Caller(2) // 回溯两层,拿到写日志的调用方的函数信息
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line) if !ok {
} else { return
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
} }
funcName := runtime.FuncForPC(pc).Name()
funcName = path.Base(funcName) //Base函数返回路径的最后一个元素只保留函数名
logger.SetPrefix(logPrefix) callerFields = append(callerFields, zap.String("func", funcName), zap.String("file", file), zap.Int("line", line))
} return
func NewOLoger() OLog {
return &oLog{}
} }

109
pkg/utils/loger/log_old.go Normal file
View File

@@ -0,0 +1,109 @@
package loger
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"github.com/IceWhaleTech/CasaOS/pkg/config"
file2 "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
)
//定义一个int的别名
type Level int
type OLog interface {
Debug(v ...interface{})
Info(v ...interface{})
Warn(v ...interface{})
Error(v ...interface{})
Fatal(v ...interface{})
Path() string
}
type oLog struct {
}
var (
F *os.File
DefaultPrefix = ""
DefaultCallerDepth = 2
logger *log.Logger
logPrefix = ""
levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
//iota在const关键字出现时将被重置为0(const内部的第一行之前)const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。
const (
DEBUG Level = iota
INFO
WARN
ERROR
FATAL
)
//日志初始化
func LogSetupOld() {
var err error
filePath := fmt.Sprintf("%s", config.AppInfo.LogSavePath)
fileName := fmt.Sprintf("%s.%s",
config.AppInfo.LogSaveName,
config.AppInfo.LogFileExt,
)
F, err = file2.MustOpen(fileName, filePath)
if err != nil {
log.Fatalf("logging.Setup err: %v", err)
}
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)
}
func (o *oLog) Info(v ...interface{}) {
setPrefix(INFO)
logger.Println(v)
}
func (o *oLog) Warn(v ...interface{}) {
setPrefix(WARN)
logger.Println(v)
}
func (o *oLog) Error(v ...interface{}) {
setPrefix(ERROR)
logger.Println(v)
}
func (o *oLog) Fatal(v ...interface{}) {
setPrefix(FATAL)
logger.Println(v)
}
func setPrefix(level Level) {
_, file, line, ok := runtime.Caller(DefaultCallerDepth)
if ok {
logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line)
} else {
logPrefix = fmt.Sprintf("[%s]", levelFlags[level])
}
logger.SetPrefix(logPrefix)
}
func NewOLoger() OLog {
return &oLog{}
}

View File

@@ -0,0 +1,30 @@
/*
* @Author: LinkLeong a624669980@163.com
* @Date: 2022-05-08 14:58:46
* @LastEditors: LinkLeong a624669980@163.com
* @LastEditTime: 2022-05-09 13:42:26
* @FilePath: /CasaOS/pkg/utils/network_detection.go
* @Description:
*
* Copyright (c) 2022 by LinkLeong a624669980@163.com, All Rights Reserved.
*/
package utils
import natType "github.com/Curtis-Milo/nat-type-identifier-go"
/**
* @description:
* @param {chanstring} data
* @param {string} url
* @return {*}
*/
func GetNetWorkTypeDetection(data chan string, url string) {
// fmt.Println("url:", url)
// httper.Get(url, nil)
// aaa <- url
result, err := natType.GetDeterminedNatType(true, 5, url)
if err == nil {
data <- result
}
}

View File

@@ -0,0 +1,29 @@
/*
* @Author: LinkLeong a624669980@163.com
* @Date: 2022-05-08 15:07:31
* @LastEditors: LinkLeong a624669980@163.com
* @LastEditTime: 2022-05-09 11:43:30
* @FilePath: /CasaOS/pkg/utils/network_detection_test.go
* @Description:
*
* Copyright (c) 2022 by LinkLeong a624669980@163.com, All Rights Reserved.
*/
package utils
import (
"fmt"
"testing"
)
func TestGetResultTest(t *testing.T) {
list := []string{"https://www.google.com", "https://www.bing.com", "https://www.baidu.com"}
data := make(chan string)
//data <- "init"
for _, v := range list {
go GetNetWorkTypeDetection(data, v)
}
result := <-data
close(data)
fmt.Println(result)
}

View File

@@ -13,10 +13,11 @@ const (
PWD_INVALID_OLD = 10003 PWD_INVALID_OLD = 10003
ACCOUNT_LOCK = 10004 ACCOUNT_LOCK = 10004
//system //system
DIR_ALREADY_EXISTS = 20001 DIR_ALREADY_EXISTS = 20001
FILE_ALREADY_EXISTS = 20002 FILE_ALREADY_EXISTS = 20002
FILE_OR_DIR_EXISTS = 20003 FILE_OR_DIR_EXISTS = 20003
PORT_IS_OCCUPIED = 20004 PORT_IS_OCCUPIED = 20004
COMMAND_ERROR_INVALID_OPERATION = 20005
//zerotier //zerotier
GET_TOKEN_ERROR = 30001 GET_TOKEN_ERROR = 30001
@@ -29,15 +30,17 @@ const (
FORMAT_ERROR = 40005 FORMAT_ERROR = 40005
//app //app
UNINSTALL_APP_ERROR = 50001 UNINSTALL_APP_ERROR = 50001
PULL_IMAGE_ERROR = 50002 PULL_IMAGE_ERROR = 50002
DEVICE_NOT_EXIST = 50003 DEVICE_NOT_EXIST = 50003
ERROR_APP_NAME_EXIST = 50004
//file //file
FILE_DOES_NOT_EXIST = 60001 FILE_DOES_NOT_EXIST = 60001
FILE_READ_ERROR = 60002 FILE_READ_ERROR = 60002
FILE_DELETE_ERROR = 60003 FILE_DELETE_ERROR = 60003
DIR_NOT_EXISTS = 60004 DIR_NOT_EXISTS = 60004
SOURCE_DES_SAME = 60005
//shortcuts //shortcuts
SHORTCUTS_URL_ERROR = 70001 SHORTCUTS_URL_ERROR = 70001
@@ -73,9 +76,10 @@ var MsgFlags = map[int]string{
GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available", GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",
//app //app
UNINSTALL_APP_ERROR: "Error uninstalling app", UNINSTALL_APP_ERROR: "Error uninstalling app",
PULL_IMAGE_ERROR: "Error pulling image", PULL_IMAGE_ERROR: "Error pulling image",
DEVICE_NOT_EXIST: "Device does not exist", DEVICE_NOT_EXIST: "Device does not exist",
ERROR_APP_NAME_EXIST: "App name already exists",
//disk //disk
NAME_NOT_AVAILABLE: "Name not available", NAME_NOT_AVAILABLE: "Name not available",
@@ -85,6 +89,7 @@ var MsgFlags = map[int]string{
FORMAT_ERROR: "Formatting failed, please check if the directory is occupied", FORMAT_ERROR: "Formatting failed, please check if the directory is occupied",
// //
SOURCE_DES_SAME: "Source and destination cannot be the same.",
FILE_DOES_NOT_EXIST: "File does not exist", FILE_DOES_NOT_EXIST: "File does not exist",
DIR_NOT_EXISTS: "Directory does not exist", DIR_NOT_EXISTS: "Directory does not exist",
@@ -93,12 +98,13 @@ var MsgFlags = map[int]string{
FILE_DELETE_ERROR: "Delete error", FILE_DELETE_ERROR: "Delete error",
SHORTCUTS_URL_ERROR: "URL error", SHORTCUTS_URL_ERROR: "URL error",
PERSON_REMOTE_ERROR: "Remote connection error", PERSON_REMOTE_ERROR: "Remote connection error",
PERSON_DOWN_NOT_EXIST: "Download record does not exist", PERSON_DOWN_NOT_EXIST: "Download record does not exist",
PERSON_EXIST_DOWNLOAD: "The same download task exists", PERSON_EXIST_DOWNLOAD: "The same download task exists",
PERSON_EXIST_FRIEND: "Friend already exist", PERSON_EXIST_FRIEND: "Friend already exist",
PERSON_NOT_EXIST_USER: "User does not exist", PERSON_NOT_EXIST_USER: "User does not exist",
PERSON_MYSELF: "You can not add yourself", PERSON_MYSELF: "You can not add yourself",
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
} }
//获取错误信息 //获取错误信息

View File

@@ -1,73 +0,0 @@
package sort
import (
"github.com/IceWhaleTech/CasaOS/model"
"sort"
)
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type devSorter struct {
dev []model.Devices
less []lessFuncDev
}
// sort接口方法之一(Less)
type lessFuncDev func(p1, p2 *model.Devices) bool
// Sort 函数有两个作用
// 第一, 将参数(实际的数据集)赋值给ms对象
// 第二, 调用内置sort函数进行排序操作
func (ms *devSorter) Sort(dev []model.Devices) {
ms.dev = dev
sort.Sort(ms)
}
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
func DevSort(less ...lessFuncDev) *devSorter {
return &devSorter{
less: less,
}
}
// Len 为sort接口方法之一
func (ms *devSorter) Len() int {
return len(ms.dev)
}
// Swap 为sort接口方法之一
func (ms *devSorter) Swap(i, j int) {
ms.dev[i], ms.dev[j] = ms.dev[j], ms.dev[i]
}
// Less 为sort接口方法之一
func (ms *devSorter) Less(i, j int) bool {
temp := ms.dev
p, q := &temp[i], &temp[j]
// Try all but the last comparison.
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q):
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p):
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}

View File

@@ -1,74 +0,0 @@
package sort
import (
"sort"
"github.com/IceWhaleTech/CasaOS/model"
)
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type evnSorter struct {
evn []model.Envs
less []lessFuncEnv
}
// sort接口方法之一(Less)
type lessFuncEnv func(p1, p2 *model.Envs) bool
// Sort 函数有两个作用
// 第一, 将参数(实际的数据集)赋值给ms对象
// 第二, 调用内置sort函数进行排序操作
func (ms *evnSorter) Sort(env []model.Envs) {
ms.evn = env
sort.Sort(ms)
}
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
func EnvSort(less ...lessFuncEnv) *evnSorter {
return &evnSorter{
less: less,
}
}
// Len 为sort接口方法之一
func (ms *evnSorter) Len() int {
return len(ms.evn)
}
// Swap 为sort接口方法之一
func (ms *evnSorter) Swap(i, j int) {
ms.evn[i], ms.evn[j] = ms.evn[j], ms.evn[i]
}
// Less 为sort接口方法之一
func (ms *evnSorter) Less(i, j int) bool {
temp := ms.evn
p, q := &temp[i], &temp[j]
// Try all but the last comparison.
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q):
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p):
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}

View File

@@ -1,73 +0,0 @@
package sort
import (
"github.com/IceWhaleTech/CasaOS/model"
"sort"
)
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type multiSorter struct {
ports []model.Ports
less []lessFunc
}
// sort接口方法之一(Less)
type lessFunc func(p1, p2 *model.Ports) bool
// Sort 函数有两个作用
// 第一, 将参数(实际的数据集)赋值给ms对象
// 第二, 调用内置sort函数进行排序操作
func (ms *multiSorter) Sort(ports []model.Ports) {
ms.ports = ports
sort.Sort(ms)
}
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
func PortsSort(less ...lessFunc) *multiSorter {
return &multiSorter{
less: less,
}
}
// Len 为sort接口方法之一
func (ms *multiSorter) Len() int {
return len(ms.ports)
}
// Swap 为sort接口方法之一
func (ms *multiSorter) Swap(i, j int) {
ms.ports[i], ms.ports[j] = ms.ports[j], ms.ports[i]
}
// Less 为sort接口方法之一
func (ms *multiSorter) Less(i, j int) bool {
port := ms.ports
p, q := &port[i], &port[j]
// Try all but the last comparison.
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q):
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p):
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}

View File

@@ -1,73 +0,0 @@
package sort
import (
"github.com/IceWhaleTech/CasaOS/model"
"sort"
)
// 数据集类型, 与上一篇排序文章(多字段单独排序)比较, less字段的数据类型不再是 func(p1, p2 *Change) bool
// 而是 []func(p1, p2 *Change) bool 因为在第一个比较的值相等的情况下, 还要比较第二个值, 所以这里需要多个比较函数
type volSorter struct {
vol []model.Volume
less []lessFuncVol
}
// sort接口方法之一(Less)
type lessFuncVol func(p1, p2 *model.Volume) bool
// Sort 函数有两个作用
// 第一, 将参数(实际的数据集)赋值给ms对象
// 第二, 调用内置sort函数进行排序操作
func (ms *volSorter) Sort(vol []model.Volume) {
ms.vol = vol
sort.Sort(ms)
}
// OrderedBy 函数的作用是返回一个multiSorter实例, 并将所有的实际排序函数赋值给实例的less字段,
// 上面已经为multiSorter结构体定义了Sort方法, 所以该函数的返回值可以直接调用Sort方法进行排序
// 该函数中, 为multiSorter结构体中的less字段赋值, Sort方法中又将实际数据集传入, 赋值给multiSorter的ports字段
// 一个函数, 一个方法调用过后, multiSorter实例中两个字段就已经全部被正确赋值, 可以调用系统sort函数进行排序
// 该函数也可看作是一个工厂方法, 用来生成less字段已经被赋值的multiSorter实例
func VolSort(less ...lessFuncVol) *volSorter {
return &volSorter{
less: less,
}
}
// Len 为sort接口方法之一
func (ms *volSorter) Len() int {
return len(ms.vol)
}
// Swap 为sort接口方法之一
func (ms *volSorter) Swap(i, j int) {
ms.vol[i], ms.vol[j] = ms.vol[j], ms.vol[i]
}
// Less 为sort接口方法之一
func (ms *volSorter) Less(i, j int) bool {
temp := ms.vol
p, q := &temp[i], &temp[j]
// Try all but the last comparison.
var k int
// 由于可能有多个需要排序的字段, 也就对应了多个less函数, 当第一个字段的值相等时,
// 需要依次尝试比对后续其他字段的值得大小, 所以这里需要获取比较函数的长度, 以便遍历比较
for k = 0; k < len(ms.less)-1; k++ {
// 提取比较函数, 将函数赋值到新的变量中以便调用
less := ms.less[k]
switch {
case less(p, q):
// 如果 p < q, 返回值为true, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
// 如果 p > q, 返回值为false, 则调到下一个case中处理
return true
case less(q, p):
// 如果 p > q, 返回值为false, 不存在两个值相等需要比较后续字段的情况, 所以这里直接返回
return false
}
// 如果代码走到这里, 说明ms.less[k]函数比较后 p == q; 重新开始下一次循环, 更换到下一个比较函数处理
continue
}
// 如果代码走到这里, 说明所有的比较函数执行过后, 所有比较的值都相等
// 直接返回最后一次的比较结果数据即可
return ms.less[k](p, q)
}

View File

@@ -1,3 +1,13 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-02 17:41:47
* @FilePath: /CasaOS/pkg/utils/version/version.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package version package version
import ( import (
@@ -32,6 +42,8 @@ func IsNeedUpdate() (bool, model.Version) {
b, _ := strconv.Atoi(v2[i]) b, _ := strconv.Atoi(v2[i])
if a > b { if a > b {
return true, version return true, version
} else {
return false, version
} }
} }
return false, version return false, version

View File

@@ -1,17 +1,17 @@
package route package route
import ( import (
"encoding/json"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/system_app" "github.com/IceWhaleTech/CasaOS/model/system_app"
"github.com/IceWhaleTech/CasaOS/pkg/config" "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/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper" "github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
@@ -27,6 +27,9 @@ func InitFunction() {
CheckSerialDiskMount() CheckSerialDiskMount()
CheckToken2_11() CheckToken2_11()
ImportApplications()
ChangeAPIUrl()
InitSystemApplication()
} }
@@ -77,14 +80,12 @@ func installSyncthing(appId string) {
appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip) appInfo.Tip = env_helper.ReplaceStringDefaultENV(appInfo.Tip)
} }
appInfo.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20 appInfo.MaxMemory = service.MyService.System().GetMemInfo().Total >> 20
id := uuid.NewV4().String() id := uuid.NewV4().String()
installLog := model2.AppNotify{}
// step下载镜像 // step下载镜像
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog) err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, "", "")
if err != nil { if err != nil {
//pull image error //pull image error
fmt.Println("pull image error", err, dockerImage, dockerImageVersion) fmt.Println("pull image error", err, dockerImage, dockerImageVersion)
@@ -102,8 +103,9 @@ func installSyncthing(appId string) {
m.Ports = appInfo.Ports m.Ports = appInfo.Ports
m.Restart = "always" m.Restart = "always"
m.Volumes = appInfo.Volumes m.Volumes = appInfo.Volumes
m.Label = id
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel) m.CustomId = id
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
if err != nil { if err != nil {
fmt.Println("container create error", err) fmt.Println("container create error", err)
// create container error // create container error
@@ -111,83 +113,45 @@ func installSyncthing(appId string) {
} }
//stepstart container //stepstart container
err = service.MyService.Docker().DockerContainerStart(id) err = service.MyService.Docker().DockerContainerStart(containerId)
if err != nil { if err != nil {
//start container error //start container error
return 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() checkSystemApp()
} }
// check if the system application is installed // check if the system application is installed
func checkSystemApp() { func checkSystemApp() {
list := service.MyService.App().GetSystemAppList() list := service.MyService.App().GetSystemAppList()
for _, v := range *list { for _, v := range list {
if v.Image == "linuxserver/syncthing" { info, err := service.MyService.Docker().DockerContainerInfo(v.ID)
if err != nil {
continue
}
if strings.Contains(info.Config.Image, "linuxserver/syncthing") {
if v.State != "running" { if v.State != "running" {
//stepstart container //stepstart container
service.MyService.Docker().DockerContainerStart(v.CustomId) service.MyService.Docker().DockerContainerStart(v.ID)
} }
syncIsExistence = true syncIsExistence = true
if config.SystemConfigInfo.SyncPort != v.Port { if config.SystemConfigInfo.SyncPort != v.Labels["web"] {
config.SystemConfigInfo.SyncPort = v.Port config.SystemConfigInfo.SyncPort = v.Labels["web"]
} }
var paths []model.PathMap
json.Unmarshal([]byte(v.Volumes), &paths)
path := "" path := ""
for _, i := range paths { for _, i := range info.Mounts {
if i.ContainerPath == "/config" { if i.Destination == "/config" {
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml" path = i.Source
for i := 0; i < 10; i++ {
if file.CheckNotExist(path) {
time.Sleep(1 * time.Second)
} else {
break
}
}
break break
} }
} }
content := file.ReadFullFile(path) content := file.ReadFullFile(filepath.Join(path, "config.xml"))
syncConfig := &system_app.SyncConfig{} syncConfig := &system_app.SyncConfig{}
xml.Unmarshal(content, &syncConfig) xml.Unmarshal(content, &syncConfig)
config.SystemConfigInfo.SyncKey = syncConfig.Key config.SystemConfigInfo.SyncKey = syncConfig.Key
break
} }
} }
if !syncIsExistence { if !syncIsExistence {
@@ -261,7 +225,7 @@ func CheckToken2_11() {
downloadPath = "C:\\CasaOS\\DATA\\Downloads" downloadPath = "C:\\CasaOS\\DATA\\Downloads"
} }
if sysType == "darwin" { if sysType == "darwin" {
downloadPath = "~/CasaOS/DATA/Downloads" downloadPath = "./CasaOS/DATA/Downloads"
} }
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath) config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
config.FileSettingInfo.DownloadDir = downloadPath config.FileSettingInfo.DownloadDir = downloadPath
@@ -280,7 +244,10 @@ func CheckToken2_11() {
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
} }
service.MyService.System().ExecUSBAutoMountShell(config.ServerInfo.USBAutoMount) if service.MyService.ZiMa().GetSysInfo().KernelArch == "aarch64" && config.ServerInfo.USBAutoMount != "True" && strings.Contains(service.MyService.ZiMa().GetDeviceTree(), "Raspberry Pi") {
service.MyService.System().UpdateUSBAutoMount("False")
service.MyService.System().ExecUSBAutoMountShell("False")
}
// str := []string{} // str := []string{}
// str = append(str, "ddd") // str = append(str, "ddd")
@@ -291,3 +258,39 @@ func CheckToken2_11() {
// config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) // config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
} }
func ImportApplications() {
service.MyService.App().ImportApplications(true)
}
// 0.3.1
func ChangeAPIUrl() {
newAPIUrl := "https://api.casaos.io/casaos-api"
if config.ServerInfo.ServerApi == "https://api.casaos.zimaboard.com" {
config.ServerInfo.ServerApi = newAPIUrl
config.Cfg.Section("server").Key("ServerApi").SetValue(newAPIUrl)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
}
// 0.3.1
func InitSystemApplication() {
list := service.MyService.App().GetApplicationList()
if len(list) != 2 {
application := model2.ApplicationModel{}
application.Name = "Files"
application.Icon = "/ui/img/Files.svg"
application.Type = "system"
application.Order = 0
service.MyService.App().CreateApplication(application)
application.Name = "CasaConnect"
application.Icon = "/ui/img/CasaConnect.svg"
application.Type = "system"
application.Order = 0
service.MyService.App().CreateApplication(application)
}
}

285
route/periodical.go Normal file
View File

@@ -0,0 +1,285 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-27 15:55:36
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-10 12:17:59
* @FilePath: /CasaOS/route/periodical.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package route
import (
"reflect"
"strconv"
"strings"
"time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/service"
)
func SendNetINfoBySocket() {
netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{}
nets := service.MyService.System().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
}
}
}
service.MyService.Notify().SendNetInfoBySocket(newNet)
}
func SendCPUBySocket() {
cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.System().GetCpuCoreNum()
cpuData := make(map[string]interface{})
cpuData["percent"] = cpu
cpuData["num"] = num
service.MyService.Notify().SendCPUInfoBySocket(cpuData)
}
func SendMemBySocket() {
service.MyService.Notify().SendMemInfoBySocket(service.MyService.System().GetMemInfo())
}
func SendDiskBySocket() {
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
service.MyService.Notify().SendDiskInfoBySocket(summary)
}
func SendUSBBySocket() {
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)
}
}
service.MyService.Notify().SendUSBInfoBySocket(usb)
}
func SendAllHardwareStatusBySocket() {
netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{}
nets := service.MyService.System().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
}
}
}
cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.System().GetCpuCoreNum()
cpuData := make(map[string]interface{})
cpuData["percent"] = cpu
cpuData["num"] = num
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
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)
}
}
memInfo := service.MyService.System().GetMemInfo()
memData := make(map[string]interface{})
memData["total"] = memInfo.Total
memData["available"] = memInfo.Available
memData["used"] = memInfo.Used
memData["free"] = memInfo.Free
memData["usedPercent"] = memInfo.UsedPercent
service.MyService.Notify().SendAllHardwareStatusBySocket(summary, usb, memData, cpuData, newNet)
}

View File

@@ -31,7 +31,6 @@ func InitRouter() *gin.Engine {
if swagHandler != nil { if swagHandler != nil {
r.GET("/swagger/*any", swagHandler) r.GET("/swagger/*any", swagHandler)
} }
r.POST("/v1/user/login", v1.Login) r.POST("/v1/user/login", v1.Login)
r.GET("/v1/guide/check", v1.GetGuideCheck) r.GET("/v1/guide/check", v1.GetGuideCheck)
@@ -41,7 +40,9 @@ func InitRouter() *gin.Engine {
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd) r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
//get user info //get user info
r.GET("/v1/user/info", v1.GetUserInfo) r.GET("/v1/user/info", v1.GetUserInfo)
//get user info
r.GET("/v1/person/shareid", v1.GetPersonShareId)
r.GET("/v1/sys/socket/port", v1.GetSystemSocketPort)
v1Group := r.Group("/v1") v1Group := r.Group("/v1")
v1Group.Use(jwt2.JWT(swagHandler)) v1Group.Use(jwt2.JWT(swagHandler))
@@ -63,46 +64,15 @@ func InitRouter() *gin.Engine {
v1UserGroup.POST("/person/info", v1.PostUserPersonInfo) v1UserGroup.POST("/person/info", v1.PostUserPersonInfo)
v1UserGroup.GET("/shareid", v1.GetUserShareID) v1UserGroup.GET("/shareid", v1.GetUserShareID)
// v1UserGroup.GET("/custom/:name")
// v1UserGroup.POST("/custom/:name")
} }
v1ZiMaGroup := v1Group.Group("/zima")
v1ZiMaGroup.Use()
{
//获取cpu信息
v1ZiMaGroup.GET("/getcpuinfo", v1.CupInfo)
//获取内存信息
v1ZiMaGroup.GET("/getmeminfo", v1.MemInfo)
//获取硬盘信息
v1ZiMaGroup.GET("/getdiskinfo", v1.DiskInfo)
//获取网络信息
v1ZiMaGroup.GET("/getnetinfo", v1.NetInfo)
//获取系统信息
v1ZiMaGroup.GET("/sysinfo", v1.SysInfo)
}
v1DDNSGroup := v1Group.Group("/ddns")
v1DDNSGroup.Use()
{
//获取ddns列表
v1DDNSGroup.GET("/getlist", v1.DDNSGetDomainList)
//测试连接性
v1DDNSGroup.GET("/ping/:api_host", v1.DDNSPing)
//获取ip
v1DDNSGroup.GET("/ip", v1.DDNSGetIP)
//设置ddns
v1DDNSGroup.POST("/set", v1.DDNSAddConfig)
//获取ddns
v1DDNSGroup.GET("/list", v1.DDNSConfigList)
//获取ddns
v1DDNSGroup.DELETE("/delete/:id", v1.DDNSDelete)
}
v1AppGroup := v1Group.Group("/app") v1AppGroup := v1Group.Group("/app")
v1AppGroup.Use() v1AppGroup.Use()
{ {
//获取我的已安装的列表 //获取我的已安装的列表
v1AppGroup.GET("/mylist", v1.MyAppList) v1AppGroup.GET("/my/list", v1.MyAppList)
// //
v1AppGroup.GET("/usage", v1.AppUsageList) v1AppGroup.GET("/usage", v1.AppUsageList)
//app详情 //app详情
@@ -117,8 +87,8 @@ func InitRouter() *gin.Engine {
v1AppGroup.GET("/category", v1.CategoryList) v1AppGroup.GET("/category", v1.CategoryList)
//容器相关 //容器相关
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal) v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
//准备安装 v1AppGroup.GET("/order", v1.GetAppOrder)
//v1AppGroup.GET("/ready/:id", v1.ReadyInstall) v1AppGroup.POST("/order", v1.PostAppOrder)
//app容器详情 //app容器详情
v1AppGroup.GET("/info/:id", v1.ContainerInfo) v1AppGroup.GET("/info/:id", v1.ContainerInfo)
//app容器日志 //app容器日志
@@ -126,11 +96,9 @@ func InitRouter() *gin.Engine {
//暂停或启动容器 //暂停或启动容器
v1AppGroup.PUT("/state/:id", v1.ChangAppState) v1AppGroup.PUT("/state/:id", v1.ChangAppState)
//安装app //安装app
v1AppGroup.POST("/install/:id", v1.InstallApp) v1AppGroup.POST("/install", v1.InstallApp)
//卸载app //卸载app
v1AppGroup.DELETE("/uninstall/:id", v1.UnInstallApp) v1AppGroup.DELETE("/uninstall/:id", v1.UnInstallApp)
//获取安装进度
v1AppGroup.GET("/speed/:id", v1.GetInstallSpeed)
//获取进度 //获取进度
v1AppGroup.GET("/state/:id", v1.GetContainerState) v1AppGroup.GET("/state/:id", v1.GetContainerState)
//更新容器配置 //更新容器配置
@@ -139,17 +107,16 @@ func InitRouter() *gin.Engine {
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo) v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo) v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig) v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
//v1AppGroup.POST("/custom/install", v1.CustomInstallApp) v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
v1AppGroup.POST("/share", v1.ShareAppFile) v1AppGroup.POST("/share", v1.ShareAppFile)
} }
v1SysGroup := v1Group.Group("/sys") v1SysGroup := v1Group.Group("/sys")
v1SysGroup.Use() v1SysGroup.Use()
{ {
//获取检查版本是否需要升级 v1SysGroup.GET("/version/check", v1.GetSystemCheckVersion)
v1SysGroup.GET("/check", v1.CheckVersion) v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
v1SysGroup.POST("/update", v1.SystemUpdate) v1SysGroup.POST("/update", v1.SystemUpdate)
v1SysGroup.GET("/sys", v1.Sys)
v1SysGroup.GET("/wsssh", v1.WsSsh) v1SysGroup.GET("/wsssh", v1.WsSsh)
v1SysGroup.GET("/config", v1.GetSystemConfig) v1SysGroup.GET("/config", v1.GetSystemConfig)
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs) v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
@@ -158,16 +125,19 @@ func InitRouter() *gin.Engine {
v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig) v1SysGroup.POST("/widget/config", v1.PostSetWidgetConfig)
v1SysGroup.GET("/port", v1.GetCasaOSPort) v1SysGroup.GET("/port", v1.GetCasaOSPort)
v1SysGroup.PUT("/port", v1.PutCasaOSPort) v1SysGroup.PUT("/port", v1.PutCasaOSPort)
v1SysGroup.POST("/kill", v1.PostKillCasaOS) v1SysGroup.POST("/stop", v1.PostKillCasaOS)
v1SysGroup.GET("/info", v1.Info) v1SysGroup.GET("/utilization", v1.GetSystemUtilization)
v1SysGroup.PUT("/usb/off", v1.PutSystemOffUSBAutoMount) v1SysGroup.PUT("/usb/:status", v1.PutSystemUSBAutoMount)
v1SysGroup.GET("/usb/on", v1.PutSystemOnUSBAutoMount) v1SysGroup.GET("/usb/status", v1.GetSystemUSBAutoMount)
v1SysGroup.GET("/usb", v1.GetSystemUSBAutoMount) v1SysGroup.GET("/cpu", v1.GetSystemCupInfo)
v1SysGroup.GET("/mem", v1.GetSystemMemInfo)
v1SysGroup.GET("/disk", v1.GetSystemDiskInfo)
v1SysGroup.GET("/network", v1.GetSystemNetInfo)
} }
v1FileGroup := v1Group.Group("/file") v1FileGroup := v1Group.Group("/file")
v1FileGroup.Use() v1FileGroup.Use()
{ {
//修改文件名称/目录名称
v1FileGroup.PUT("/rename", v1.RenamePath) v1FileGroup.PUT("/rename", v1.RenamePath)
v1FileGroup.GET("/read", v1.GetFilerContent) v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.POST("/upload", v1.PostFileUpload) v1FileGroup.POST("/upload", v1.PostFileUpload)
@@ -178,10 +148,12 @@ func InitRouter() *gin.Engine {
v1FileGroup.POST("/create", v1.PostCreateFile) v1FileGroup.POST("/create", v1.PostCreateFile)
v1FileGroup.GET("/download", v1.GetDownloadFile) v1FileGroup.GET("/download", v1.GetDownloadFile)
v1FileGroup.GET("/new/download", v1.GetFileDownloadNew) v1FileGroup.GET("/download/*path", v1.GetDownloadSingleFile)
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir) v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
v1FileGroup.DELETE("/delete", v1.DeleteFile) v1FileGroup.DELETE("/delete", v1.DeleteFile)
v1FileGroup.PUT("/update", v1.PutFileContent) v1FileGroup.PUT("/update", v1.PutFileContent)
v1FileGroup.GET("/image", v1.GetFileImage)
v1FileGroup.DELETE("/operate/:id", v1.DeleteOperateFileOrDir)
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService) //v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
} }
@@ -231,31 +203,12 @@ func InitRouter() *gin.Engine {
v1TaskGroup.PUT("/update", v1.PutTaskUpdate) v1TaskGroup.PUT("/update", v1.PutTaskUpdate)
v1TaskGroup.POST("/add", v1.PostTaskAdd) v1TaskGroup.POST("/add", v1.PostTaskAdd)
v1TaskGroup.PUT("/completion/:id", v1.PutTaskMarkerCompletion) v1TaskGroup.PUT("/completion/:id", v1.PutTaskMarkerCompletion)
}
}
v1ShortcutsGroup := v1Group.Group("/shortcuts")
v1ShortcutsGroup.Use()
{
v1ShortcutsGroup.GET("/list", v1.GetShortcutsList)
v1ShortcutsGroup.POST("/add", v1.PostShortcutsAdd)
v1ShortcutsGroup.PUT("/edit", v1.PutShortcutsEdit)
v1ShortcutsGroup.DELETE("/del/:id", v1.DeleteShortcutsDelete)
}
v1NotifyGroup := v1Group.Group("/notify")
v1NotifyGroup.Use()
{
v1NotifyGroup.GET("/ws", v1.NotifyWS)
v1NotifyGroup.PUT("/read/:id", v1.PutNotifyRead)
}
v1SearchGroup := v1Group.Group("/search")
v1SearchGroup.Use()
{
v1SearchGroup.GET("/search", v1.GetSearchList)
}
v1PersonGroup := v1Group.Group("/person") v1PersonGroup := v1Group.Group("/person")
v1PersonGroup.Use() v1PersonGroup.Use()
{ {
v1PersonGroup.GET("/test", v1.PersonTest) v1PersonGroup.GET("/detection", v1.GetPersonDetection)
v1PersonGroup.GET("/users", v1.GetPersonFriend) v1PersonGroup.GET("/users", v1.GetPersonFriend)
v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend) v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend) v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
@@ -267,11 +220,15 @@ func InitRouter() *gin.Engine {
v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile) v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
v1PersonGroup.POST("/share", v1.PostPersonShare) v1PersonGroup.POST("/share", v1.PostPersonShare)
v1PersonGroup.POST("/file/:shareid", v1.PostPersonFile)
v1PersonGroup.GET("/share", v1.GetPersonShare) v1PersonGroup.GET("/share", v1.GetPersonShare)
v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir) v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir) v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock) v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
v1PersonGroup.GET("/public", v1.GetPersonPublic) v1PersonGroup.GET("/public", v1.GetPersonPublic)
v1PersonGroup.PUT("/friend/:shareid", v1.PutPersonAgreeFriend)
v1PersonGroup.PUT("/write/:shareid", v1.PutPersonWrite)
v1PersonGroup.GET("/image/thumbnail/:shareid", v1.GetPersonImageThumbnail)
} }
v1AnalyseGroup := v1Group.Group("/analyse") v1AnalyseGroup := v1Group.Group("/analyse")

60
route/socket.go Normal file
View File

@@ -0,0 +1,60 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-23 17:18:56
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-09 21:48:10
* @FilePath: /CasaOS/route/socket.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package route
import (
"strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/service"
f "github.com/ambelovsky/gosf"
)
func SocketInit(msg chan notify.Message) {
// set socket port
socketPort := 0
if len(config.ServerInfo.SocketPort) == 0 {
socketPort, _ = port.GetAvailablePort("tcp")
config.ServerInfo.SocketPort = strconv.Itoa(socketPort)
config.Cfg.Section("server").Key("SocketPort").SetValue(strconv.Itoa(socketPort))
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
} else {
socketPort, _ = strconv.Atoi(config.ServerInfo.SocketPort)
if !port.IsPortAvailable(socketPort, "tcp") {
socketPort, _ := port.GetAvailablePort("tcp")
config.ServerInfo.SocketPort = strconv.Itoa(socketPort)
config.Cfg.Section("server").Key("SocketPort").SetValue(strconv.Itoa(socketPort))
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
}
f.OnConnect(func(c *f.Client, request *f.Request) {
service.ClientCount += 1
})
f.OnDisconnect(func(c *f.Client, request *f.Request) {
service.ClientCount -= 1
})
go func(msg chan notify.Message) {
for v := range msg {
f.Broadcast("", v.Path, &v.Msg)
time.Sleep(time.Millisecond * 100)
}
}(msg)
f.Startup(map[string]interface{}{
"port": socketPort})
}

View File

@@ -106,13 +106,18 @@ func PortCheck(c *gin.Context) {
// @Param size query int false "size" // @Param size query int false "size"
// @Param position query bool false "是否是首页应用" // @Param position query bool false "是否是首页应用"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/mylist [get] // @Router /app/my/list [get]
func MyAppList(c *gin.Context) { func MyAppList(c *gin.Context) {
index, _ := strconv.Atoi(c.DefaultQuery("index", "1")) index, _ := strconv.Atoi(c.DefaultQuery("index", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "0")) size, _ := strconv.Atoi(c.DefaultQuery("size", "0"))
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true")) position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
list := service.MyService.App().GetMyList(index, size, position) list, unTranslation := service.MyService.App().GetMyList(index, size, position)
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
data := make(map[string]interface{}, 2)
data["list"] = list
data["local"] = unTranslation
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
} }
// @Summary my app hardware usage list // @Summary my app hardware usage list
@@ -204,7 +209,7 @@ func AppInfo(c *gin.Context) {
// sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap)) // sort.VolSort(volOrder).Sort(info.Volumes.([]model.PathMap))
// sort.DevSort(devOrder).Sort(info.Devices) // sort.DevSort(devOrder).Sort(info.Devices)
info.MaxMemory = service.MyService.ZiMa().GetMemInfo().Total >> 20 info.MaxMemory = service.MyService.System().GetMemInfo().Total >> 20
c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info}) c.JSON(http.StatusOK, &model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info})
} }
@@ -241,14 +246,3 @@ func ShareAppFile(c *gin.Context) {
content := service.MyService.Casa().ShareAppFile(str) content := service.MyService.Casa().ShareAppFile(str)
c.JSON(http.StatusOK, json.RawMessage(content)) 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

@@ -5,17 +5,19 @@ import (
"encoding/json" "encoding/json"
json2 "encoding/json" json2 "encoding/json"
"net/http" "net/http"
"reflect" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/docker" "github.com/IceWhaleTech/CasaOS/pkg/docker"
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp" upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper" ip_helper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
oasis_err2 "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" port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
"github.com/IceWhaleTech/CasaOS/pkg/utils/random" "github.com/IceWhaleTech/CasaOS/pkg/utils/random"
@@ -27,7 +29,6 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"github.com/tidwall/gjson"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@@ -143,10 +144,8 @@ func SpeedPush(c *gin.Context) {
// @Param env formData string false "环境变量" // @Param env formData string false "环境变量"
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /app/install/{id} [post] // @Router /app/install [post]
func InstallApp(c *gin.Context) { func InstallApp(c *gin.Context) {
appId := c.Param("id")
language := c.GetHeader("Language")
var appInfo model.ServerAppList var appInfo model.ServerAppList
m := model.CustomizationPostData{} m := model.CustomizationPostData{}
c.BindJSON(&m) c.BindJSON(&m)
@@ -154,7 +153,30 @@ func InstallApp(c *gin.Context) {
const CUSTOM = "custom" const CUSTOM = "custom"
var dockerImage string var dockerImage string
var dockerImageVersion string var dockerImageVersion string
//检查端口
//check app name is exist
if len(m.Protocol) == 0 {
m.Protocol = "http"
}
if m.Origin != "custom" {
oldName := m.Label
for i := 0; true; i++ {
if i != 0 {
m.Label = oldName + "-" + strconv.Itoa(i)
}
if _, err := service.MyService.Docker().DockerListByName(m.Label); err != nil {
break
}
}
} else {
if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
return
}
}
//check port
if len(m.PortMap) > 0 && m.PortMap != "0" { if len(m.PortMap) > 0 && m.PortMap != "0" {
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) //c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
portMap, _ := strconv.Atoi(m.PortMap) portMap, _ := strconv.Atoi(m.PortMap)
@@ -175,21 +197,6 @@ func InstallApp(c *gin.Context) {
dockerImage = m.Image dockerImage = m.Image
dockerImageVersion = "latest" dockerImageVersion = "latest"
} }
if m.Origin != "custom" {
appInfo = service.MyService.Casa().GetServerAppInfo(appId, "", language)
} else {
appInfo.Title = m.Label
appInfo.Description = m.Description
appInfo.Icon = m.Icon
appInfo.ScreenshotLink = model.Strings{}
appInfo.NetworkModel = m.NetworkModel
appInfo.Tags = model.Strings{}
appInfo.Tagline = ""
appInfo.Index = m.Index
}
for _, u := range m.Ports { for _, u := range m.Ports {
@@ -248,19 +255,19 @@ func InstallApp(c *gin.Context) {
// //
//} //}
id := uuid.NewV4().String() id := uuid.NewV4().String()
m.CustomId = id
var relyMap = make(map[string]string) var relyMap = make(map[string]string)
go func() { go func() {
installLog := model2.AppNotify{} // installLog := model2.AppNotify{}
installLog.State = 0 // installLog.State = 0
installLog.CustomId = id // installLog.CustomId = m.Label
installLog.Message = "installing rely" // installLog.Message = "installing rely"
installLog.Class = types.NOTIFY_APP // installLog.Class = types.NOTIFY_APP
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT // installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10) // installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10) // installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
installLog.Id = uuid.NewV4().String() // installLog.Id = uuid.NewV4().String()
service.MyService.Notify().AddLog(installLog) // service.MyService.Notify().AddLog(installLog)
if m.Origin != "custom" { if m.Origin != "custom" {
for _, plugin := range appInfo.Plugins { for _, plugin := range appInfo.Plugins {
if plugin == "mysql" { if plugin == "mysql" {
@@ -281,7 +288,7 @@ func InstallApp(c *gin.Context) {
rely.Type = types.RELY_TYPE_MYSQL rely.Type = types.RELY_TYPE_MYSQL
rely.ContainerId = mysqlContainerId rely.ContainerId = mysqlContainerId
rely.CustomId = mid rely.CustomId = mid
rely.ContainerCustomId = id rely.ContainerCustomId = m.Label
var mysqlConfig model2.MysqlConfigs var mysqlConfig model2.MysqlConfigs
//结构体转换 //结构体转换
@@ -293,24 +300,26 @@ func InstallApp(c *gin.Context) {
} else { } else {
docker_base.MysqlDelete(mysqlContainerId) docker_base.MysqlDelete(mysqlContainerId)
installLog.State = 0 // installLog.State = 0
installLog.Message = err.Error() // installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog) // service.MyService.Notify().UpdateLog(installLog)
} }
} }
} }
} }
installLog.Message = "pulling"
service.MyService.Notify().UpdateLog(installLog)
// step下载镜像 // step下载镜像
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog) err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, m.Icon, m.Label)
if err != nil { if err != nil {
installLog.State = 0 notify := notify.Application{}
installLog.Message = err.Error() notify.Icon = m.Icon
installLog.Type = types.NOTIFY_TYPE_ERROR notify.Name = m.Label
service.MyService.Notify().UpdateLog(installLog) notify.State = "PULLING"
notify.Type = "INSTALL"
notify.Success = false
notify.Finished = false
notify.Message = err.Error()
service.MyService.Notify().SendInstallAppBySocket(notify)
return return
} }
@@ -318,60 +327,57 @@ func InstallApp(c *gin.Context) {
time.Sleep(time.Second) time.Sleep(time.Second)
} }
//if { _, err = service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
//}
//step创建容器
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
// if err != nil {
// //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
// installLog.State = 0
// installLog.Speed = 75
// installLog.Type = types.NOTIFY_TYPE_ERROR
// installLog.Message = err.Error()
// service.MyService.Notify().UpdateLog(installLog)
// return
// }
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
installLog.Name = appInfo.Title
installLog.Icon = appInfo.Icon
if err != nil { if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100) //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
installLog.State = 0 notify := notify.Application{}
installLog.Type = types.NOTIFY_TYPE_ERROR notify.Icon = m.Icon
installLog.Message = err.Error() notify.Name = m.Label
service.MyService.Notify().UpdateLog(installLog) notify.State = "STARTING"
notify.Type = "INSTALL"
notify.Success = false
notify.Finished = false
notify.Message = err.Error()
service.MyService.Notify().SendInstallAppBySocket(notify)
return return
} else { } else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100) notify := notify.Application{}
installLog.Message = "starting" notify.Icon = m.Icon
service.MyService.Notify().UpdateLog(installLog) notify.Name = m.Label
notify.State = "STARTING"
notify.Type = "INSTALL"
notify.Success = true
notify.Finished = false
service.MyService.Notify().SendInstallAppBySocket(notify)
} }
// echo -e "hellow\nworld" >> // echo -e "hellow\nworld" >>
//step启动容器 //step启动容器
err = service.MyService.Docker().DockerContainerStart(id) err = service.MyService.Docker().DockerContainerStart(m.Label)
if err != nil { if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100) //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
installLog.State = 0 notify := notify.Application{}
installLog.Type = types.NOTIFY_TYPE_ERROR notify.Icon = m.Icon
installLog.Message = err.Error() notify.Name = m.Label
service.MyService.Notify().UpdateLog(installLog) notify.State = "STARTING"
notify.Type = "INSTALL"
notify.Success = false
notify.Finished = false
notify.Message = err.Error()
service.MyService.Notify().SendInstallAppBySocket(notify)
return return
} else { } else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100) // if m.Origin != CUSTOM {
if m.Origin != CUSTOM { // installLog.Message = "setting upnp"
installLog.Message = "setting upnp" // } else {
} else { // installLog.Message = "nearing completion"
installLog.Message = "nearing completion" // }
} // service.MyService.Notify().UpdateLog(installLog)
service.MyService.Notify().UpdateLog(installLog)
} }
if m.Origin != CUSTOM { if m.Origin != CUSTOM {
//step:启动upnp //step:enable upnp
if m.EnableUPNP { if m.EnableUPNP {
upnp, err := upnp2.Gateway() upnp, err := upnp2.Gateway()
if err == nil { if err == nil {
@@ -403,94 +409,55 @@ func InstallApp(c *gin.Context) {
} }
} }
if err != nil { // if err != nil {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100) // //service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
installLog.State = 0 // installLog.State = 0
installLog.Type = types.NOTIFY_TYPE_ERROR // installLog.Type = types.NOTIFY_TYPE_ERROR
installLog.Message = err.Error() // installLog.Message = err.Error()
service.MyService.Notify().UpdateLog(installLog) // service.MyService.Notify().UpdateLog(installLog)
} else { // } else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100) // //service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
installLog.Message = "checking" // installLog.Message = "checking"
service.MyService.Notify().UpdateLog(installLog) // service.MyService.Notify().UpdateLog(installLog)
} // }
} }
} }
//step: 启动成功 检查容器状态确认启动成功 //step: 启动成功 检查容器状态确认启动成功
container, err := service.MyService.Docker().DockerContainerInfo(id) container, err := service.MyService.Docker().DockerContainerInfo(m.Label)
if err != nil && container.ContainerJSONBase.State.Running { if err != nil && container.ContainerJSONBase.State.Running {
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100) notify := notify.Application{}
installLog.State = 0 notify.Icon = m.Icon
installLog.Type = types.NOTIFY_TYPE_ERROR notify.Name = m.Label
installLog.Message = err.Error() notify.State = "INSTALLED"
service.MyService.Notify().UpdateLog(installLog) notify.Type = "INSTALL"
notify.Success = false
notify.Finished = true
notify.Message = err.Error()
service.MyService.Notify().SendInstallAppBySocket(notify)
return return
} else { } else {
//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100) notify := notify.Application{}
installLog.Message = "installed" notify.Icon = m.Icon
service.MyService.Notify().UpdateLog(installLog) notify.Name = m.Label
notify.State = "INSTALLED"
notify.Type = "INSTALL"
notify.Success = true
notify.Finished = true
service.MyService.Notify().SendInstallAppBySocket(notify)
} }
rely := model.MapStrings{}
copier.Copy(&rely, &relyMap)
// if m.Origin != "custom" { // if m.Origin != "custom" {
// for i := 0; i < len(m.Volumes); i++ { // for i := 0; i < len(m.Volumes); i++ {
// m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path) // m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
// } // }
// } // }
//service.MyService.App().SaveContainer(md)
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,
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,
//Port: m.Port,
PortMap: m.PortMap,
Label: m.Label,
EnableUPNP: m.EnableUPNP,
Ports: string(portsStr),
Envs: string(envsStr),
Volumes: string(volumesStr),
Position: m.Position,
NetModel: appInfo.NetworkModel,
Restart: m.Restart,
CpuShares: m.CpuShares,
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),
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 config.CasaOSGlobalVariables.AppChange = true
}() }()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m.Label})
} }
@@ -691,35 +658,36 @@ func UnInstallApp(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
info := service.MyService.App().GetUninstallInfo(appId) //info := service.MyService.App().GetUninstallInfo(appId)
info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
//step停止容器 //step停止容器
err := service.MyService.Docker().DockerContainerStop(appId) err = service.MyService.Docker().DockerContainerStop(appId)
if err != nil { 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()}) 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 return
} }
//step删除容器
err = service.MyService.Docker().DockerContainerRemove(appId, false) err = service.MyService.Docker().DockerContainerRemove(appId, false)
if err != nil { 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()}) 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 return
} }
//存在镜像正在使用的情况 // stepremove image
// step删除镜像 service.MyService.Docker().DockerImageRemove(info.Config.Image)
service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)
//step: 删除本地数据
service.MyService.App().RemoveContainerById(appId)
if info.Origin != "custom" {
if info.Config.Labels["origin"] != "custom" {
//step: 删除文件夹 //step: 删除文件夹
vol := gjson.Get(info.Volumes, "#.host") for _, v := range info.Mounts {
for _, v := range vol.Array() { if strings.Contains(v.Source, info.Name) {
if strings.Contains(v.String(), appId) { path := filepath.Join(strings.Split(v.Source, info.Name)[0], info.Name)
service.MyService.App().DelAppConfigDir(v.String()) service.MyService.App().DelAppConfigDir(path)
} }
} }
@@ -764,13 +732,14 @@ func UnInstallApp(c *gin.Context) {
//} //}
} }
config.CasaOSGlobalVariables.AppChange = true config.CasaOSGlobalVariables.AppChange = true
unInstallLog := model2.AppNotify{} notify := notify.Application{}
unInstallLog.State = 0 notify.Icon = info.Config.Labels["icon"]
unInstallLog.CustomId = appId notify.Name = strings.ReplaceAll(info.Name, "/", "")
unInstallLog.Message = "uninstalled" notify.State = "FINISHED"
unInstallLog.Id = uuid.NewV4().String() notify.Type = "UNINSTALL"
service.MyService.Notify().UpdateLog(unInstallLog) notify.Success = true
notify.Finished = true
service.MyService.Notify().SendUninstallAppBySocket(notify)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
@@ -793,7 +762,7 @@ func ChangAppState(c *gin.Context) {
} else if state == "start" { } else if state == "start" {
err = service.MyService.Docker().DockerContainerStart(appId) err = service.MyService.Docker().DockerContainerStart(appId)
} else if state == "restart" { } else if state == "restart" {
err = service.MyService.Docker().DockerContainerStop(appId) service.MyService.Docker().DockerContainerStop(appId)
err = service.MyService.Docker().DockerContainerStart(appId) err = service.MyService.Docker().DockerContainerStart(appId)
} }
if err != nil { if err != nil {
@@ -822,20 +791,6 @@ func ContainerLog(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: log})
} }
// @Summary 获取安装进度
// @Produce application/json
// @Accept application/json
// @Tags app
// @Param id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/speed/{id} [get]
func GetInstallSpeed(c *gin.Context) {
id := c.Param("id")
b := service.MyService.Notify().GetLog(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: b})
}
// @Summary 获取容器状态 // @Summary 获取容器状态
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -889,19 +844,23 @@ func UpdateSetting(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
var cpd model.CustomizationPostData //var cpd model.CustomizationPostData
copier.Copy(&cpd, &m) //copier.Copy(&cpd, &m)
appInfo := service.MyService.App().GetAppDBInfo(id) //appInfo := service.MyService.App().GetAppDBInfo(id)
//info, err := service.MyService.Docker().DockerContainerInfo(id)
var containerId string // //check app name is exist
containerId = appInfo.ContainerId // if _, err := service.MyService.Docker().DockerListByName(m.Label); err == nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR_APP_NAME_EXIST, Message: oasis_err2.GetMsg(oasis_err2.ERROR_APP_NAME_EXIST)})
// return
// }
service.MyService.Docker().DockerContainerStop(id) service.MyService.Docker().DockerContainerStop(id)
portMap, _ := strconv.Atoi(m.PortMap) portMap, _ := strconv.Atoi(m.PortMap)
if !port2.IsPortAvailable(portMap, "tcp") { if !port2.IsPortAvailable(portMap, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
return return
} }
@@ -911,77 +870,54 @@ func UpdateSetting(c *gin.Context) {
if u.Protocol == "udp" { if u.Protocol == "udp" {
t, _ := strconv.Atoi(u.CommendPort) t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") { if !port2.IsPortAvailable(t, "udp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return return
} }
} else if u.Protocol == "tcp" { } else if u.Protocol == "tcp" {
te, _ := strconv.Atoi(u.CommendPort) te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") { if !port2.IsPortAvailable(te, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return return
} }
} else if u.Protocol == "both" { } else if u.Protocol == "both" {
t, _ := strconv.Atoi(u.CommendPort) t, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(t, "udp") { if !port2.IsPortAvailable(t, "udp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return return
} }
te, _ := strconv.Atoi(u.CommendPort) te, _ := strconv.Atoi(u.CommendPort)
if !port2.IsPortAvailable(te, "tcp") { if !port2.IsPortAvailable(te, "tcp") {
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
return return
} }
} }
} }
service.MyService.Docker().DockerContainerUpdateName(id, id)
//service.MyService.Docker().DockerContainerRemove(id, true)
//如果容器端口均未修改,这不进行处理 containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m, m.NetworkModel)
portsStr, _ := json2.Marshal(m.Ports) if err != nil {
service.MyService.Docker().DockerContainerUpdateName(m.Label, id)
envsStr, _ := json2.Marshal(m.Envs) service.MyService.Docker().DockerContainerStart(id)
volumesStr, _ := json2.Marshal(m.Volumes) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
devicesStr, _ := json2.Marshal(m.Devices) return
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
// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetModel)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
// return
// }
containerId, err = service.MyService.Docker().DockerContainerCreate(appInfo.Image+":"+appInfo.Version, newUUid, cpd, m.NetworkModel)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
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
}
service.MyService.Docker().DockerContainerUpdateName(appInfo.CustomId, newUUid)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
} else if !reflect.DeepEqual(string(devicesStr), appInfo.Devices) || m.CpuShares != appInfo.CpuShares || m.Memory != appInfo.Memory || m.Restart != appInfo.Restart {
service.MyService.Docker().DockerContainerUpdate(cpd, id)
} }
// echo -e "hellow\nworld" >>
//step启动容器
err = service.MyService.Docker().DockerContainerStart(containerId)
err := service.MyService.Docker().DockerContainerStart(id)
if err != nil { if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return return
} }
service.MyService.Docker().DockerContainerRemove(id, true)
//更新upnp //更新upnp
if m.Origin != CUSTOM { if m.Origin != CUSTOM {
//if appInfo.EnableUPNP != appInfo.EnableUPNP { //if appInfo.EnableUPNP != appInfo.EnableUPNP {
@@ -1047,31 +983,96 @@ func UpdateSetting(c *gin.Context) {
//} //}
} }
appInfo.ContainerId = containerId //service.MyService.App().UpdateApp(appInfo)
appInfo.PortMap = m.PortMap
appInfo.Label = m.Label
appInfo.Index = m.Index
appInfo.Ports = string(portsStr)
appInfo.Envs = string(envsStr)
appInfo.Icon = m.Icon
appInfo.Volumes = string(volumesStr)
appInfo.Devices = string(devicesStr)
appInfo.NetModel = m.NetworkModel
appInfo.Position = m.Position
appInfo.EnableUPNP = m.EnableUPNP
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)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary update app version
// @Produce application/json
// @Accept multipart/form-data
// @Tags app
// @Param id path string true "容器id"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/update/{id} [put]
func PutAppUpdate(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
}
inspect, err := service.MyService.Docker().DockerContainerInfo(id)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
imageLatest := strings.Split(inspect.Config.Image, ":")[0] + ":latest"
err = service.MyService.Docker().DockerPullImage(imageLatest, "", "")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
service.MyService.Docker().DockerContainerStop(id)
service.MyService.Docker().DockerContainerUpdateName(id, id)
//service.MyService.Docker().DockerContainerRemove(id, true)
inspect.Image = imageLatest
inspect.Config.Image = imageLatest
containerId, err := service.MyService.Docker().DockerContainerCopyCreate(inspect)
if err != nil {
service.MyService.Docker().DockerContainerUpdateName(inspect.Name, id)
service.MyService.Docker().DockerContainerStart(id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
//step启动容器
err = service.MyService.Docker().DockerContainerStart(containerId)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
return
}
service.MyService.Docker().DockerContainerRemove(id, true)
delete(service.NewVersionApp, id)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary get app index
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/order [get]
func GetAppOrder(c *gin.Context) {
data := service.MyService.System().GetAppOrderFile()
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(data)})
}
// @Summary update app index
// @Produce application/json
// @Accept application/json
// @Tags app
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /app/order [post]
func PostAppOrder(c *gin.Context) {
data := c.PostForm("data")
service.MyService.System().UpAppOrderFile(data)
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
Data: json.RawMessage(data),
})
}
// @Summary 获取容器详情 // @Summary 获取容器详情
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -1109,7 +1110,7 @@ func ContainerInfo(c *gin.Context) {
data := make(map[string]interface{}, 5) data := make(map[string]interface{}, 5)
data["app"] = appInfo data["app"] = appInfo
data["cpu"] = cpuModel data["cpu"] = cpuModel
data["memory"] = service.MyService.ZiMa().GetMemInfo().Total data["memory"] = service.MyService.System().GetMemInfo().Total
data["container"] = json2.RawMessage(containerInfo) data["container"] = json2.RawMessage(containerInfo)
data["info"] = con data["info"] = con
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
@@ -1132,7 +1133,7 @@ func GetDockerInstallConfig(c *gin.Context) {
} }
} }
data["networks"] = list data["networks"] = list
data["memory"] = service.MyService.ZiMa().GetMemInfo() data["memory"] = service.MyService.System().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
} }
@@ -1160,58 +1161,113 @@ func ContainerRelyInfo(c *gin.Context) {
// @Router /app/update/{id}/info [get] // @Router /app/update/{id}/info [get]
func ContainerUpdateInfo(c *gin.Context) { func ContainerUpdateInfo(c *gin.Context) {
appId := c.Param("id") appId := c.Param("id")
appInfo := service.MyService.App().GetAppDBInfo(appId) //appInfo := service.MyService.App().GetAppDBInfo(appId)
info, err := service.MyService.Docker().DockerContainerInfo(appId) info, err := service.MyService.Docker().DockerContainerInfo(appId)
if err != nil { if err != nil {
//todo 需要自定义错误
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: err.Error()})
return return
} }
var port model.PortArray var port model.PortArray
json2.Unmarshal([]byte(appInfo.Ports), &port) // json2.Unmarshal([]byte(appInfo.Ports), &port)
var envs model.EnvArray for k, v := range info.HostConfig.PortBindings {
json2.Unmarshal([]byte(appInfo.Envs), &envs) temp := model.PortMap{
CommendPort: v[0].HostPort,
ContainerPort: k.Port(),
var vol model.PathArray Protocol: k.Proto(),
json2.Unmarshal([]byte(appInfo.Volumes), &vol) }
port = append(port, temp)
for i := 0; i < len(vol); i++ {
vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
} }
var dir model.PathArray var envs model.EnvArray
json2.Unmarshal([]byte(appInfo.Devices), &dir) // json2.Unmarshal([]byte(appInfo.Envs), &envs)
showENV := info.Config.Labels["show_env"]
showENVList := strings.Split(showENV, ",")
showENVMap := make(map[string]string)
if len(showENVList) > 1 {
for _, name := range showENVList {
showENVMap[name] = "1"
}
}
for _, v := range info.Config.Env {
if len(showENVList) > 1 {
if _, ok := showENVMap[strings.Split(v, "=")[0]]; ok {
temp := model.Env{
Name: strings.Split(v, "=")[0],
Value: strings.Split(v, "=")[1],
}
envs = append(envs, temp)
}
} else {
temp := model.Env{
Name: strings.Split(v, "=")[0],
Value: strings.Split(v, "=")[1],
}
envs = append(envs, temp)
}
}
var vol model.PathArray
// json2.Unmarshal([]byte(appInfo.Volumes), &vol)
for i := 0; i < len(info.Mounts); i++ {
temp := model.PathMap{
Path: strings.ReplaceAll(info.Mounts[i].Source, "$AppID", info.Name),
ContainerPath: info.Mounts[i].Destination,
}
vol = append(vol, temp)
}
var driver model.PathArray
var cmd []string
json2.Unmarshal([]byte(appInfo.Cmd), &cmd)
var capAdd []string
json2.Unmarshal([]byte(appInfo.CapAdd), &capAdd)
//volumesStr, _ := json2.Marshal(m.Volumes) //volumesStr, _ := json2.Marshal(m.Volumes)
//devicesStr, _ := json2.Marshal(m.Devices) //devicesStr, _ := json2.Marshal(m.Devices)
for _, v := range info.HostConfig.Resources.Devices {
temp := model.PathMap{
Path: v.PathOnHost,
ContainerPath: v.PathInContainer,
}
driver = append(driver, temp)
}
m := model.CustomizationPostData{} m := model.CustomizationPostData{}
m.Index = appInfo.Index m.Icon = info.Config.Labels["icon"]
m.Icon = appInfo.Icon
m.Ports = port m.Ports = port
m.Image = appInfo.Image + ":" + appInfo.Version m.Image = info.Config.Image
m.Origin = appInfo.Origin m.Origin = info.Config.Labels["origin"]
m.NetworkModel = appInfo.NetModel if len(m.Origin) == 0 {
m.Description = appInfo.Description m.Origin = "local"
m.Label = appInfo.Label }
m.PortMap = appInfo.PortMap m.NetworkModel = string(info.HostConfig.NetworkMode)
m.Devices = dir //appInfo.Devices m.Description = info.Config.Labels["desc"]
m.Label = strings.ReplaceAll(info.Name, "/", "")
m.PortMap = info.Config.Labels["web"]
m.Devices = driver
m.Envs = envs m.Envs = envs
m.Memory = info.HostConfig.Memory >> 20 m.Memory = info.HostConfig.Memory >> 20
m.CpuShares = info.HostConfig.CPUShares m.CpuShares = info.HostConfig.CPUShares
m.Volumes = vol //appInfo.Volumes m.Volumes = vol //appInfo.Volumes
m.Restart = info.HostConfig.RestartPolicy.Name m.Restart = info.HostConfig.RestartPolicy.Name
m.EnableUPNP = appInfo.EnableUPNP m.EnableUPNP = false
m.Position = appInfo.Position m.Index = info.Config.Labels["index"]
m.Position = false
m.CustomId = info.Config.Labels["custom_id"]
m.Host = info.Config.Labels["host"]
if len(m.CustomId) == 0 {
m.CustomId = uuid.NewV4().String()
}
m.CapAdd = info.HostConfig.CapAdd
m.Cmd = info.Config.Cmd
m.HostName = info.Config.Hostname
m.Privileged = info.HostConfig.Privileged
m.CapAdd = capAdd m.Protocol = info.Config.Labels["protocol"]
m.Cmd = cmd if m.Protocol == "" {
m.HostName = appInfo.HostName m.Protocol = "http"
m.Privileged = appInfo.Privileged }
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
} }

View File

@@ -6,19 +6,25 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"net/url"
url2 "net/url" url2 "net/url"
"os" "os"
"path" "path"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err" oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/spf13/afero" uuid "github.com/satori/go.uuid"
) )
func downloadReadFile(c *gin.Context) { func downloadReadFile(c *gin.Context) {
@@ -47,24 +53,6 @@ func downloadReadFile(c *gin.Context) {
} }
} }
func downloadWriteFile(c *gin.Context) {
//写文件
var filename = "./output1.csv"
file, err := os.Create(filename) //创建文件
if err != nil {
c.String(400, err.Error())
return
}
buf := bufio.NewWriter(file) //创建新的 Writer 对象
buf.WriteString("test")
buf.Flush()
defer file.Close()
//返回文件流
c.File(filename)
}
// @Summary 读取文件 // @Summary 读取文件
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -134,82 +122,106 @@ func GetLocalFile(c *gin.Context) {
// @Accept application/json // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path query string true "path of file" // @Param t query string false "Compression format" Enums(zip,tar,targz)
// @Param files query string true "file list eg: filename1,filename2,filename3 "
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/download [get] // @Router /file/download [get]
func GetDownloadFile(c *gin.Context) { func GetDownloadFile(c *gin.Context) {
filePath := c.Query("path")
if len(filePath) == 0 { t := c.Query("t")
files := c.Query("files")
if len(files) == 0 {
c.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.INVALID_PARAMS, Success: oasis_err2.INVALID_PARAMS,
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS), Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
}) })
return return
} }
if !file.Exists(filePath) { list := strings.Split(files, ",")
c.JSON(http.StatusOK, model.Result{ for _, v := range list {
Success: oasis_err2.FILE_DOES_NOT_EXIST, if !file.Exists(v) {
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST), c.JSON(http.StatusOK, model.Result{
}) Success: oasis_err2.FILE_DOES_NOT_EXIST,
return Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
})
return
}
} }
//打开文件
fileTmp, _ := os.Open(filePath)
defer fileTmp.Close()
//获取文件的名称
fileName := path.Base(filePath)
c.Header("Content-Type", "application/octet-stream") c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
c.Header("Content-Transfer-Encoding", "binary") c.Header("Content-Transfer-Encoding", "binary")
c.Header("Cache-Control", "no-cache") c.Header("Cache-Control", "no-cache")
// handles only single files not folders and multiple files
if len(list) == 1 {
c.File(filePath) filePath := list[0]
} info, err := os.Stat(filePath)
if err != nil {
c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.FILE_DOES_NOT_EXIST,
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST),
})
return
}
if !info.IsDir() {
// @Summary download //打开文件
// @Produce application/json fileTmp, _ := os.Open(filePath)
// @Accept application/json defer fileTmp.Close()
// @Tags file
// @Security ApiKeyAuth //获取文件的名称
// @Param path query string true "path of file" fileName := path.Base(filePath)
// @Success 200 {string} string "ok" c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
// @Router /file/new/download [get] c.File(filePath)
func GetFileDownloadNew(c *gin.Context) { return
filePath := c.Query("path") }
if len(filePath) == 0 { }
extension, ar, err := file.GetCompressionAlgorithm(t)
if err != nil {
c.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.INVALID_PARAMS, Success: oasis_err2.INVALID_PARAMS,
Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS), Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS),
}) })
return return
} }
if !file.Exists(filePath) {
err = ar.Create(c.Writer)
if err != nil {
c.JSON(http.StatusOK, model.Result{ c.JSON(http.StatusOK, model.Result{
Success: oasis_err2.FILE_DOES_NOT_EXIST, Success: oasis_err.ERROR,
Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST), Message: oasis_err2.GetMsg(oasis_err2.ERROR),
Data: err.Error(),
}) })
return return
} }
//打开文件 defer ar.Close()
fileStat, _ := os.Stat(filePath) commonDir := file.CommonPrefix(filepath.Separator, list...)
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)) currentPath := filepath.Base(commonDir)
//在线
name := "_" + currentPath
name += extension
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name))
for _, fname := range list {
err = file.AddFile(ar, fname, commonDir)
if err != nil {
log.Printf("Failed to archive %s: %v", fname, err)
}
}
}
func GetDownloadSingleFile(c *gin.Context) {
filePath := c.Param("path")
fileTmp, _ := os.Open(filePath)
defer fileTmp.Close()
fileName := path.Base(filePath)
//c.Header("Content-Disposition", "inline") //c.Header("Content-Disposition", "inline")
// extraHeaders := map[string]string{ c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url2.PathEscape(fileName))
// "Content-Disposition": `attachment; filename="` + url2.PathEscape(fileName) + `"`, c.File(filePath)
// }
//c.Header("Cache-Control", "private")
//c.Header("Content-Type", "application/octet-stream")
http.ServeContent(c.Writer, c.Request, fileStat.Name(), fileStat.ModTime(), fileT)
} }
// @Summary 获取目录列表 // @Summary 获取目录列表
@@ -224,10 +236,10 @@ func DirPath(c *gin.Context) {
path := c.DefaultQuery("path", "") path := c.DefaultQuery("path", "")
info := service.MyService.ZiMa().GetDirPath(path) info := service.MyService.ZiMa().GetDirPath(path)
if path == "/DATA/AppData" { if path == "/DATA/AppData" {
list := service.MyService.App().GetAllDBApps() list := service.MyService.Docker().DockerContainerList()
apps := make(map[string]string, len(list)) apps := make(map[string]string, len(list))
for _, v := range list { for _, v := range list {
apps[v.CustomId] = v.Label apps[strings.ReplaceAll(v.Names[0], "/", "")] = strings.ReplaceAll(v.Names[0], "/", "")
} }
for i := 0; i < len(info); i++ { for i := 0; i < len(info); i++ {
if v, ok := apps[info[i].Name]; ok { if v, ok := apps[info[i].Name]; ok {
@@ -263,7 +275,30 @@ func DirPath(c *gin.Context) {
} }
} }
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: info}) //Hide the files or folders in operation
fileQueue := make(map[string]string)
if len(service.OpStrArr) > 0 {
for _, v := range service.OpStrArr {
v, ok := service.FileQueue.Load(v)
if !ok {
continue
}
vt := v.(model.FileOperate)
for _, i := range vt.Item {
lastPath := i.From[strings.LastIndex(i.From, "/")+1:]
fileQueue[vt.To+"/"+lastPath] = i.From
}
}
}
pathList := []model.Path{}
for i := 0; i < len(info); i++ {
if _, ok := fileQueue[info[i].Path]; !ok {
pathList = append(pathList, info[i])
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: pathList})
} }
// @Summary rename file or dir // @Summary rename file or dir
@@ -271,13 +306,15 @@ func DirPath(c *gin.Context) {
// @Accept application/json // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param oldpath formData string true "path of old" // @Param oldpath body string true "path of old"
// @Param newpath formData string true "path of new" // @Param newpath body string true "path of new"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/rename [put] // @Router /file/rename [put]
func RenamePath(c *gin.Context) { func RenamePath(c *gin.Context) {
op := c.PostForm("oldpath") json := make(map[string]string)
np := c.PostForm("newpath") c.BindJSON(&json)
op := json["oldpath"]
np := json["newpath"]
if len(op) == 0 || len(np) == 0 { if len(op) == 0 || len(np) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
@@ -288,45 +325,59 @@ func RenamePath(c *gin.Context) {
// @Summary create folder // @Summary create folder
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path formData string true "path of folder" // @Param path body string true "path of folder"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/mkdir [post] // @Router /file/mkdir [post]
func MkdirAll(c *gin.Context) { func MkdirAll(c *gin.Context) {
path := c.PostForm("path") json := make(map[string]string)
c.BindJSON(&json)
path := json["path"]
var code int var code int
if len(path) == 0 { if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
// decodedPath, err := url.QueryUnescape(path)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
code, _ = service.MyService.ZiMa().MkdirAll(path) code, _ = service.MyService.ZiMa().MkdirAll(path)
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)}) c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
} }
// @Summary create file // @Summary create file
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path formData string false "路径" // @Param path body string true "path of folder (path need to url encode)"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/create [post] // @Router /file/create [post]
func PostCreateFile(c *gin.Context) { func PostCreateFile(c *gin.Context) {
path := c.PostForm("path") json := make(map[string]string)
c.BindJSON(&json)
path := json["path"]
var code int var code int
if len(path) == 0 { if len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
// decodedPath, err := url.QueryUnescape(path)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
code, _ = service.MyService.ZiMa().CreateFile(path) code, _ = service.MyService.ZiMa().CreateFile(path)
c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)}) c.JSON(http.StatusOK, model.Result{Success: code, Message: oasis_err2.GetMsg(code)})
} }
// @Summary upload file // @Summary upload file
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path formData string false "file path" // @Param path formData string false "file path"
@@ -342,7 +393,7 @@ func GetFileUpload(c *gin.Context) {
path := c.Query("path") path := c.Query("path")
dirPath := "" dirPath := ""
hash := file.GetHashByContent([]byte(fileName)) hash := file.GetHashByContent([]byte(fileName))
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/" tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
if fileName != relative { if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName) dirPath = strings.TrimSuffix(relative, fileName)
tempDir += dirPath tempDir += dirPath
@@ -381,7 +432,7 @@ func PostFileUpload(c *gin.Context) {
c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(oasis_err2.INVALID_PARAMS, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/" tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
if fileName != relative { if fileName != relative {
dirPath = strings.TrimSuffix(relative, fileName) dirPath = strings.TrimSuffix(relative, fileName)
@@ -431,94 +482,177 @@ func PostFileUpload(c *gin.Context) {
// @Summary copy or move file // @Summary copy or move file
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param from formData string true "from path" // @Param body body model.FileOperate true "type:move,copy"
// @Param to formData string true "to path"
// @Param type formData string true "action" Enums(move,copy)
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/operate [post] // @Router /file/operate [post]
func PostOperateFileOrDir(c *gin.Context) { func PostOperateFileOrDir(c *gin.Context) {
from := c.PostForm("from")
to := c.PostForm("to") list := model.FileOperate{}
t := c.PostForm("type") c.BindJSON(&list)
if len(from) == 0 || len(t) == 0 || len(to) == 0 {
if len(list.Item) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return return
} }
if t == "move" { if list.To == list.Item[0].From[:strings.LastIndex(list.Item[0].From, "/")] {
lastPath := from[strings.LastIndex(from, "/")+1:] c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SOURCE_DES_SAME, Message: oasis_err2.GetMsg(oasis_err2.SOURCE_DES_SAME)})
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 return
} }
var total int64 = 0
for i := 0; i < len(list.Item); i++ {
size, err := file.GetFileOrDirSize(list.Item[i].From)
if err != nil {
continue
}
list.Item[i].Size = size
total += size
}
list.TotalSize = total
list.ProcessedSize = 0
uid := uuid.NewV4().String()
service.FileQueue.Store(uid, list)
service.OpStrArr = append(service.OpStrArr, uid)
if len(service.OpStrArr) == 1 {
go service.ExecOpFile()
go service.CheckFileStatus()
go service.MyService.Notify().SendFileOperateNotify(false)
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary delete file // @Summary delete file
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path query string true "path" // @Param body body string true "paths eg ["/a/b/c","/d/e/f"]"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/delete [delete] // @Router /file/delete [delete]
func DeleteFile(c *gin.Context) { func DeleteFile(c *gin.Context) {
path := c.Query("path")
//err := os.Remove(path) paths := []string{}
err := os.RemoveAll(path) c.BindJSON(&paths)
if err != nil { if len(paths) == 0 {
fmt.Println(err) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
return return
} }
// path := c.Query("path")
// paths := strings.Split(path, ",")
for _, v := range paths {
err := os.RemoveAll(v)
if err != nil {
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)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary update file // @Summary update file
// @Produce application/json // @Produce application/json
// @Accept multipart/form-data // @Accept application/json
// @Tags file // @Tags file
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param path formData string true "path" // @Param path body string true "path"
// @Param content formData string true "content" // @Param content body string true "content"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /file/update [put] // @Router /file/update [put]
func PutFileContent(c *gin.Context) { func PutFileContent(c *gin.Context) {
path := c.PostForm("path")
content := c.PostForm("content") fi := model.FileUpdate{}
if !file.Exists(path) { c.BindJSON(&fi)
c.JSON(oasis_err2.FILE_ALREADY_EXISTS, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
// path := c.PostForm("path")
// content := c.PostForm("content")
if !file.Exists(fi.FilePath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return return
} }
//err := os.Remove(path) //err := os.Remove(path)
err := os.RemoveAll(path) err := os.RemoveAll(fi.FilePath)
if err != nil { 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}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DELETE_ERROR, Message: oasis_err2.GetMsg(oasis_err2.FILE_DELETE_ERROR), Data: err})
return return
} }
err = file.CreateFileAndWriteContent(path, content) err = file.CreateFileAndWriteContent(fi.FilePath, fi.FileContent)
if err != nil { 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}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err})
return return
} }
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary image thumbnail/original image
// @Produce application/json
// @Accept application/json
// @Tags file
// @Security ApiKeyAuth
// @Param path query string true "path"
// @Param type query string false "original,thumbnail" Enums(original,thumbnail)
// @Success 200 {string} string "ok"
// @Router /file/image [get]
func GetFileImage(c *gin.Context) {
t := c.Query("type")
path := c.Query("path")
if !file.Exists(path) {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
return
}
if t == "thumbnail" {
f, err := file.GetImage(path, 100, 0)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
c.Writer.WriteString(string(f))
return
}
f, err := os.Open(path)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
c.Writer.WriteString(string(data))
}
func DeleteOperateFileOrDir(c *gin.Context) {
id := c.Param("id")
if id == "0" {
service.FileQueue = sync.Map{}
service.OpStrArr = []string{}
} else {
service.FileQueue.Delete(id)
tempList := []string{}
for _, v := range service.OpStrArr {
if v != id {
tempList = append(tempList, v)
}
}
service.OpStrArr = tempList
}
go service.MyService.Notify().SendFileOperateNotify(true)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}

View File

@@ -1,62 +1,5 @@
package v1 package v1
import ( func aaa() {
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// @Summary websocket 接口,连接成功后发送一个"notify"字符串
// @Produce application/json
// @Accept application/json
// @Tags notify
// @Security ApiKeyAuth
// @Param token path string true "token"
// @Success 200 {string} string "ok"
// @Router /notify/ws [get]
func NotifyWS(c *gin.Context) {
//升级get请求为webSocket协议
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
defer ws.Close()
service.WebSocketConns = append(service.WebSocketConns, ws)
if !service.SocketRun {
service.SocketRun = true
service.SendMeg()
}
for {
mt, message, err := ws.ReadMessage()
fmt.Println(mt, message, err)
}
} }
// @Summary 标记notify已读
// @Produce application/json
// @Accept application/json
// @Tags notify
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @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
// }
fmt.Println(id)
service.MyService.Notify().MarkRead(id, types.NOTIFY_READ)
}

62
route/v1/notify_old.go Normal file
View File

@@ -0,0 +1,62 @@
package v1
import (
"fmt"
"net/http"
"github.com/IceWhaleTech/CasaOS/service"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// @Summary websocket 接口,连接成功后发送一个"notify"字符串
// @Produce application/json
// @Accept application/json
// @Tags notify
// @Security ApiKeyAuth
// @Param token path string true "token"
// @Success 200 {string} string "ok"
// @Router /notify/ws [get]
func NotifyWS(c *gin.Context) {
//升级get请求为webSocket协议
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
defer ws.Close()
service.WebSocketConns = append(service.WebSocketConns, ws)
if !service.SocketRun {
service.SocketRun = true
service.SendMeg()
}
for {
mt, message, err := ws.ReadMessage()
fmt.Println(mt, message, err)
}
}
// @Summary 标记notify已读
// @Produce application/json
// @Accept application/json
// @Tags notify
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @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
// }
fmt.Println(id)
service.MyService.Notify().MarkRead(id, types.NOTIFY_READ)
}

View File

@@ -1,18 +1,24 @@
package v1 package v1
import ( import (
"bytes"
"encoding/base64"
"encoding/gob"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"os"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"time" "time"
natType "github.com/Curtis-Milo/nat-type-identifier-go"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err" oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
"github.com/IceWhaleTech/CasaOS/service" "github.com/IceWhaleTech/CasaOS/service"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
@@ -21,33 +27,6 @@ import (
uuid "github.com/satori/go.uuid" 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 // @Summary Retry the file that failed to download
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -135,7 +114,7 @@ func GetPersonFile(c *gin.Context) {
task.Size = 0 task.Size = 0
task.State = types.DOWNLOADAWAIT task.State = types.DOWNLOADAWAIT
task.Created = time.Now().Unix() task.Created = time.Now().Unix()
task.Type = 0 task.Type = types.PERSONFILEDOWNLOAD
task.LocalPath = localPath task.LocalPath = localPath
if service.MyService.Download().GetDownloadListByPath(task) > 0 { 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)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
@@ -197,7 +176,7 @@ func DeletePersonDownloadFile(c *gin.Context) {
// @Router /person/list [get] // @Router /person/list [get]
func GetPersonDownloadList(c *gin.Context) { func GetPersonDownloadList(c *gin.Context) {
state := c.DefaultQuery("state", "") state := c.DefaultQuery("state", "")
list := service.MyService.Download().GetDownloadListByState(state) list := service.MyService.Download().GetDownloadListByState(state, types.PERSONFILEDOWNLOAD)
//if it is downloading, it need to add 'already' //if it is downloading, it need to add 'already'
for i := 0; i < len(list); i++ { for i := 0; i < len(list); i++ {
if list[i].State == types.DOWNLOADING { if list[i].State == types.DOWNLOADING {
@@ -235,6 +214,79 @@ func PutPersonRemarks(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary edit friend's
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param write formData bool true "write"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/write/{shareid} [put]
func PutPersonWrite(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
write, _ := strconv.ParseBool(c.PostForm("write"))
friend := model2.FriendModel{}
friend.Token = token
friend.Write = write
service.MyService.Friend().EditFriendMark(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary image thumbnail
// @Produce application/json
// @Accept application/json
// @Tags person
// @Param write formData bool true "write"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/image/thumbnail/{shareid} [get]
func GetPersonImageThumbnail(c *gin.Context) {
token := c.Param("shareid")
path := c.Query("path")
_, err := uuid.FromString(token)
if err != nil || len(path) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONIMAGETHUMBNAIL
m.UUId = uuid
img, err := service.Dial(m, false)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
// var buf bytes.Buffer
//err = gob.NewEncoder(&buf).Encode(img.Data)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
var buf bytes.Buffer
err = gob.NewEncoder(&buf).Encode(img.Data)
if err != nil {
c.JSON(http.StatusInternalServerError, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
imageBuffer, _ := base64.StdEncoding.DecodeString(img.Data.(string))
c.Writer.WriteString(string(imageBuffer))
// c.String(http.StatusOK, "data:image/"+filesuffix+";base64,"+img.Data.(string))
//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: img.Data.(string)})
}
// @Summary get my friend list // @Summary get my friend list
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -247,11 +299,39 @@ func GetPersonFriend(c *gin.Context) {
for i := 0; i < len(list); i++ { for i := 0; i < len(list); i++ {
if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 { if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
list[i].OnLine = true list[i].OnLine = true
if ip_helper.HasLocalIP(net.ParseIP(strings.Split(v, ":")[0])) {
list[i].LocalIP = strings.Split(v, ":")[0]
}
} }
} }
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
} }
// @Summary network type detection
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/detection [get]
func GetPersonDetection(c *gin.Context) {
// - Blocked
// - Open Internet
// - Full Cone
// - Symmetric UDP Firewall
// - Restric NAT
// - Restric Port NAT
// - Symmetric NAT
result, err := natType.GetDeterminedNatType(true, 5, "stun.l.google.com")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR), Data: err.Error()})
return
}
//result := service.MyService.Person().GetPersionNetWorkTypeDetection()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: result})
}
// @Summary add friend // @Summary add friend
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -296,10 +376,20 @@ func PostAddPersonFriend(c *gin.Context) {
go service.Dial(message, true) go service.Dial(message, true)
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = v
msg.UUId = uuid.NewV4().String()
service.Dial(msg, true)
friend := model2.FriendModel{} friend := model2.FriendModel{}
friend.Token = v friend.Token = v
friend.Avatar = user.Avatar friend.Avatar = user.Avatar
friend.Block = false friend.Block = false
friend.State = types.FRIENDSTATEWAIT
friend.NickName = user.NickName friend.NickName = user.NickName
friend.Profile = user.Desc friend.Profile = user.Desc
friend.Version = user.Version friend.Version = user.Version
@@ -439,6 +529,17 @@ 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}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.FileSettingInfo.ShareDir})
} }
// @Summary Get the shareid
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/shareid [get]
func GetPersonShareId(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: config.ServerInfo.Token})
}
// @Summary Modify disabled status // @Summary Modify disabled status
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
@@ -489,8 +590,214 @@ func DeletePersonFriend(c *gin.Context) {
// @Tags person // @Tags person
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /person/public [delete] // @Router /person/public [get]
func GetPersonPublic(c *gin.Context) { func GetPersonPublic(c *gin.Context) {
list := service.MyService.Casa().GetPersonPublic() list := service.MyService.Casa().GetPersonPublic()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
} }
// @Summary upload file to friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Param path formData string true "Destination path"
// @Param local_path formData string true "Full path of the file to be uploaded"
// @Success 200 {string} string "ok"
// @Router /person/file/{shareid} [post]
func PostPersonFile(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
path := c.PostForm("path")
localPath := c.PostForm("local_path")
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
if !file.Exists(localPath) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_DOES_NOT_EXIST, Message: oasis_err2.GetMsg(oasis_err2.FILE_DOES_NOT_EXIST)})
return
}
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONUPLOAD
m.UUId = uuid
go service.UDPSendData(m, localPath)
f, _ := os.Stat(localPath)
task := model2.PersonDownloadDBModel{}
task.UUID = uuid
task.Name = f.Name()
task.Length = 0
task.From = token
task.Path = path
task.Size = f.Size()
task.State = types.DOWNLOADFINISHED
task.Created = time.Now().Unix()
task.Type = types.PERSONFILEUPLOAD
task.LocalPath = localPath
if service.MyService.Download().GetDownloadListByPath(task) > 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.PERSON_EXIST_DOWNLOAD, Message: oasis_err2.GetMsg(oasis_err2.PERSON_EXIST_DOWNLOAD)})
return
}
service.MyService.Download().AddDownloadTask(task)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary agree add friend
// @Produce application/json
// @Accept application/json
// @Tags person
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /person/friend/{shareid} [put]
func PutPersonAgreeFriend(c *gin.Context) {
token := c.Param("shareid")
_, err := uuid.FromString(token)
if err != nil {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
user := service.MyService.Friend().GetFriendById(model2.FriendModel{Token: token})
if user.State != types.FRIENDSTATEREQUEST {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.COMMAND_ERROR_INVALID_OPERATION, Message: oasis_err2.GetMsg(oasis_err2.COMMAND_ERROR_INVALID_OPERATION)})
return
}
service.MyService.Friend().AgreeFrined(user.Token)
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = ""
m.From = config.ServerInfo.Token
m.To = token
m.Type = types.PERSONAGREEFRIEND
m.UUId = uuid
go service.Dial(m, true)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// // @Summary upload file
// // @Produce application/json
// // @Accept multipart/form-data
// // @Tags person
// // @Security ApiKeyAuth
// // @Param path formData string false "file path"
// // @Param file formData file true "file"
// // @Success 200 {string} string "ok"
// // @Router /person/upload/{shareid} [get]
// func GetPersonFileUpload(c *gin.Context) {
// token := c.Param("shareid")
// _, err := uuid.FromString(token)
// path := c.Query("path")
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// relative := c.Query("relativePath")
// fileName := c.Query("filename")
// chunkNumber := c.Query("chunkNumber")
// totalChunks, _ := strconv.Atoi(c.DefaultQuery("totalChunks", "0"))
// dirPath := ""
// hash := file.GetHashByContent([]byte(fileName))
// tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
// if fileName != relative {
// dirPath = strings.TrimSuffix(relative, fileName)
// tempDir += dirPath
// file.MkDir(path + "/" + dirPath)
// }
// tempDir += chunkNumber
// if !file.CheckNotExist(tempDir) {
// c.JSON(200, model.Result{Success: 200, Message: 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 person
// // @Security ApiKeyAuth
// // @Param path formData string false "file path"
// // @Param file formData file true "file"
// // @Success 200 {string} string "ok"
// // @Router /person/upload [post]
// func PostPersonFileUpload(c *gin.Context) {
// token := c.Param("shareid")
// _, err := uuid.FromString(token)
// if err != nil {
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
// return
// }
// f, _, _ := c.Request.FormFile("file")
// relative := c.PostForm("relativePath")
// fileName := c.PostForm("filename")
// totalChunks, _ := strconv.Atoi(c.DefaultPostForm("totalChunks", "0"))
// chunkNumber := c.PostForm("chunkNumber")
// dirPath := ""
// path := c.PostForm("path")
// hash := file.GetHashByContent([]byte(fileName))
// if len(path) == 0 {
// c.JSON(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.RMDir(tempDir)
// }
// c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
// }

View File

@@ -23,14 +23,14 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// @Summary 系统信息 // @Summary check version
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/chackversion [get] // @Router /sys/version/check [get]
func CheckVersion(c *gin.Context) { func GetSystemCheckVersion(c *gin.Context) {
need, version := version.IsNeedUpdate() need, version := version.IsNeedUpdate()
if need { if need {
installLog := model2.AppNotify{} installLog := model2.AppNotify{}
@@ -47,7 +47,6 @@ func CheckVersion(c *gin.Context) {
data["version"] = version data["version"] = version
data["current_version"] = types.CURRENTVERSION data["current_version"] = types.CURRENTVERSION
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data}) c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
return
} }
// @Summary 系统信息 // @Summary 系统信息
@@ -65,7 +64,7 @@ func SystemUpdate(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
} }
//系统配置 //Get system config
func GetSystemConfig(c *gin.Context) { 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)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: json.RawMessage(config.SystemConfigInfo.ConfigStr)})
} }
@@ -115,7 +114,7 @@ func GetSystemConfigDebug(c *gin.Context) {
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t" systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
list := service.MyService.App().GetSystemAppList() list := service.MyService.App().GetSystemAppList()
for _, v := range *list { for _, v := range list {
systemAppStatus += v.Image + ",\n\t" systemAppStatus += v.Image + ",\n\t"
} }
@@ -136,9 +135,6 @@ func GetSystemConfigDebug(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: bugContent}) 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()
}
//widget配置 //widget配置
func GetWidgetConfig(c *gin.Context) { func GetWidgetConfig(c *gin.Context) {
@@ -155,9 +151,7 @@ func GetWidgetConfig(c *gin.Context) {
func PostSetWidgetConfig(c *gin.Context) { func PostSetWidgetConfig(c *gin.Context) {
buf := make([]byte, 1024) buf := make([]byte, 1024)
n, _ := c.Request.Body.Read(buf) n, _ := c.Request.Body.Read(buf)
fmt.Println("错误", strconv.Itoa(n))
service.MyService.System().UpSystemConfig("", string(buf[0:n])) service.MyService.System().UpSystemConfig("", string(buf[0:n]))
fmt.Println("错误1", string(buf[0:n]))
c.JSON(http.StatusOK, c.JSON(http.StatusOK,
model.Result{ model.Result{
Success: oasis_err.SUCCESS, Success: oasis_err.SUCCESS,
@@ -187,11 +181,14 @@ func GetCasaOSPort(c *gin.Context) {
// @Accept application/json // @Accept application/json
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Param port formData string true "port" // @Param port json string true "port"
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/port [put] // @Router /sys/port [put]
func PutCasaOSPort(c *gin.Context) { func PutCasaOSPort(c *gin.Context) {
port, err := strconv.Atoi(c.PostForm("port")) json := make(map[string]string)
c.BindJSON(&json)
portStr := json["port"]
port, err := strconv.Atoi(portStr)
if err != nil { if err != nil {
c.JSON(http.StatusOK, c.JSON(http.StatusOK,
model.Result{ model.Result{
@@ -246,7 +243,7 @@ func GetGuideCheck(c *gin.Context) {
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/kill [post] // @Router /sys/restart [post]
func PostKillCasaOS(c *gin.Context) { func PostKillCasaOS(c *gin.Context) {
os.Exit(0) os.Exit(0)
} }
@@ -257,10 +254,17 @@ func PostKillCasaOS(c *gin.Context) {
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/usg/off [put] // @Router /sys/usb/off [put]
func PutSystemOffUSBAutoMount(c *gin.Context) { func PutSystemUSBAutoMount(c *gin.Context) {
service.MyService.System().UpdateUSBAutoMount("False") status := c.Param("status")
service.MyService.System().ExecUSBAutoMountShell("False") if status == "on" {
service.MyService.System().UpdateUSBAutoMount("True")
service.MyService.System().ExecUSBAutoMountShell("True")
} else {
service.MyService.System().UpdateUSBAutoMount("False")
service.MyService.System().ExecUSBAutoMountShell("False")
}
c.JSON(http.StatusOK, c.JSON(http.StatusOK,
model.Result{ model.Result{
Success: oasis_err.SUCCESS, Success: oasis_err.SUCCESS,
@@ -280,6 +284,7 @@ func GetSystemUSBAutoMount(c *gin.Context) {
if config.ServerInfo.USBAutoMount == "False" { if config.ServerInfo.USBAutoMount == "False" {
state = "False" state = "False"
} }
c.JSON(http.StatusOK, c.JSON(http.StatusOK,
model.Result{ model.Result{
Success: oasis_err.SUCCESS, Success: oasis_err.SUCCESS,
@@ -288,31 +293,33 @@ func GetSystemUSBAutoMount(c *gin.Context) {
}) })
} }
// @Summary Turn off usb auto-mount // @Summary get system hardware info
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/usb/on [put] // @Router /sys/hardware/info [get]
func PutSystemOnUSBAutoMount(c *gin.Context) { func GetSystemHardwareInfo(c *gin.Context) {
service.MyService.System().UpdateUSBAutoMount("True")
service.MyService.System().ExecUSBAutoMountShell("True") data := make(map[string]string, 1)
data["drive_model"] = service.MyService.ZiMa().GetDeviceTree()
c.JSON(http.StatusOK, c.JSON(http.StatusOK,
model.Result{ model.Result{
Success: oasis_err.SUCCESS, Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS), Message: oasis_err.GetMsg(oasis_err.SUCCESS),
Data: data,
}) })
} }
// @Summary system info // @Summary system utilization
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json
// @Tags sys // @Tags sys
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Success 200 {string} string "ok" // @Success 200 {string} string "ok"
// @Router /sys/info [get] // @Router /sys/utilization [get]
func Info(c *gin.Context) { func GetSystemUtilization(c *gin.Context) {
var data = make(map[string]interface{}, 6) var data = make(map[string]interface{}, 6)
list := service.MyService.Disk().LSBLK(true) list := service.MyService.Disk().LSBLK(true)
@@ -411,18 +418,18 @@ func Info(c *gin.Context) {
} }
} }
data["usb"] = usb data["usb"] = usb
cpu := service.MyService.ZiMa().GetCpuPercent() cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum() num := service.MyService.System().GetCpuCoreNum()
cpuData := make(map[string]interface{}) cpuData := make(map[string]interface{})
cpuData["percent"] = cpu cpuData["percent"] = cpu
cpuData["num"] = num cpuData["num"] = num
data["cpu"] = cpuData data["cpu"] = cpuData
data["mem"] = service.MyService.ZiMa().GetMemInfo() data["mem"] = service.MyService.System().GetMemInfo()
//拼装网络信息 //拼装网络信息
netList := service.MyService.ZiMa().GetNetInfo() netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{} newNet := []model.IOCountersStat{}
nets := service.MyService.ZiMa().GetNet(true) nets := service.MyService.System().GetNet(true)
for _, n := range netList { for _, n := range netList {
for _, netCardName := range nets { for _, netCardName := range nets {
if n.Name == netCardName { if n.Name == netCardName {
@@ -439,3 +446,88 @@ func Info(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
} }
// @Summary Get notification port
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/socket/port [get]
func GetSystemSocketPort(c *gin.Context) {
c.JSON(http.StatusOK,
model.Result{
Success: oasis_err.SUCCESS,
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
Data: config.ServerInfo.SocketPort,
})
}
// @Summary get cpu info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/cpu [get]
func GetSystemCupInfo(c *gin.Context) {
cpu := service.MyService.System().GetCpuPercent()
num := service.MyService.System().GetCpuCoreNum()
data := make(map[string]interface{})
data["percent"] = cpu
data["num"] = num
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: data})
}
// @Summary get mem info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/mem [get]
func GetSystemMemInfo(c *gin.Context) {
mem := service.MyService.System().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: mem})
}
// @Summary get disk info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/disk [get]
func GetSystemDiskInfo(c *gin.Context) {
disk := service.MyService.ZiMa().GetDiskInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: disk})
}
// @Summary get Net info
// @Produce application/json
// @Accept application/json
// @Tags sys
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /sys/net [get]
func GetSystemNetInfo(c *gin.Context) {
netList := service.MyService.System().GetNetInfo()
newNet := []model.IOCountersStat{}
for _, n := range netList {
for _, netCardName := range service.MyService.System().GetNet(true) {
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
}
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
}

View File

@@ -1,10 +1,17 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-13 15:20:56
* @FilePath: /CasaOS/route/v1/zima_info.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package v1 package v1
import ( import (
"net/http" "net/http"
"strings"
"time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err" oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
@@ -12,77 +19,6 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// @Summary 获取cpu信息
// @Produce application/json
// @Accept application/json
// @Tags zima
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zima/getcpuinfo [get]
func CupInfo(c *gin.Context) {
//检查参数是否正确
cpu := service.MyService.ZiMa().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum()
data := make(map[string]interface{})
data["percent"] = cpu
data["num"] = num
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
// @Tags zima
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zima/getmeminfo [get]
func MemInfo(c *gin.Context) {
//检查参数是否正确
mem := service.MyService.ZiMa().GetMemInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: mem})
}
// @Summary 获取硬盘信息
// @Produce application/json
// @Accept application/json
// @Tags zima
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zima/getdiskinfo [get]
func DiskInfo(c *gin.Context) {
disk := service.MyService.ZiMa().GetDiskInfo()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: disk})
}
// @Summary 获取网络信息
// @Produce application/json
// @Accept application/json
// @Tags zima
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /zima/getnetinfo [get]
func NetInfo(c *gin.Context) {
netList := service.MyService.ZiMa().GetNetInfo()
newNet := []model.IOCountersStat{}
for _, n := range netList {
for _, netCardName := range service.MyService.ZiMa().GetNet(true) {
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
}
}
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: newNet})
}
// @Summary 获取信息系统信息 // @Summary 获取信息系统信息
// @Produce application/json // @Produce application/json
// @Accept application/json // @Accept application/json

View File

@@ -3,9 +3,11 @@ package service
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"runtime" "runtime"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -13,164 +15,326 @@ import (
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command" "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
client2 "github.com/docker/docker/client" client2 "github.com/docker/docker/client"
"github.com/pkg/errors" "github.com/pkg/errors"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
"gorm.io/gorm" "gorm.io/gorm"
) )
type AppService interface { type AppService interface {
GetMyList(index, size int, position bool) *[]model2.MyAppList CreateApplication(m model2.ApplicationModel) model2.ApplicationModel
GetApplicationList() (m []model2.ApplicationModel)
GetApplicationById(id string) (m model2.ApplicationModel)
UpdateApplicationOrderById(id string, order int)
GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList)
GetCasaOSCount() int
SaveContainer(m model2.AppListDBModel) SaveContainer(m model2.AppListDBModel)
GetUninstallInfo(id string) model2.AppListDBModel GetUninstallInfo(id string) model2.AppListDBModel
RemoveContainerById(id string) DeleteApp(id string)
GetContainerInfo(name string) (types.Container, error) GetContainerInfo(name string) (types.Container, error)
GetAppDBInfo(id string) model2.AppListDBModel GetAppDBInfo(id string) model2.AppListDBModel
UpdateApp(m model2.AppListDBModel) UpdateApp(m model2.AppListDBModel)
GetSimpleContainerInfo(name string) (types.Container, error) GetSimpleContainerInfo(name string) (types.Container, error)
DelAppConfigDir(path string) DelAppConfigDir(path string)
GetSystemAppList() *[]model2.MyAppList GetSystemAppList() []types.Container
GetHardwareUsageSteam() GetHardwareUsageSteam()
GetHardwareUsage() []model.DockerStatsModel GetHardwareUsage() []model.DockerStatsModel
GetAppStats(id string) string GetAppStats(id string) string
GetAllDBApps() []model2.AppListDBModel GetAllDBApps() []model2.AppListDBModel
ImportApplications(casaApp bool)
CheckNewImage()
} }
type appStruct struct { type appStruct struct {
db *gorm.DB db *gorm.DB
log loger2.OLog
} }
//获取我的应用列表 func (a *appStruct) GetApplicationById(id string) (m model2.ApplicationModel) {
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList { a.db.Where("id = ?", id).First(&m)
//获取docker应用 return
}
func (a *appStruct) UpdateApplicationOrderById(id string, order int) {
a.db.Model(&model2.ApplicationModel{}).Where("id = ?", id).Update("order", order)
}
func (a *appStruct) CreateApplication(m model2.ApplicationModel) model2.ApplicationModel {
a.db.Create(&m)
return m
}
func (a *appStruct) GetApplicationList() (m []model2.ApplicationModel) {
a.db.Find(&m)
return
}
func (a *appStruct) CheckNewImage() {
list := MyService.Docker().DockerContainerList()
for _, v := range list {
inspect, err := MyService.Docker().DockerImageInfo(strings.Split(v.Image, ":")[0])
if err != nil {
NewVersionApp[v.ID] = inspect.ID
continue
}
if inspect.ID == v.ImageID {
delete(NewVersionApp, v.ID)
continue
}
NewVersionApp[v.ID] = inspect.ID
}
}
func (a *appStruct) ImportApplications(casaApp bool) {
if casaApp {
list := MyService.App().GetAllDBApps()
for _, app := range list {
info, err := MyService.Docker().DockerContainerInfo(app.CustomId)
if err != nil {
MyService.App().DeleteApp(app.CustomId)
continue
}
//info.NetworkSettings
info.Config.Labels["casaos"] = "casaos"
info.Config.Labels["web"] = app.PortMap
info.Config.Labels["icon"] = app.Icon
info.Config.Labels["desc"] = app.Description
info.Config.Labels["index"] = app.Index
info.Config.Labels["custom_id"] = app.CustomId
info.Name = app.Title
container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
if err != nil {
fmt.Println(err)
continue
}
MyService.App().DeleteApp(app.CustomId)
MyService.Docker().DockerContainerStop(app.CustomId)
MyService.Docker().DockerContainerRemove(app.CustomId, false)
MyService.Docker().DockerContainerStart(container_id)
}
} else {
list := MyService.Docker().DockerContainerList()
for _, app := range list {
info, err := MyService.Docker().DockerContainerInfo(app.ID)
if err != nil || info.Config.Labels["casaos"] == "casaos" {
continue
}
info.Config.Labels["casaos"] = "casaos"
info.Config.Labels["web"] = ""
info.Config.Labels["icon"] = ""
info.Config.Labels["desc"] = ""
info.Config.Labels["index"] = ""
info.Config.Labels["custom_id"] = uuid.NewV4().String()
_, err = MyService.Docker().DockerContainerCopyCreate(info)
if err != nil {
continue
}
}
}
// allcontainer := MyService.Docker().DockerContainerList()
// for _, app := range allcontainer {
// info, err := MyService.Docker().DockerContainerInfo(app.ID)
// if err != nil {
// continue
// }
// MyService.Docker().DockerContainerStop(app.ID)
// MyService.Docker().DockerContainerRemove(app.ID, false)
// //info.NetworkSettings
// info.Config.Labels["custom_id"] = uuid.NewV4().String()
// container_id, err := MyService.Docker().DockerContainerCopyCreate(info)
// if err != nil {
// fmt.Println(err)
// continue
// }
// MyService.Docker().DockerContainerStart(container_id)
//}
}
func (a *appStruct) GetCasaOSCount() int {
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5)) cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil { if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err) loger.Error("Failed to init client", zap.Any("err", err))
return 0
} }
defer cli.Close() defer cli.Close()
fts := filters.NewArgs() fts := filters.NewArgs()
fts.Add("label", "origin") fts.Add("label", "casaos=casaos")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts}) //fts.Add("label", "casaos:casaos")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: fts, Limit: 200})
if err != nil { if err != nil {
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err) loger.Error("failed to get container_list", zap.Any("err", err))
return 0
}
systemApp := MyService.App().GetApplicationList()
return len(containers) + len(systemApp)
}
//获取我的应用列表
func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) {
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil {
loger.Error("Failed to init client", zap.Any("err", err))
}
defer cli.Close()
// fts := filters.NewArgs()
// fts.Add("label", "casaos=casaos")
//fts.Add("label", "casaos")
//fts.Add("casaos", "casaos")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
} }
//获取本地数据库应用 //获取本地数据库应用
var lm []model2.AppListDBModel unTranslation := []model2.MyAppList{}
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image").Find(&lm)
list := []model2.MyAppList{} list := []model2.MyAppList{}
lMap := make(map[string]interface{})
for _, dbModel := range lm { systemApp := MyService.App().GetApplicationList()
if position { for _, v := range systemApp {
if dbModel.Position { list = append(list, model2.MyAppList{
lMap[dbModel.ContainerId] = dbModel Name: v.Name,
} Icon: v.Icon,
} else { State: strconv.Itoa(v.State),
lMap[dbModel.ContainerId] = dbModel Id: strconv.Itoa(v.Id),
} CustomId: strconv.Itoa(v.Id),
Port: "",
//Order: strconv.Itoa(v.Order),
Index: "/",
Image: "",
Type: v.Type,
Host: "",
Protocol: "",
NewVersion: false,
})
} }
for _, container := range containers {
if lMap[container.ID] != nil && container.Labels["origin"] != "system" { for _, m := range containers {
m := lMap[container.ID].(model2.AppListDBModel) if m.Labels["casaos"] == "casaos" {
if len(m.Label) == 0 { if m.Labels["origin"] == "system" {
m.Label = m.Title continue
} }
_, newVersion := NewVersionApp[m.ID]
// 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{ list = append(list, model2.MyAppList{
Name: m.Label, Name: strings.ReplaceAll(m.Names[0], "/", ""),
Icon: m.Icon, Icon: m.Labels["icon"],
State: container.State, State: m.State,
CustomId: strings.ReplaceAll(container.Names[0], "/", ""), CustomId: m.Labels["custom_id"],
Port: m.PortMap, Id: m.ID,
Index: m.Index, Port: m.Labels["web"],
//UpTime: tm, Index: m.Labels["index"],
Image: m.Image, //Order: m.Labels["order"],
Slogan: m.Slogan, Image: m.Image,
NewVersion: newVersion,
Type: m.Labels["origin"],
//Slogan: m.Slogan,
//Rely: m.Rely, //Rely: m.Rely,
Host: m.Labels["host"],
Protocol: m.Labels["protocol"],
})
} else {
unTranslation = append(unTranslation, model2.MyAppList{
Name: strings.ReplaceAll(m.Names[0], "/", ""),
Icon: "",
State: m.State,
CustomId: m.ID,
Id: m.ID,
Port: "",
NewVersion: false,
Host: "",
Protocol: "",
Image: m.Image,
}) })
} }
} }
return &list //lMap := make(map[string]interface{})
// for _, dbModel := range lm {
// if position {
// if dbModel.Position {
// lMap[dbModel.ContainerId] = dbModel
// }
// } else {
// 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, &unTranslation
} }
//system application list //system application list
func (a *appStruct) GetSystemAppList() *[]model2.MyAppList { func (a *appStruct) GetSystemAppList() []types.Container {
//获取docker应用 //获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv) cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil { if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err) loger.Error("Failed to init client", zap.Any("err", err))
} }
defer cli.Close() defer cli.Close()
fts := filters.NewArgs() fts := filters.NewArgs()
fts.Add("label", "origin=system") fts.Add("label", "origin=system")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts}) containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil { if err != nil {
a.log.Error("获取docker容器失败", "app.sys", "line:123", err) loger.Error("Failed to get container_list", zap.Any("err", err))
} }
//获取本地数据库应用 //获取本地数据库应用
var lm []model2.AppListDBModel // var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm) // a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
list := []model2.MyAppList{} //list := []model2.MyAppList{}
lMap := make(map[string]interface{}) //lMap := make(map[string]interface{})
for _, dbModel := range lm { // for _, dbModel := range lm {
lMap[dbModel.ContainerId] = dbModel // lMap[dbModel.ContainerId] = dbModel
} // }
for _, container := range containers {
if lMap[container.ID] != nil { return containers
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,
Volumes: m.Volumes,
//Rely: m.Rely,
})
}
}
return &list
} }
func (a *appStruct) GetAllDBApps() []model2.AppListDBModel { func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
var lm []model2.AppListDBModel var lm []model2.AppListDBModel
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image").Find(&lm) a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image,port_map").Find(&lm)
return lm return lm
} }
@@ -179,13 +343,13 @@ func (a *appStruct) GetContainerInfo(name string) (types.Container, error) {
//获取docker应用 //获取docker应用
cli, err := client2.NewClientWithOpts(client2.FromEnv) cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil { if err != nil {
a.log.Error("初始化client失败", "app.getmylist", "line:36", err) loger.Error("Failed to init client", zap.Any("err", err))
} }
filters := filters.NewArgs() filters := filters.NewArgs()
filters.Add("name", name) filters.Add("name", name)
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters}) containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: filters})
if err != nil { if err != nil {
a.log.Error("获取docker容器失败", "app.getcontainerinfo", "line:182", err) loger.Error("Failed to get container_list", zap.Any("err", err))
} }
if len(containers) > 0 { if len(containers) > 0 {
@@ -242,7 +406,7 @@ func (a *appStruct) DelAppConfigDir(path string) {
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + path) command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;DelAppConfigDir " + path)
} }
func (a *appStruct) RemoveContainerById(id string) { func (a *appStruct) DeleteApp(id string) {
a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{}) a.db.Table(model2.CONTAINERTABLENAME).Where("custom_id = ?", id).Delete(&model2.AppListDBModel{})
} }
@@ -298,31 +462,29 @@ func (a *appStruct) GetHardwareUsageSteam() {
ctx := context.Background() ctx := context.Background()
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
var lm []model2.AppListDBModel fts := filters.NewArgs()
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm) fts.Add("label", "casaos=casaos")
//fts.Add("label", "casaos")
//fts.Add("casaos", "casaos")
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
if err != nil {
loger.Error("Failed to get container_list", zap.Any("err", err))
}
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
if config.CasaOSGlobalVariables.AppChange { if config.CasaOSGlobalVariables.AppChange {
lm = []model2.AppListDBModel{}
config.CasaOSGlobalVariables.AppChange = false 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.Range(func(key, value interface{}) bool {
dataStats.Delete(key) dataStats.Delete(key)
return true return true
}) })
for _, v := range lm {
m, _ := dataApps.Load(v.ContainerId)
if m != nil {
dataStats.Store(v.ContainerId, m)
}
}
} }
var wg sync.WaitGroup var wg sync.WaitGroup
for _, v := range lm { for _, v := range containers {
wg.Add(1) wg.Add(1)
go func(v model2.AppListDBModel, i int) { go func(v types.Container, i int) {
defer wg.Done() defer wg.Done()
stats, err := cli.ContainerStats(ctx, v.ContainerId, true) stats, err := cli.ContainerStats(ctx, v.ID, true)
if err != nil { if err != nil {
return return
} }
@@ -331,19 +493,15 @@ func (a *appStruct) GetHardwareUsageSteam() {
if err := decode.Decode(&data); err == io.EOF { if err := decode.Decode(&data); err == io.EOF {
return return
} }
m, _ := dataStats.Load(v.ContainerId) m, _ := dataStats.Load(v.ID)
dockerStats := model.DockerStatsModel{} dockerStats := model.DockerStatsModel{}
if m != nil { if m != nil {
dockerStats.Pre = m.(model.DockerStatsModel).Data dockerStats.Pre = m.(model.DockerStatsModel).Data
} }
dockerStats.Data = data dockerStats.Data = data
dockerStats.Icon = v.Icon dockerStats.Icon = v.Labels["icon"]
if len(v.Label) > 0 { dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "")
dockerStats.Title = v.Label dataStats.Store(v.ID, dockerStats)
} else {
dockerStats.Title = v.Title
}
dataStats.Store(v.ContainerId, dockerStats)
if i == 99 { if i == 99 {
stats.Body.Close() stats.Body.Close()
} }
@@ -357,6 +515,6 @@ func (a *appStruct) GetHardwareUsageSteam() {
cancel() cancel()
} }
func NewAppService(db *gorm.DB, logger loger2.OLog) AppService { func NewAppService(db *gorm.DB) AppService {
return &appStruct{db: db, log: logger} return &appStruct{db: db}
} }

9
service/app_test.go Normal file
View File

@@ -0,0 +1,9 @@
package service
import (
"testing"
)
func TestGetCasaOSCount(t *testing.T) {
}

View File

@@ -5,11 +5,13 @@ import (
json2 "encoding/json" json2 "encoding/json"
"fmt" "fmt"
"strconv" "strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
@@ -77,24 +79,71 @@ func (o *casaService) GetServerList(index, size, tp, categoryId, key, language s
json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community) json2.Unmarshal([]byte(gjson.Get(listS, "data.community").String()), &community)
if len(list) > 0 { if len(list) > 0 {
Cache.SetDefault(keyName, listS) Cache.Set(keyName, listS, time.Hour*24)
} }
return return
} }
func (o *casaService) GetServerCategoryList() []model.ServerCategoryList { func (o *casaService) GetServerCategoryList() (list []model.ServerCategoryList) {
keyName := fmt.Sprintf("category_list")
if result, ok := Cache.Get(keyName); ok {
res, ok := result.(string)
if ok {
json2.Unmarshal([]byte(gjson.Get(res, "data").String()), &list)
return list
}
}
head := make(map[string]string) head := make(map[string]string)
head["Authorization"] = GetToken() head["Authorization"] = GetToken()
listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head) listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
list := []model.ServerCategoryList{}
json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list) json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &list)
if len(list) > 0 {
Cache.Set(keyName, listS, time.Hour*24)
}
return list return list
} }
// func (o *casaService) GetServerCategoryList() (list model.ServerCategoryList) {
// results := file.ReadFullFile(config.AppInfo.ProjectPath + "/conf/app_category.json")
// err := json2.Unmarshal(results, &list)
// if err != nil {
// loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
// }
// return list
// }
// func (o *casaService) AsyncGetServerCategoryList() {
// list := model.ServerCategoryList{}
// results := file.ReadFullFile(config.AppInfo.ProjectPath + "/conf/app_category.json")
// err := json2.Unmarshal(results, &list)
// if err != nil {
// loger.Error("marshal error", zap.Any("err", err), zap.Any("content", string(results)))
// }
// if list.Version == GetAppVersion() {
// return
// }
// item := []model.CategoryList{}
// head := make(map[string]string)
// head["Authorization"] = GetToken()
// listS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/category", head)
// json2.Unmarshal([]byte(gjson.Get(listS, "data").String()), &item)
// if len(item) > 0 {
// list.Version = GetAppVersion()
// list.Item = item
// by, err := json.Marshal(list)
// if err != nil {
// loger.Error("marshal error", zap.Any("err", err))
// }
// file.WriteToPath(by, config.AppInfo.ProjectPath+"/conf", "app_category.json")
// }
// }
func (o *casaService) GetServerAppInfo(id, t string, language string) model.ServerAppList { func (o *casaService) GetServerAppInfo(id, t string, language string) model.ServerAppList {
head := make(map[string]string) head := make(map[string]string)
@@ -154,6 +203,7 @@ func (o *casaService) PushAppAnalyse(uuid, t string, name, language string) {
m.Type = t m.Type = t
m.Name = name m.Name = name
m.Language = language m.Language = language
m.Version = types.CURRENTVERSION
b, _ := json.Marshal(m) b, _ := json.Marshal(m)
head := make(map[string]string) head := make(map[string]string)

View File

@@ -11,10 +11,11 @@ import (
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/disk"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"go.uber.org/zap"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -37,8 +38,7 @@ type DiskService interface {
RemoveLSBLKCache() RemoveLSBLKCache()
} }
type diskService struct { type diskService struct {
log loger2.OLog db *gorm.DB
db *gorm.DB
} }
func (d *diskService) RemoveLSBLKCache() { func (d *diskService) RemoveLSBLKCache() {
@@ -58,16 +58,16 @@ func (d *diskService) SmartCTL(path string) model.SmartctlA {
var m model.SmartctlA var m model.SmartctlA
str := command2.ExecSmartCTLByPath(path) str := command2.ExecSmartCTLByPath(path)
if str == nil { if str == nil {
d.log.Error("smartctl exec error,smartctl") loger.Error("failed to exec shell ", zap.Any("err", "smartctl exec error"))
return m return m
} }
err := json2.Unmarshal([]byte(str), &m) err := json2.Unmarshal([]byte(str), &m)
if err != nil { if err != nil {
d.log.Error("json ummarshal error", err) loger.Error("Failed to unmarshal json", zap.Any("err", err))
} }
if !reflect.DeepEqual(m, model.SmartctlA{}) { if !reflect.DeepEqual(m, model.SmartctlA{}) {
Cache.Add(key, m, time.Second*10) Cache.Add(key, m, time.Hour*24)
} }
return m return m
} }
@@ -133,13 +133,13 @@ func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
str := command2.ExecLSBLK() str := command2.ExecLSBLK()
if str == nil { if str == nil {
d.log.Error("lsblk exec error,lsblk") loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
return nil return nil
} }
var m []model.LSBLKModel var m []model.LSBLKModel
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m) err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m)
if err != nil { if err != nil {
d.log.Error("json ummarshal error", err) loger.Error("Failed to unmarshal json", zap.Any("err", err))
} }
var c []model.LSBLKModel var c []model.LSBLKModel
@@ -172,7 +172,7 @@ func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
if fsused > 0 { if fsused > 0 {
i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64) i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64)
if err != nil { if err != nil {
d.log.Fatal("diskservice_lsblk_fsused", err) loger.Error("Failed to parse float", zap.Any("err", err))
} }
} }
n = append(n, i) n = append(n, i)
@@ -190,15 +190,14 @@ func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
func (d *diskService) GetDiskInfo(path string) model.LSBLKModel { func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
str := command2.ExecLSBLKByPath(path) str := command2.ExecLSBLKByPath(path)
if str == nil { if str == nil {
d.log.Error("lsblk exec error,str") loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error"))
return model.LSBLKModel{} return model.LSBLKModel{}
} }
var ml []model.LSBLKModel var ml []model.LSBLKModel
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml) err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
if err != nil { if err != nil {
d.log.Info(string(str)) loger.Error("Failed to unmarshal json", zap.Any("err", err))
d.log.Error("json ummarshal error", err)
return model.LSBLKModel{} return model.LSBLKModel{}
} }
@@ -211,8 +210,7 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
chiArr := make(map[string]string) chiArr := make(map[string]string)
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + m.Path) chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + m.Path)
if len(chiList) == 0 { if len(chiList) == 0 {
d.log.Error(m.Path, chiList) loger.Error("chiList length error", zap.Any("err", "chiList length error"))
d.log.Error("chiList length error")
} }
for i := 0; i < len(chiList); i++ { for i := 0; i < len(chiList); i++ {
tempArr := strings.Split(chiList[i], ",") tempArr := strings.Split(chiList[i], ",")
@@ -231,7 +229,7 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDiskSizeAndSectors " + m.Path) diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDiskSizeAndSectors " + m.Path)
if len(diskEndSector) < 2 { if len(diskEndSector) < 2 {
d.log.Error("diskEndSector length error") loger.Error("diskEndSector length error", zap.Any("err", "diskEndSector length error"))
} }
diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64) diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 { if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
@@ -275,6 +273,6 @@ func (d *diskService) GetSerialAll() []model2.SerialDisk {
return m return m
} }
func NewDiskService(log loger2.OLog, db *gorm.DB) DiskService { func NewDiskService(db *gorm.DB) DiskService {
return &diskService{log: log, db: db} return &diskService{db: db}
} }

View File

@@ -7,22 +7,22 @@ import (
"encoding/binary" "encoding/binary"
json2 "encoding/json" json2 "encoding/json"
"fmt" "fmt"
"reflect"
"syscall" "syscall"
model2 "github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/model/notify"
types2 "github.com/IceWhaleTech/CasaOS/types"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cio" "github.com/containerd/containerd/cio"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci" "github.com/containerd/containerd/oci"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/docker" "github.com/IceWhaleTech/CasaOS/pkg/docker"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper" "github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
//"github.com/containerd/containerd/oci" //"github.com/containerd/containerd/oci"
"io" "io"
@@ -43,9 +43,10 @@ import (
) )
type DockerService interface { type DockerService interface {
DockerPullImage(imageName string, m model2.AppNotify) error DockerPullImage(imageName string, icon, name string) error
IsExistImage(imageName string) bool IsExistImage(imageName string) bool
DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) DockerContainerCreate(imageName string, m model.CustomizationPostData, net string) (containerId string, err error)
DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error)
DockerContainerStart(name string) error DockerContainerStart(name string) error
DockerContainerStats(name string) (string, error) DockerContainerStats(name string) (string, error)
DockerListByName(name string) (*types.Container, error) DockerListByName(name string) (*types.Container, error)
@@ -58,15 +59,28 @@ type DockerService interface {
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error) DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
DockerContainerLog(name string) (string, error) DockerContainerLog(name string) (string, error)
DockerContainerCommit(name string) DockerContainerCommit(name string)
DockerContainerList() []types.Container
DockerNetworkModelList() []types.NetworkResource DockerNetworkModelList() []types.NetworkResource
DockerImageInfo(image string) DockerImageInfo(image string) (types.ImageInspect, error)
GetNetWorkNameByNetWorkID(id string) (string, error) GetNetWorkNameByNetWorkID(id string) (string, error)
ContainerExecShell(container_id string) string ContainerExecShell(container_id string) string
} }
type dockerService struct { type dockerService struct {
rootDir string rootDir string
log loger2.OLog }
func (ds *dockerService) DockerContainerList() []types.Container {
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
if err != nil {
return nil
}
defer cli.Close()
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return containers
}
return containers
} }
func (ds *dockerService) ContainerExecShell(container_id string) string { func (ds *dockerService) ContainerExecShell(container_id string) string {
@@ -119,10 +133,7 @@ func DockerPull() {
cli, _ := client2.NewClientWithOpts(client2.FromEnv) cli, _ := client2.NewClientWithOpts(client2.FromEnv)
defer cli.Close() defer cli.Close()
authConfig := types.AuthConfig{ authConfig := types.AuthConfig{}
Username: "cn-north-4@M4OW0IULZ3U6PCQPBUZC",
Password: "7390181a1565f90927bbd98038436b57d6ebc66a3828d7a11dfda42b9c19d91d",
}
encodedJSON, err := json2.Marshal(authConfig) encodedJSON, err := json2.Marshal(authConfig)
fmt.Println(err) fmt.Println(err)
@@ -174,18 +185,16 @@ func DockerEx() {
// //
//} //}
func (ds *dockerService) DockerImageInfo(image string) { func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv) cli, err := client2.NewClientWithOpts(client2.FromEnv)
//but := bytes.Buffer{}
d, b, err := cli.ImageInspectWithRaw(context.Background(), image)
st, _ := json2.Marshal(d.Config)
fmt.Println(string(st))
fmt.Println("换行")
fmt.Println(string(b))
if err != nil { if err != nil {
fmt.Print(err) return types.ImageInspect{}, err
} }
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image)
if err != nil {
return inspect, err
}
return inspect, nil
} }
func MsqlExec(container string) error { func MsqlExec(container string) error {
@@ -308,7 +317,7 @@ func (ds *dockerService) IsExistImage(imageName string) bool {
} }
//安装镜像 //安装镜像
func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) error { func (ds *dockerService) DockerPullImage(imageName string, icon, name string) error {
cli, err := client2.NewClientWithOpts(client2.FromEnv) cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil { if err != nil {
return err return err
@@ -323,7 +332,8 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
return err return err
} }
buf := make([]byte, 256) //io.Copy()
buf := make([]byte, 2048*4)
for { for {
n, err := out.Read(buf) n, err := out.Read(buf)
if err != nil { if err != nil {
@@ -332,16 +342,33 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
} }
break break
} }
if !reflect.DeepEqual(m, model2.AppNotify{}) { if len(icon) > 0 && len(name) > 0 {
m.Type = types2.NOTIFY_TYPE_INSTALL_LOG notify := notify.Application{}
m.State = 0 notify.Icon = icon
m.Message = string(buf[:n]) notify.Name = name
MyService.Notify().UpdateLog(m) notify.State = "PULLING"
notify.Type = "INSTALL"
notify.Finished = false
notify.Success = true
notify.Message = string(buf[:n])
MyService.Notify().SendInstallAppBySocket(notify)
} }
} }
return err return err
} }
func (ds *dockerService) DockerContainerCopyCreate(info *types.ContainerJSON) (containerId string, err error) {
cli, err := client2.NewClientWithOpts(client2.FromEnv)
if err != nil {
return "", err
}
defer cli.Close()
container, err := cli.ContainerCreate(context.Background(), info.Config, info.HostConfig, &network.NetworkingConfig{info.NetworkSettings.Networks}, nil, info.Name)
if err != nil {
return "", err
}
return container.ID, err
}
//param imageName 镜像名称 //param imageName 镜像名称
//param containerDbId 数据库的id //param containerDbId 数据库的id
@@ -349,7 +376,7 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
//param mapPort 容器主端口映射到外部的端口 //param mapPort 容器主端口映射到外部的端口
//param tcp 容器其他tcp端口 //param tcp 容器其他tcp端口
//param udp 容器其他udp端口 //param udp 容器其他udp端口
func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId string, m model.CustomizationPostData, net string) (containerId string, err error) { func (ds *dockerService) DockerContainerCreate(imageName string, m model.CustomizationPostData, net string) (containerId string, err error) {
if len(net) == 0 { if len(net) == 0 {
net = "bridge" net = "bridge"
} }
@@ -410,7 +437,10 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
} }
var envArr []string var envArr []string
var showENV []string
showENV = append(showENV, "casaos")
for _, e := range m.Envs { for _, e := range m.Envs {
showENV = append(showENV, e.Name)
if strings.HasPrefix(e.Value, "$") { if strings.HasPrefix(e.Value, "$") {
envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone())) envArr = append(envArr, e.Name+"="+env_helper.ReplaceDefaultENV(e.Value, MyService.System().GetTimeZone()))
continue continue
@@ -442,18 +472,18 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
for _, v := range m.Volumes { for _, v := range m.Volumes {
path := v.Path path := v.Path
if len(path) == 0 { if len(path) == 0 {
path = docker.GetDir(containerDbId, v.Path) path = docker.GetDir(m.Label, v.Path)
if len(path) == 0 { if len(path) == 0 {
continue continue
} }
} }
path = strings.ReplaceAll(path, "$AppID", containerDbId) path = strings.ReplaceAll(path, "$AppID", m.Label)
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`) //reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
//result1 := reg1.FindAllStringSubmatch(path, -1) //result1 := reg1.FindAllStringSubmatch(path, -1)
//if len(result1) == 0 { //if len(result1) == 0 {
err = file.IsNotExistMkDir(path) err = file.IsNotExistMkDir(path)
if err != nil { if err != nil {
ds.log.Error("mkdir error", err) loger.Error("Failed to create a folder", zap.Any("err", err))
continue continue
} }
//} //}
@@ -495,12 +525,22 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
} }
config := &container.Config{ config := &container.Config{
Image: imageName, Image: imageName,
Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin}, Labels: map[string]string{"origin": m.Origin, m.Origin: m.Origin, "casaos": "casaos"},
Env: envArr, Env: envArr,
// Healthcheck: health, // Healthcheck: health,
Hostname: m.HostName, Hostname: m.HostName,
Cmd: m.Cmd, Cmd: m.Cmd,
} }
config.Labels["web"] = m.PortMap
config.Labels["icon"] = m.Icon
config.Labels["desc"] = m.Description
config.Labels["index"] = m.Index
config.Labels["custom_id"] = m.CustomId
config.Labels["show_env"] = strings.Join(showENV, ",")
config.Labels["protocol"] = m.Protocol
config.Labels["host"] = m.Host
//config.Labels["order"] = strconv.Itoa(MyService.App().GetCasaOSCount() + 1)
hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net), Privileged: m.Privileged, CapAdd: m.CapAdd} hostConfig := &container.HostConfig{Resources: res, Mounts: volumes, RestartPolicy: rp, NetworkMode: container.NetworkMode(net), Privileged: m.Privileged, CapAdd: m.CapAdd}
//if net != "host" { //if net != "host" {
config.ExposedPorts = ports config.ExposedPorts = ports
@@ -512,7 +552,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
hostConfig, hostConfig,
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{net: {NetworkID: "", Aliases: []string{}}}}, &network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{net: {NetworkID: "", Aliases: []string{}}}},
nil, nil,
containerDbId) m.Label)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -695,6 +735,9 @@ func (ds *dockerService) DockerListByName(name string) (*types.Container, error)
if err != nil { if err != nil {
return &types.Container{}, err return &types.Container{}, err
} }
if len(containers) == 0 {
return &types.Container{}, errors.New("not found")
}
return &containers[0], nil return &containers[0], nil
} }
@@ -794,8 +837,8 @@ func (ds *dockerService) DockerNetworkModelList() []types.NetworkResource {
networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{}) networks, _ := cli.NetworkList(context.Background(), types.NetworkListOptions{})
return networks return networks
} }
func NewDockerService(log loger2.OLog) DockerService { func NewDockerService() DockerService {
return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`), log: log} return &dockerService{rootDir: command2.ExecResultStr(`source ./shell/helper.sh ;GetDockerRootDir`)}
} }
// ---------------------------------------test------------------------------------ // ---------------------------------------test------------------------------------

33
service/down_record.go Normal file
View File

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

View File

@@ -11,7 +11,7 @@ type DownloadService interface {
SaveDownload(m model2.PersonDownloadDBModel) SaveDownload(m model2.PersonDownloadDBModel)
DelDownload(uuid string) DelDownload(uuid string)
GetDownloadById(uuid string) model2.PersonDownloadDBModel GetDownloadById(uuid string) model2.PersonDownloadDBModel
GetDownloadListByState(state string) []model2.PersonDownloadDBModel GetDownloadListByState(state string, t int) []model2.PersonDownloadDBModel
SetDownloadError(m model2.PersonDownloadDBModel) SetDownloadError(m model2.PersonDownloadDBModel)
GetDownloadListByPath(m model2.PersonDownloadDBModel) int GetDownloadListByPath(m model2.PersonDownloadDBModel) int
} }
@@ -48,11 +48,11 @@ func (d *downloadService) GetDownloadById(uuid string) model2.PersonDownloadDBMo
d.db.Model(m).Where("uuid = ?", uuid).First(&m) d.db.Model(m).Where("uuid = ?", uuid).First(&m)
return m return m
} }
func (d *downloadService) GetDownloadListByState(state string) (list []model2.PersonDownloadDBModel) { func (d *downloadService) GetDownloadListByState(state string, t int) (list []model2.PersonDownloadDBModel) {
if len(state) == 0 { if len(state) == 0 {
d.db.Find(&list) d.db.Where("type = ?", t).Find(&list)
} else { } else {
d.db.Where("state = ?", state).Find(&list) d.db.Where("state = ? AND type= ?", state, t).Find(&list)
} }
return return

View File

@@ -1,38 +1,33 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-12-20 14:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-09 18:15:54
* @FilePath: /CasaOS/service/file.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package service package service
import ( import (
"context" "context"
"io" "io"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"go.uber.org/zap"
) )
// type InteruptReader struct { var FileQueue sync.Map
// r io.Reader
// interupt chan int
// }
// func NewInteruptReader(r io.Reader) InteruptReader { var OpStrArr []string
// 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 { type reader struct {
ctx context.Context ctx context.Context
@@ -83,3 +78,96 @@ func (w *writer) Write(p []byte) (n int, err error) {
return w.w.Write(p) return w.w.Write(p)
} }
} }
func FileOperate(k string) {
list, ok := FileQueue.Load(k)
if !ok {
return
}
temp := list.(model.FileOperate)
if temp.ProcessedSize > 0 {
return
}
for i := 0; i < len(temp.Item); i++ {
v := temp.Item[i]
if temp.Type == "move" {
lastPath := v.From[strings.LastIndex(v.From, "/")+1:]
if !file.CheckNotExist(temp.To + "/" + lastPath) {
if temp.Style == "skip" {
temp.Item[i].Finished = true
continue
} else {
os.Remove(temp.To + "/" + lastPath)
}
}
err := os.Rename(v.From, temp.To+"/"+lastPath)
if err != nil {
loger.Debug("file move error", zap.Any("err", err))
continue
}
} else if temp.Type == "copy" {
err := file.CopyDir(v.From, temp.To, temp.Style)
if err != nil {
continue
}
} else {
continue
}
}
temp.Finished = true
FileQueue.Store(k, temp)
}
func ExecOpFile() {
len := len(OpStrArr)
if len == 0 {
return
}
if len > 1 {
len = 1
}
for i := 0; i < len; i++ {
go FileOperate(OpStrArr[i])
}
}
// file move or copy and send notify
func CheckFileStatus() {
for {
if len(OpStrArr) == 0 {
return
}
for _, v := range OpStrArr {
var total int64 = 0
item, ok := FileQueue.Load(v)
if !ok {
continue
}
temp := item.(model.FileOperate)
for i := 0; i < len(temp.Item); i++ {
if !temp.Item[i].Finished {
size, err := file.GetFileOrDirSize(temp.To + "/" + filepath.Base(temp.Item[i].From))
if err != nil {
continue
}
temp.Item[i].ProcessedSize = size
if size == temp.Item[i].Size {
temp.Item[i].Finished = true
}
total += size
} else {
total += temp.Item[i].ProcessedSize
}
}
temp.ProcessedSize = total
FileQueue.Store(v, temp)
}
time.Sleep(time.Second * 3)
}
}

View File

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

View File

@@ -0,0 +1,20 @@
package model
import (
"time"
)
type ApplicationModel struct {
Id int `gorm:"column:id;primary_key" json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
State int `json:"state"`
Type string `json:"type"`
Order int `json:"order"`
CreatedAt time.Time `gorm:"<-:create" json:"created_at"`
UpdatedAt time.Time `gorm:"<-:create;<-:update" json:"updated_at"`
}
func (p *ApplicationModel) TableName() string {
return "o_application"
}

View File

@@ -1,11 +1,18 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-05-13 18:15:46
* @LastEditors: LinkLeong
* @LastEditTime: 2022-05-30 17:33:21
* @FilePath: /CasaOS/service/model/o_container.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package model package model
import (
"github.com/IceWhaleTech/CasaOS/model"
)
const CONTAINERTABLENAME = "o_container" const CONTAINERTABLENAME = "o_container"
//Soon to be removed
type AppListDBModel struct { type AppListDBModel struct {
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"` CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
Title string `json:"title"` Title string `json:"title"`
@@ -52,15 +59,21 @@ func (p *AppListDBModel) TableName() string {
} }
type MyAppList struct { type MyAppList struct {
Name string `json:"name"` Id string `json:"id"`
Icon string `json:"icon"` Name string `json:"name"`
State string `json:"state"` Icon string `json:"icon"`
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"` State string `json:"state"`
Index string `json:"index"` CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
Port string `json:"port"` Index string `json:"index"`
UpTime string `json:"up_time"` //Order string `json:"order"`
Slogan string `json:"slogan"` Port string `json:"port"`
Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}] UpTime string `json:"up_time"`
Image string `json:"image"` Slogan string `json:"slogan"`
Volumes string `json:"volumes"` Type string `json:"type"`
//Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
Image string `json:"image"`
Volumes string `json:"volumes"`
NewVersion bool `json:"new_version"`
Host string `json:"host"`
Protocol string `json:"protocol"`
} }

View File

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

View File

@@ -3,7 +3,7 @@ package model
type PersonDownloadDBModel struct { type PersonDownloadDBModel struct {
UUID string `gorm:"column:uuid;primary_key" json:"uuid"` UUID string `gorm:"column:uuid;primary_key" json:"uuid"`
State int `json:"state"` // State int `json:"state"` //
Type int `json:"type"` //defult 1 Type int `json:"type"` //defult 0
Name string `json:"name"` //file name Name string `json:"name"` //file name
Size int64 `json:"size"` //file size Size int64 `json:"size"` //file size
BlockSize int `json:"block_size"` //Size of each file block BlockSize int `json:"block_size"` //Size of each file block

View File

@@ -1,7 +1,7 @@
package model package model
type FriendModel struct { type FriendModel struct {
State int `json:"state"` //Reserved State int `json:"state"`
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"` CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"` UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
NickName string `json:"nick_name"` NickName string `json:"nick_name"`
@@ -12,6 +12,8 @@ type FriendModel struct {
Profile string `json:"profile"` //Description Profile string `json:"profile"` //Description
OnLine bool `json:"on_line" gorm:"-"` OnLine bool `json:"on_line" gorm:"-"`
Version int `json:"version"` Version int `json:"version"`
Write bool `json:"write"`
LocalIP string `json:"local_ip"`
} }
func (p *FriendModel) TableName() string { func (p *FriendModel) TableName() string {

View File

@@ -2,14 +2,23 @@ package service
import ( import (
json2 "encoding/json" json2 "encoding/json"
"fmt"
"time" "time"
model2 "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/ambelovsky/gosf"
socketio "github.com/googollee/go-socket.io"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/shirou/gopsutil/v3/mem"
"gorm.io/gorm" "gorm.io/gorm"
) )
var NotifyMsg chan notify.Message
var ClientCount int = 0
type NotifyServer interface { type NotifyServer interface {
GetLog(id string) model.AppNotify GetLog(id string) model.AppNotify
AddLog(log model.AppNotify) AddLog(log model.AppNotify)
@@ -18,13 +27,336 @@ type NotifyServer interface {
DelLog(id string) DelLog(id string)
GetList(c int) (list []model.AppNotify) GetList(c int) (list []model.AppNotify)
MarkRead(id string, state int) MarkRead(id string, state int)
SendText(m model.AppNotify) // SendText(m model.AppNotify)
SendUninstallAppBySocket(app notify.Application)
SendNetInfoBySocket(netList []model2.IOCountersStat)
SendCPUInfoBySocket(cpu map[string]interface{})
SendMemInfoBySocket(mem *mem.VirtualMemoryStat)
SendUSBInfoBySocket(list []model2.DriveUSB)
SendDiskInfoBySocket(disk model2.Summary)
SendPersonStatusBySocket(status notify.Person)
SendFileOperateNotify(nowSend bool)
SendInstallAppBySocket(app notify.Application)
SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat)
} }
type notifyServer struct { type notifyServer struct {
db *gorm.DB db *gorm.DB
} }
func (i *notifyServer) SendAllHardwareStatusBySocket(disk model2.Summary, list []model2.DriveUSB, mem map[string]interface{}, cpu map[string]interface{}, netList []model2.IOCountersStat) {
body := make(map[string]interface{})
body["sys_disk"] = disk
body["sys_usb"] = list
body["sys_mem"] = mem
body["sys_cpu"] = cpu
body["sys_net"] = netList
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_hardware_status"
notify := notify.Message{}
notify.Path = "sys_hardware_status"
notify.Msg = msg
NotifyMsg <- notify
}
// Send periodic broadcast messages
func (i *notifyServer) SendFileOperateNotify(nowSend bool) {
if nowSend {
len := 0
FileQueue.Range(func(k, v interface{}) bool {
len++
return true
})
model := notify.NotifyModel{}
listMsg := make(map[string]interface{})
if len == 0 {
model.Data = []string{}
listMsg["file_operate"] = model
msg := gosf.Message{}
msg.Success = true
msg.Body = listMsg
msg.Text = "file_operate"
notify := notify.Message{}
notify.Path = "file_operate"
notify.Msg = msg
NotifyMsg <- notify
return
}
model.State = "NORMAL"
list := []notify.File{}
OpStrArrbak := OpStrArr
for _, v := range OpStrArrbak {
tempItem, ok := FileQueue.Load(v)
temp := tempItem.(model2.FileOperate)
if !ok {
continue
}
task := notify.File{}
task.Id = v
task.ProcessedSize = temp.ProcessedSize
task.TotalSize = temp.TotalSize
task.To = temp.To
task.Type = temp.Type
if task.ProcessedSize == 0 {
task.Status = "STARTING"
} else {
task.Status = "PROCESSING"
}
if temp.Finished || temp.ProcessedSize >= temp.TotalSize {
task.Finished = true
task.Status = "FINISHED"
FileQueue.Delete(v)
OpStrArr = OpStrArr[1:]
go ExecOpFile()
list = append(list, task)
continue
}
for _, v := range temp.Item {
if v.Size != v.ProcessedSize {
task.ProcessingPath = v.From
break
}
}
list = append(list, task)
}
model.Data = list
listMsg["file_operate"] = model
msg := gosf.Message{}
msg.Success = true
msg.Body = listMsg
msg.Text = "file_operate"
notify := notify.Message{}
notify.Path = "file_operate"
notify.Msg = msg
NotifyMsg <- notify
} else {
for {
len := 0
FileQueue.Range(func(k, v interface{}) bool {
len++
return true
})
if len == 0 {
return
}
listMsg := make(map[string]interface{})
model := notify.NotifyModel{}
model.State = "NORMAL"
list := []notify.File{}
OpStrArrbak := OpStrArr
for _, v := range OpStrArrbak {
tempItem, ok := FileQueue.Load(v)
temp := tempItem.(model2.FileOperate)
if !ok {
continue
}
task := notify.File{}
task.Id = v
task.ProcessedSize = temp.ProcessedSize
task.TotalSize = temp.TotalSize
task.To = temp.To
task.Type = temp.Type
if task.ProcessedSize == 0 {
task.Status = "STARTING"
} else {
task.Status = "PROCESSING"
}
if temp.Finished || temp.ProcessedSize >= temp.TotalSize {
task.Finished = true
task.Status = "FINISHED"
FileQueue.Delete(v)
OpStrArr = OpStrArr[1:]
go ExecOpFile()
list = append(list, task)
continue
}
for _, v := range temp.Item {
if v.Size != v.ProcessedSize {
task.ProcessingPath = v.From
break
}
}
list = append(list, task)
}
model.Data = list
listMsg["file_operate"] = model
msg := gosf.Message{}
msg.Success = true
msg.Body = listMsg
msg.Text = "file_operate"
notify := notify.Message{}
notify.Path = "file_operate"
notify.Msg = msg
NotifyMsg <- notify
time.Sleep(time.Second * 3)
}
}
}
func (i *notifyServer) SendPersonStatusBySocket(status notify.Person) {
body := make(map[string]interface{})
body["data"] = status
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "person_status"
notify := notify.Message{}
notify.Path = "person_status"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendDiskInfoBySocket(disk model2.Summary) {
body := make(map[string]interface{})
body["data"] = disk
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_disk"
notify := notify.Message{}
notify.Path = "sys_disk"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendUSBInfoBySocket(list []model2.DriveUSB) {
body := make(map[string]interface{})
body["data"] = list
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_usb"
notify := notify.Message{}
notify.Path = "sys_usb"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendMemInfoBySocket(mem *mem.VirtualMemoryStat) {
body := make(map[string]interface{})
body["data"] = mem
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_mem"
notify := notify.Message{}
notify.Path = "sys_mem"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendInstallAppBySocket(app notify.Application) {
body := make(map[string]interface{})
body["data"] = app
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "app_install"
notify := notify.Message{}
notify.Path = "app_install"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendCPUInfoBySocket(cpu map[string]interface{}) {
body := make(map[string]interface{})
body["data"] = cpu
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_cpu"
notify := notify.Message{}
notify.Path = "sys_cpu"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendNetInfoBySocket(netList []model2.IOCountersStat) {
body := make(map[string]interface{})
body["data"] = netList
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "sys_net"
notify := notify.Message{}
notify.Path = "sys_net"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SendUninstallAppBySocket(app notify.Application) {
body := make(map[string]interface{})
body["data"] = app
msg := gosf.Message{}
msg.Body = body
msg.Success = true
msg.Text = "app_uninstall"
notify := notify.Message{}
notify.Path = "app_uninstall"
notify.Msg = msg
NotifyMsg <- notify
}
func (i *notifyServer) SSR() {
server := socketio.NewServer(nil)
fmt.Println(server)
}
func (i notifyServer) GetList(c int) (list []model.AppNotify) { 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) i.db.Where("class = ?", c).Where(i.db.Where("state = ?", types.NOTIFY_DYNAMICE).Or("state = ?", types.NOTIFY_UNREAD)).Find(&list)
return return
@@ -103,25 +435,25 @@ func SendMeg() {
// } // }
} }
func (i notifyServer) SendText(m model.AppNotify) { // func (i notifyServer) SendText(m model.AppNotify) {
list := []model.AppNotify{} // list := []model.AppNotify{}
list = append(list, m) // list = append(list, m)
json, _ := json2.Marshal(list) // json, _ := json2.Marshal(list)
var temp []*websocket.Conn // var temp []*websocket.Conn
for _, v := range WebSocketConns { // for _, v := range WebSocketConns {
err := v.WriteMessage(1, json) // err := v.WriteMessage(1, json)
if err == nil { // if err == nil {
temp = append(temp, v) // temp = append(temp, v)
} // }
} // }
WebSocketConns = temp // WebSocketConns = temp
if len(WebSocketConns) == 0 { // if len(WebSocketConns) == 0 {
SocketRun = false // SocketRun = false
} // }
} // }
func NewNotifyService(db *gorm.DB) NotifyServer { func NewNotifyService(db *gorm.DB) NotifyServer {
return &notifyServer{db: db} return &notifyServer{db: db}

View File

@@ -15,8 +15,10 @@ import (
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper" "github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port" port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
@@ -26,6 +28,7 @@ import (
type PersonService interface { type PersonService interface {
GetPersionInfo(token string) (m model.PersionModel, err error) GetPersionInfo(token string) (m model.PersionModel, err error)
GetPersionNetWorkTypeDetection() string
} }
type personService struct { type personService struct {
@@ -34,11 +37,12 @@ type personService struct {
var IpInfo model.PersionModel var IpInfo model.PersionModel
var CancelList map[string]string var CancelList map[string]string
var InternalInspection map[string][]string
func PushIpInfo(token string) { func PushIpInfo(token string) {
m := model.PersionModel{} m := model.PersionModel{}
m.Ips = GetDeviceAllIP() m.Ips = ip_helper.GetDeviceAllIP("")
m.Token = token m.Token = token
b, _ := json.Marshal(m) b, _ := json.Marshal(m)
@@ -54,6 +58,16 @@ func (p *personService) GetPersionInfo(token string) (m model.PersionModel, err
err = json.Unmarshal([]byte(infoS), &m) err = json.Unmarshal([]byte(infoS), &m)
return return
} }
func (p *personService) GetPersionNetWorkTypeDetection() string {
data := make(chan string)
list := []string{"stun.l.google.com", "stun1.l.google.com", "stun2.l.google.com", "stun.sipgate.net"}
for _, v := range list {
go utils.GetNetWorkTypeDetection(data, v)
}
result := <-data
close(data)
return result
}
func NewPersonService(db *gorm.DB) PersonService { func NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db} return &personService{db: db}
@@ -193,6 +207,11 @@ func ProcessingContent(stream quic.Stream) {
} else { } else {
list = []model.Path{} list = []model.Path{}
} }
if rFriend.Write {
for i := 0; i < len(list); i++ {
list[i].Write = true
}
}
m.To = m.From m.To = m.From
m.Data = list m.Data = list
m.From = config.ServerInfo.Token m.From = config.ServerInfo.Token
@@ -200,10 +219,9 @@ func ProcessingContent(stream quic.Stream) {
break break
} else if m.Type == types.PERSONDOWNLOAD { } else if m.Type == types.PERSONDOWNLOAD {
SendFileData(stream, m.Data.(string), m.From, m.UUId) SendFileData(stream, m.Data.(string), m.From, m.UUId, types.PERSONDOWNLOAD)
break break
} else if m.Type == types.PERSONADDFRIEND { } else if m.Type == types.PERSONADDFRIEND {
fmt.Println("有用户来请求加好友", m)
friend := model2.FriendModel{} friend := model2.FriendModel{}
dataModelByte, _ := json.Marshal(m.Data) dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &friend) err := json.Unmarshal(dataModelByte, &friend)
@@ -225,6 +243,7 @@ func ProcessingContent(stream quic.Stream) {
break break
} else if m.Type == types.PERSONCONNECTION { } else if m.Type == types.PERSONCONNECTION {
if len(m.Data.(string)) > 0 { if len(m.Data.(string)) > 0 {
fmt.Println("设置ip", m.Data.(string))
UDPAddressMap[m.From] = m.Data.(string) UDPAddressMap[m.From] = m.Data.(string)
} else { } else {
delete(UDPAddressMap, m.From) delete(UDPAddressMap, m.From)
@@ -236,14 +255,18 @@ func ProcessingContent(stream quic.Stream) {
// mi.Token = config.ServerInfo.Token // mi.Token = config.ServerInfo.Token
user := MyService.Casa().GetUserInfoByShareId(m.From) user := MyService.Casa().GetUserInfoByShareId(m.From)
//好友申请 //不是好友
friend := model2.FriendModel{} friend := model2.FriendModel{}
friend.Token = m.From friend.Token = m.From
friend.Avatar = user.Avatar friend.Avatar = user.Avatar
friend.Block = false friend.Block = false
friend.NickName = user.NickName friend.NickName = user.NickName
friend.Profile = user.Avatar friend.Profile = user.Avatar
friend.Write = false
friend.Version = user.Version friend.Version = user.Version
if len(config.UserInfo.Public) > 0 {
friend.State = types.FRIENDSTATEREQUEST
}
MyService.Friend().AddFriend(friend) MyService.Friend().AddFriend(friend)
msg := model.MessageModel{} msg := model.MessageModel{}
@@ -254,10 +277,96 @@ func ProcessingContent(stream quic.Stream) {
msg.UUId = m.UUId msg.UUId = m.UUId
Dial(msg, false) Dial(msg, false)
//agree user
if len(config.UserInfo.Public) == 0 {
msg.Type = types.PERSONAGREEFRIEND
msg.Data = ""
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
Dial(msg, true)
}
break
} else if m.Type == types.PERSONAGREEFRIEND {
MyService.Friend().AgreeFrined(m.From)
break break
} else if m.Type == types.PERSONCANCEL { } else if m.Type == types.PERSONCANCEL {
CancelList[m.UUId] = "cancel" CancelList[m.UUId] = "cancel"
break break
} else if m.Type == types.PERSONSUMMARY {
Summary(m, "upload")
continue
} else if m.Type == types.PERSONUPLOAD {
//TODO:检查是否存在如果存在直接结束
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
task.LocalPath = m.Data.(string)
MyService.Download().AddDownloadTask(task)
friend := MyService.Friend().GetFriendById(model2.FriendModel{Token: m.From})
if friend.Write {
continue
} else {
break
}
} else if m.Type == types.PERSONUPLOADDATA {
r := SaveFile(m, stream)
if r {
break
}
continue
} else if m.Type == types.PERSONINTERNALINSPECTION {
fmt.Println("内网测试")
var ips []string
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
go MyService.Friend().InternalInspection(ips, m.From)
} else if m.Type == types.PERSONPING {
fmt.Println("来自", m.From, "的ping", m.Data)
msg := m
m.To = m.From
m.Data = config.ServerInfo.Token
m.From = config.ServerInfo.Token
SendData(stream, m)
var ips []string
dataModelByte, _ := json.Marshal(msg.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
backIP := false
if v, ok := UDPAddressMap[msg.From]; ok {
for _, ip := range ips {
if ip == v {
backIP = true
break
}
}
}
if !backIP {
fmt.Println("检测需要查询ip", msg.From)
go MyService.Friend().InternalInspection(ips, msg.From)
}
break
} else if m.Type == types.PERSONIMAGETHUMBNAIL {
m.To = m.From
if data, err := file.GetImage(m.Data.(string), 100, 0); err == nil {
m.Data = data
} else {
m.Data = ""
}
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else { } else {
//不应有不做返回的数据 //不应有不做返回的数据
//ServiceMessage <- m //ServiceMessage <- m
@@ -269,7 +378,7 @@ func ProcessingContent(stream quic.Stream) {
} }
//文件分片发送 //文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid string) error { func SendFileData(stream quic.Stream, filePath, to, uuid, t string) error {
summary := model.FileSummaryModel{} summary := model.FileSummaryModel{}
msg := model.MessageModel{} msg := model.MessageModel{}
@@ -341,7 +450,7 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
tran.Length = length tran.Length = length
fileMsg := model.MessageModel{} fileMsg := model.MessageModel{}
fileMsg.Type = types.PERSONDOWNLOAD fileMsg.Type = t
fileMsg.Data = tran fileMsg.Data = tran
fileMsg.From = config.ServerInfo.Token fileMsg.From = config.ServerInfo.Token
fileMsg.To = to fileMsg.To = to
@@ -356,5 +465,18 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
} }
stream.Write(data) stream.Write(data)
} }
record := model2.PersonDownRecordDBModel{}
record.UUID = uuid
record.Name = f.Name()
record.Downloader = to
record.Path = filePath
record.Size = fStat.Size()
record.Type = types.PERSONFILEDOWNLOAD
if t == types.PERSONUPLOADDATA {
record.Type = types.PERSONFILEUPLOAD
}
MyService.DownRecord().AddDownRecord(record)
return nil return nil
} }

View File

@@ -1,7 +1,16 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2021-09-30 18:18:14
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-02 18:00:57
* @FilePath: /CasaOS/service/rely.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package service package service
import ( import (
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -13,8 +22,7 @@ type RelyService interface {
} }
type relyService struct { type relyService struct {
db *gorm.DB db *gorm.DB
log loger2.OLog
} }
func (r *relyService) Create(rely model2.RelyDBModel) { func (r *relyService) Create(rely model2.RelyDBModel) {
@@ -35,6 +43,6 @@ func (r *relyService) Delete(id string) {
r.db.Where("custom_id = ?", id).Delete(&c) r.db.Where("custom_id = ?", id).Delete(&c)
} }
func NewRelyService(db *gorm.DB, log loger2.OLog) RelyService { func NewRelyService(db *gorm.DB) RelyService {
return &relyService{db: db, log: log} return &relyService{db: db}
} }

View File

@@ -1,7 +1,6 @@
package service package service
import ( import (
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"gorm.io/gorm" "gorm.io/gorm"
@@ -12,7 +11,7 @@ var Cache *cache.Cache
var MyService Repository var MyService Repository
var WebSocketConns []*websocket.Conn var WebSocketConns []*websocket.Conn
var NewVersionApp map[string]string
var SocketRun bool var SocketRun bool
type Repository interface { type Repository interface {
@@ -34,29 +33,30 @@ type Repository interface {
Person() PersonService Person() PersonService
Friend() FriendService Friend() FriendService
Download() DownloadService Download() DownloadService
DownRecord() DownRecordService
} }
func NewService(db *gorm.DB, log loger2.OLog) Repository { func NewService(db *gorm.DB) Repository {
return &store{ return &store{
app: NewAppService(db, log), app: NewAppService(db),
ddns: NewDDNSService(db, log),
user: NewUserService(), user: NewUserService(),
docker: NewDockerService(log), docker: NewDockerService(),
//redis: NewRedisService(rp), //redis: NewRedisService(rp),
zima: NewZiMaService(), zima: NewZiMaService(),
casa: NewCasaService(), casa: NewCasaService(),
disk: NewDiskService(log, db), disk: NewDiskService(db),
notify: NewNotifyService(db), notify: NewNotifyService(db),
shareDirectory: NewShareDirService(db, log), shareDirectory: NewShareDirService(db),
task: NewTaskService(db, log), task: NewTaskService(db),
rely: NewRelyService(db, log), rely: NewRelyService(db),
system: NewSystemService(log), system: NewSystemService(),
shortcuts: NewShortcutsService(db), shortcuts: NewShortcutsService(db),
search: NewSearchService(), search: NewSearchService(),
person: NewPersonService(db), person: NewPersonService(db),
friend: NewFriendService(db), friend: NewFriendService(db),
download: NewDownloadService(db), download: NewDownloadService(db),
downrecord: NewDownRecordService(db),
} }
} }
@@ -79,6 +79,11 @@ type store struct {
person PersonService person PersonService
friend FriendService friend FriendService
download DownloadService download DownloadService
downrecord DownRecordService
}
func (c *store) DownRecord() DownRecordService {
return c.downrecord
} }
func (c *store) Download() DownloadService { func (c *store) Download() DownloadService {

View File

@@ -1,13 +1,15 @@
package service package service
import ( import (
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
"os" "os"
"strconv" "strconv"
"github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service/model"
"go.uber.org/zap"
"gorm.io/gorm"
) )
type ShareDirService interface { type ShareDirService interface {
@@ -20,8 +22,7 @@ type ShareDirService interface {
} }
type shareDirService struct { type shareDirService struct {
db *gorm.DB db *gorm.DB
log loger2.OLog
} }
func (s *shareDirService) List(desc bool) []model.ShareDirDBModel { func (s *shareDirService) List(desc bool) []model.ShareDirDBModel {
@@ -305,7 +306,7 @@ func (s *shareDirService) UpConfig() {
// /etc/samba/smb.conf // /etc/samba/smb.conf
f, err := os.OpenFile("/etc/samba/smb.conf", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) f, err := os.OpenFile("/etc/samba/smb.conf", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil { if err != nil {
s.log.Error("file create failed. err: " + err.Error()) loger.Error("Failed to create file", zap.Any("err", err))
} else { } else {
defer f.Close() defer f.Close()
f.WriteString(str) f.WriteString(str)
@@ -318,6 +319,6 @@ func (s *shareDirService) Info(id string) model.ShareDirDBModel {
return m return m
} }
func NewShareDirService(db *gorm.DB, log loger2.OLog) ShareDirService { func NewShareDirService(db *gorm.DB) ShareDirService {
return &shareDirService{db: db, log: log} return &shareDirService{db: db}
} }

View File

@@ -1,13 +1,19 @@
package service package service
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"net" net2 "net"
"os" "os"
"strconv"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger" "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
) )
type SystemService interface { type SystemService interface {
@@ -20,11 +26,47 @@ type SystemService interface {
GetTimeZone() string GetTimeZone() string
UpdateUSBAutoMount(state string) UpdateUSBAutoMount(state string)
ExecUSBAutoMountShell(state string) ExecUSBAutoMountShell(state string)
UpAppOrderFile(str string)
GetAppOrderFile() []byte
GetNet(physics bool) []string
GetNetInfo() []net.IOCountersStat
GetCpuCoreNum() int
GetCpuPercent() float64
GetMemInfo() *mem.VirtualMemoryStat
} }
type systemService struct { type systemService struct {
log loger.OLog log loger.OLog
} }
func (c *systemService) GetMemInfo() *mem.VirtualMemoryStat {
memInfo, _ := mem.VirtualMemory()
memInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", memInfo.UsedPercent), 64)
return memInfo
}
func (c *systemService) GetCpuPercent() float64 {
percent, _ := cpu.Percent(0, false)
value, _ := strconv.ParseFloat(fmt.Sprintf("%.1f", percent[0]), 64)
return value
}
func (c *systemService) GetCpuCoreNum() int {
count, _ := cpu.Counts(false)
return count
}
func (c *systemService) GetNetInfo() []net.IOCountersStat {
parts, _ := net.IOCounters(true)
return parts
}
func (c *systemService) GetNet(physics bool) []string {
t := "1"
if physics {
t = "2"
}
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetNetCard " + t)
}
func (s *systemService) UpdateSystemVersion(version string) { func (s *systemService) UpdateSystemVersion(version string) {
//command2.OnlyExec(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version) //command2.OnlyExec(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
//s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version) //s.log.Error(config.AppInfo.ProjectPath + "/shell/tool.sh -r " + version)
@@ -62,9 +104,15 @@ func (s *systemService) UpSystemConfig(str string, widget string) {
} }
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
} }
func (s *systemService) UpAppOrderFile(str string) {
file.WriteToPath([]byte(str), config.AppInfo.ProjectPath+"/conf", "app_order.json")
}
func (s *systemService) GetAppOrderFile() []byte {
return file.ReadFullFile(config.AppInfo.ProjectPath + "/conf/app_order.json")
}
func (s *systemService) UpdateUSBAutoMount(state string) { func (s *systemService) UpdateUSBAutoMount(state string) {
config.ServerInfo.USBAutoMount = state config.ServerInfo.USBAutoMount = state
config.Cfg.Section("system").Key("USBAutoMount").SetValue(state) config.Cfg.Section("server").Key("USBAutoMount").SetValue(state)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath) config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
} }
func (s *systemService) UpSystemPort(port string) { func (s *systemService) UpSystemPort(port string) {
@@ -90,12 +138,12 @@ func (s *systemService) GetCasaOSLogs(lineNumber int) string {
func GetDeviceAllIP() []string { func GetDeviceAllIP() []string {
var address []string var address []string
addrs, err := net.InterfaceAddrs() addrs, err := net2.InterfaceAddrs()
if err != nil { if err != nil {
return address return address
} }
for _, a := range addrs { for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() { if ipNet, ok := a.(*net2.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To16() != nil { if ipNet.IP.To16() != nil {
address = append(address, ipNet.IP.String()) address = append(address, ipNet.IP.String())
} }
@@ -103,6 +151,6 @@ func GetDeviceAllIP() []string {
} }
return address return address
} }
func NewSystemService(log loger.OLog) SystemService { func NewSystemService() SystemService {
return &systemService{log: log} return &systemService{}
} }

View File

@@ -6,7 +6,6 @@ import (
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper" httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
"github.com/IceWhaleTech/CasaOS/service/model" "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@@ -24,8 +23,7 @@ type TaskService interface {
} }
type taskService struct { type taskService struct {
db *gorm.DB db *gorm.DB
log loger2.OLog
} }
func (s *taskService) List(desc bool) []model.TaskDBModel { func (s *taskService) List(desc bool) []model.TaskDBModel {
@@ -141,6 +139,6 @@ func SyncTask(db *gorm.DB) {
} }
}(list) }(list)
} }
func NewTaskService(db *gorm.DB, log loger2.OLog) TaskService { func NewTaskService(db *gorm.DB) TaskService {
return &taskService{db: db, log: log} return &taskService{db: db}
} }

View File

@@ -11,13 +11,17 @@ import (
"net" "net"
"os" "os"
path2 "path" path2 "path"
"reflect"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/model/notify"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper" "github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
"github.com/IceWhaleTech/CasaOS/pkg/utils/file" "github.com/IceWhaleTech/CasaOS/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
model2 "github.com/IceWhaleTech/CasaOS/service/model" model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types" "github.com/IceWhaleTech/CasaOS/types"
"github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go"
@@ -29,7 +33,7 @@ var PeopleMap map[string]quic.Stream
var Message chan model.MessageModel var Message chan model.MessageModel
var UDPAddressMap map[string]string var UDPAddressMap map[string]string
func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) { func UDPSendData(msg model.MessageModel, localFilePath string) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
Message = make(chan model.MessageModel) Message = make(chan model.MessageModel)
@@ -44,6 +48,65 @@ func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error)
IP: net.IPv4zero, Port: p} //注意端口必须固定 IP: net.IPv4zero, Port: p} //注意端口必须固定
addr := UDPAddressMap[msg.To] addr := UDPAddressMap[msg.To]
ticket := msg.To ticket := msg.To
dstAddr, err := net.ResolveUDPAddr("udp", addr)
session, err := quic.DialContext(ctx, UDPConn, dstAddr, srcAddr.String(), quic_helper.GetClientTlsConfig(ticket), quic_helper.GetQUICConfig())
if err != nil {
if msg.Type == types.PERSONDOWNLOAD {
task := MyService.Download().GetDownloadById(msg.UUId)
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
if config.SystemConfigInfo.Analyse != "False" {
go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
}
return err
}
stream, err := session.OpenStreamSync(ctx)
if err != nil {
if msg.Type == types.PERSONDOWNLOAD {
task := MyService.Download().GetDownloadById(msg.UUId)
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
if config.SystemConfigInfo.Analyse != "False" {
go MyService.Casa().PushConnectionStatus(msg.UUId, err.Error(), msg.From, msg.To, msg.Type)
}
session.CloseWithError(1, err.Error())
return err
}
SayHello(stream, msg.To)
//TODO:发送
SendData(stream, msg)
SendFileData(stream, localFilePath, msg.To, msg.UUId, types.PERSONUPLOADDATA)
stream.Close()
if config.SystemConfigInfo.Analyse != "False" {
go MyService.Casa().PushConnectionStatus(msg.UUId, "OK", msg.From, msg.To, msg.Type)
}
return nil
}
func Dial(msg model.MessageModel, server bool) (m model.MessageModel, err error) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
defer cancel()
Message = make(chan model.MessageModel)
_, port, err := net.SplitHostPort(UDPConn.LocalAddr().String())
if config.ServerInfo.UDPPort != port {
config.ServerInfo.UDPPort = port
config.Cfg.Section("server").Key("UDPPort").SetValue(port)
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
}
p, err := strconv.Atoi(port)
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: p} //注意端口必须固定
addr := UDPAddressMap[msg.To]
ticket := msg.To
if server { if server {
addr = config.ServerInfo.Handshake + ":9527" addr = config.ServerInfo.Handshake + ":9527"
ticket = "bench" ticket = "bench"
@@ -142,139 +205,17 @@ func ReadContent(stream quic.Stream) {
} }
m := model.MessageModel{} m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m) err = json.Unmarshal(messageByte, &m)
fmt.Println("客户端", m)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
break break
} }
if m.Type == types.PERSONDOWNLOAD { if m.Type == types.PERSONDOWNLOAD {
r := SaveFile(m, stream)
dataModelByte, _ := json.Marshal(m.Data) if r {
dataModel := model.TranFileModel{}
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
continue
}
dataLengthByte := make([]byte, 8)
_, err = io.ReadFull(stream, dataLengthByte)
if err != nil {
fmt.Println(err)
continue
}
dataLength, err := strconv.Atoi(string(dataLengthByte))
if err != nil {
fmt.Println(err)
continue
}
dataByte := make([]byte, dataLength)
_, err = io.ReadFull(stream, dataByte)
if err != nil {
fmt.Println(err)
continue
}
sum := md5.Sum(dataByte)
hash := hex.EncodeToString(sum[:])
if dataModel.Hash != hash {
fmt.Println("hash不匹配", hash, dataModel.Hash)
continue
}
tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
file.IsNotExistMkDir(tempPath)
filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
_, err = os.Stat(filepath)
if os.IsNotExist(err) {
err = ioutil.WriteFile(filepath, dataByte, 0644)
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
if err != nil {
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
} else {
if file.GetHashByPath(filepath) != dataModel.Hash {
os.Remove(filepath)
err = ioutil.WriteFile(filepath, dataByte, 0644)
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
if err != nil {
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
}
}
files, err := ioutil.ReadDir(tempPath)
if err != nil {
fmt.Println(err)
continue
}
if len(files) >= dataModel.Length {
summary := MyService.Download().GetDownloadById(m.UUId)
summary.State = types.DOWNLOADFINISH
MyService.Download().EditDownloadState(summary)
fullPath := file.GetNoDuplicateFileName(path2.Join(summary.LocalPath, summary.Name))
file.SpliceFiles(tempPath, fullPath, dataModel.Length, 0)
if file.GetHashByPath(fullPath) == summary.Hash {
file.RMDir(tempPath)
summary.State = types.DOWNLOADFINISHED
MyService.Download().EditDownloadState(summary)
} else {
os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
summary.State = types.DOWNLOADERROR
summary.Error = "hash mismatch"
MyService.Download().SetDownloadError(summary)
}
break break
} }
} else if m.Type == types.PERSONSUMMARY { } else if m.Type == types.PERSONSUMMARY {
Summary(m, "download")
dataModel := model.FileSummaryModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
}
task := MyService.Download().GetDownloadById(m.UUId)
fullPath := path2.Join(task.LocalPath, task.Name)
task.State = types.DOWNLOADING
if len(dataModel.Message) > 0 {
task.State = types.DOWNLOADERROR
task.Error = dataModel.Message
}
if file.Exists(fullPath) && file.GetHashByPath(fullPath) == dataModel.Hash {
task.State = types.DOWNLOADFINISHED
go func(from, uuid string) {
m := model.MessageModel{}
m.Data = ""
m.From = config.ServerInfo.Token
m.To = from
m.Type = types.PERSONCANCEL
m.UUId = uuid
CancelList[uuid] = uuid
Dial(m, false)
}(task.From, task.UUID)
}
task.UUID = m.UUId
task.Name = dataModel.Name
task.Length = dataModel.Length
task.Size = dataModel.Size
task.BlockSize = dataModel.BlockSize
task.Hash = dataModel.Hash
task.Type = 0
task.From = m.From
MyService.Download().SaveDownload(task)
} else if m.Type == types.PERSONCONNECTION { } else if m.Type == types.PERSONCONNECTION {
if len(m.Data.(string)) > 0 { if len(m.Data.(string)) > 0 {
UDPAddressMap[m.From] = m.Data.(string) UDPAddressMap[m.From] = m.Data.(string)
@@ -295,26 +236,49 @@ func ReadContent(stream quic.Stream) {
go Dial(msg, false) go Dial(msg, false)
Message <- m Message <- m
break break
} else if m.Type == "get_ip" { } else if m.Type == types.PERSONGETIP {
notify := model2.AppNotify{} notify := notify.Person{}
notify.CustomId = m.From notify.ShareId = m.From
if len(m.Data.(string)) == 0 { if len(m.Data.(string)) == 0 {
if _, ok := UDPAddressMap[m.From]; ok { if _, ok := UDPAddressMap[m.From]; ok {
notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LEAVE notify.Type = "OFFLINE"
go MyService.Notify().SendText(notify) go MyService.Notify().SendPersonStatusBySocket(notify)
} }
delete(UDPAddressMap, m.From) delete(UDPAddressMap, m.From)
Message <- m Message <- m
break break
} }
if _, ok := UDPAddressMap[m.From]; !ok { if _, ok := UDPAddressMap[m.From]; !ok {
notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LIVE notify.Type = "ONLINE"
go MyService.Notify().SendText(notify) go MyService.Notify().SendPersonStatusBySocket(notify)
} }
UDPAddressMap[m.From] = m.Data.(string) UDPAddressMap[m.From] = m.Data.(string)
if config.ServerInfo.Token != m.From && strings.Split(m.Data.(string), ":")[0] == strings.Split(UDPAddressMap[config.ServerInfo.Token], ":")[0] {
msg := model.MessageModel{}
msg.Type = types.PERSONINTERNALINSPECTION
msg.Data = ip_helper.GetDeviceAllIP(config.ServerInfo.UDPPort)
msg.To = m.From
msg.From = config.ServerInfo.Token
msg.UUId = m.UUId
go Dial(msg, true)
}
Message <- m
break
} else if m.Type == types.PERSONINTERNALINSPECTION {
fmt.Println("接收到反验证")
var ips []string
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &ips)
if err != nil {
fmt.Println(err)
break
}
go MyService.Friend().InternalInspection(ips, m.From)
Message <- m Message <- m
break break
} else { } else {
Message <- m Message <- m
} }
} }
@@ -334,23 +298,55 @@ func SendIPToServer() {
func LoopFriend() { func LoopFriend() {
list := MyService.Friend().GetFriendList() list := MyService.Friend().GetFriendList()
msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
for i := 0; i < len(list); i++ { for i := 0; i < len(list); i++ {
msg := model.MessageModel{} if _, ok := UDPAddressMap[list[i].Token]; !ok {
msg.Type = "get_ip" msg := model.MessageModel{}
msg.Type = types.PERSONGETIP
msg.Data = ""
msg.From = config.ServerInfo.Token
msg.To = list[i].Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
}
msg.Type = types.PERSONPING
msg.Data = "" msg.Data = ""
msg.From = config.ServerInfo.Token msg.From = config.ServerInfo.Token
msg.To = list[i].Token msg.To = list[i].Token
msg.UUId = uuid.NewV4().String() msg.UUId = uuid.NewV4().String()
Dial(msg, true) if v, ok := UDPAddressMap[list[i].Token]; ok {
if ip_helper.HasLocalIP(net.ParseIP(strings.Split(v, ":")[0])) {
msg.Data = ip_helper.GetDeviceAllIP(config.ServerInfo.UDPPort)
}
oldIP := UDPAddressMap[list[i].Token]
data, err := Dial(msg, false)
if err != nil || reflect.DeepEqual(data, model.MessageModel{}) || len(data.Data.(string)) == 0 {
if oldIP == UDPAddressMap[list[i].Token] {
notify := notify.Person{}
notify.ShareId = data.From
notify.Type = "LEAVE"
go MyService.Notify().SendPersonStatusBySocket(notify)
msg.Type = types.PERSONHELLO delete(UDPAddressMap, list[i].Token)
msg.Data = ""
msg.From = config.ServerInfo.Token msg := model.MessageModel{}
msg.To = list[i].Token msg.Type = types.PERSONGETIP
msg.UUId = uuid.NewV4().String() msg.Data = ""
if _, ok := UDPAddressMap[list[i].Token]; ok { msg.From = config.ServerInfo.Token
go Dial(msg, false) msg.To = list[i].Token
msg.UUId = uuid.NewV4().String()
Dial(msg, true)
}
}
} }
go func(shareId string) { go func(shareId string) {
user := MyService.Casa().GetUserInfoByShareId(shareId) user := MyService.Casa().GetUserInfoByShareId(shareId)
@@ -368,3 +364,140 @@ func LoopFriend() {
} }
} }
//file summary
func Summary(m model.MessageModel, t string) {
dataModel := model.FileSummaryModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
}
task := MyService.Download().GetDownloadById(m.UUId)
task.State = types.DOWNLOADING
fullPath := path2.Join(task.LocalPath, task.Name)
if len(dataModel.Message) > 0 {
task.State = types.DOWNLOADERROR
task.Error = dataModel.Message
}
//The file already exists and the file is the same, no need to download
if t != "upload" && file.Exists(fullPath) && file.GetHashByPath(fullPath) == dataModel.Hash {
task.State = types.DOWNLOADFINISHED
go func(from, uuid string) {
m := model.MessageModel{}
m.Data = ""
m.From = config.ServerInfo.Token
m.To = from
m.Type = types.PERSONCANCEL
m.UUId = uuid
CancelList[uuid] = uuid
Dial(m, false)
}(task.From, task.UUID)
}
task.UUID = m.UUId
task.Name = dataModel.Name
task.Length = dataModel.Length
task.Size = dataModel.Size
task.BlockSize = dataModel.BlockSize
task.Hash = dataModel.Hash
task.Type = types.PERSONFILEDOWNLOAD
task.From = m.From
if t == "upload" {
task.Type = types.PERSONFILERECEIVEUPLOAD
}
MyService.Download().SaveDownload(task)
}
//Save file fragment
func SaveFile(m model.MessageModel, stream quic.Stream) bool {
dataModelByte, _ := json.Marshal(m.Data)
dataModel := model.TranFileModel{}
err := json.Unmarshal(dataModelByte, &dataModel)
if err != nil {
fmt.Println(err)
return false
}
dataLengthByte := make([]byte, 8)
_, err = io.ReadFull(stream, dataLengthByte)
if err != nil {
fmt.Println(err)
return false
}
dataLength, err := strconv.Atoi(string(dataLengthByte))
if err != nil {
fmt.Println(err)
return false
}
dataByte := make([]byte, dataLength)
_, err = io.ReadFull(stream, dataByte)
if err != nil {
fmt.Println(err)
return false
}
sum := md5.Sum(dataByte)
hash := hex.EncodeToString(sum[:])
if dataModel.Hash != hash {
fmt.Println("hash不匹配", hash, dataModel.Hash)
return false
}
tempPath := config.AppInfo.RootPath + "/temp" + "/" + m.UUId
file.IsNotExistMkDir(tempPath)
filepath := tempPath + "/" + strconv.Itoa(dataModel.Index)
_, err = os.Stat(filepath)
if os.IsNotExist(err) {
err = ioutil.WriteFile(filepath, dataByte, 0644)
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
if err != nil {
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
} else {
if file.GetHashByPath(filepath) != dataModel.Hash {
os.Remove(filepath)
err = ioutil.WriteFile(filepath, dataByte, 0644)
task := model2.PersonDownloadDBModel{}
task.UUID = m.UUId
if err != nil {
task.Error = err.Error()
task.State = types.DOWNLOADERROR
MyService.Download().SetDownloadError(task)
}
}
}
files, err := ioutil.ReadDir(tempPath)
if err != nil {
fmt.Println(err)
return false
}
if len(files) >= dataModel.Length {
summary := MyService.Download().GetDownloadById(m.UUId)
summary.State = types.DOWNLOADFINISH
MyService.Download().EditDownloadState(summary)
fullPath := file.GetNoDuplicateFileName(path2.Join(summary.LocalPath, summary.Name))
file.SpliceFiles(tempPath, fullPath, dataModel.Length, 0)
if file.GetHashByPath(fullPath) == summary.Hash {
file.RMDir(tempPath)
summary.State = types.DOWNLOADFINISHED
MyService.Download().EditDownloadState(summary)
} else {
os.Remove(config.FileSettingInfo.DownloadDir + "/" + summary.Name)
summary.State = types.DOWNLOADERROR
summary.Error = "hash mismatch"
MyService.Download().SetDownloadError(summary)
}
return true
}
return false
}

View File

@@ -9,7 +9,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"unsafe"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -19,18 +18,12 @@ import (
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
) )
//系统信息 //系统信息
type ZiMaService interface { type ZiMaService interface {
GetCpuPercent() float64
GetCpuCoreNum() int
GetMemInfo() *mem.VirtualMemoryStat
GetDiskInfo() *disk.UsageStat GetDiskInfo() *disk.UsageStat
GetNetInfo() []net.IOCountersStat
GetNet(physics bool) []string
GetNetState(name string) string GetNetState(name string) string
GetSysInfo() host.InfoStat GetSysInfo() host.InfoStat
GetDirPath(path string) []model.Path GetDirPath(path string) []model.Path
@@ -39,6 +32,7 @@ type ZiMaService interface {
CreateFile(path string) (int, error) CreateFile(path string) (int, error)
RenameFile(oldF, newF string) (int, error) RenameFile(oldF, newF string) (int, error)
GetCpuInfo() []cpu.InfoStat GetCpuInfo() []cpu.InfoStat
GetDeviceTree() string
} }
var NetArray [][]model.IOCountersStat var NetArray [][]model.IOCountersStat
@@ -46,32 +40,12 @@ var NetArray [][]model.IOCountersStat
type zima struct { type zima struct {
} }
//获取cpu占用率
func (c *zima) GetCpuPercent() float64 {
percent, _ := cpu.Percent(0, false)
value, _ := strconv.ParseFloat(fmt.Sprintf("%.1f", percent[0]), 64)
return value
}
//获取物理核心数
func (c *zima) GetCpuCoreNum() int {
count, _ := cpu.Counts(false)
return count
}
//cpu详情 //cpu详情
func (c *zima) GetCpuInfo() []cpu.InfoStat { func (c *zima) GetCpuInfo() []cpu.InfoStat {
info, _ := cpu.Info() info, _ := cpu.Info()
return info return info
} }
//获取内存详情
func (c *zima) GetMemInfo() *mem.VirtualMemoryStat {
memInfo, _ := mem.VirtualMemory()
memInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", memInfo.UsedPercent), 64)
return memInfo
}
//获取硬盘详情 //获取硬盘详情
func (c *zima) GetDiskInfo() *disk.UsageStat { func (c *zima) GetDiskInfo() *disk.UsageStat {
path := "/" path := "/"
@@ -86,6 +60,16 @@ func (c *zima) GetDiskInfo() *disk.UsageStat {
//获取硬盘目录 //获取硬盘目录
func (c *zima) GetDirPath(path string) []model.Path { func (c *zima) GetDirPath(path string) []model.Path {
if path == "/DATA" {
sysType := runtime.GOOS
if sysType == "windows" {
path = "C:\\CasaOS\\DATA"
}
if sysType == "darwin" {
path = "./CasaOS/DATA"
}
}
ls, _ := ioutil.ReadDir(path) ls, _ := ioutil.ReadDir(path)
dirs := []model.Path{} dirs := []model.Path{}
@@ -130,13 +114,8 @@ func (c *zima) GetSysInfo() host.InfoStat {
return *info return *info
} }
//shell脚本参数 {1:虚拟网卡 2:物理网卡} func (c *zima) GetDeviceTree() string {
func (c *zima) GetNet(physics bool) []string { return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDeviceTree")
t := "1"
if physics {
t = "2"
}
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetNetCard " + t)
} }
//shell脚本参数 { 网卡名称 } //shell脚本参数 { 网卡名称 }
@@ -144,13 +123,6 @@ func (c *zima) GetNetState(name string) string {
return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;CatNetCardState " + name) return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;CatNetCardState " + name)
} }
//网络信息
func (c *zima) GetNetInfo() []net.IOCountersStat {
parts, _ := net.IOCounters(true)
//fmt.Println(net.ConntrackStatsWithContext(true))
return parts
}
//mkdir //mkdir
func (c *zima) MkdirAll(path string) (int, error) { func (c *zima) MkdirAll(path string) (int, error) {
_, err := os.Stat(path) _, err := os.Stat(path)
@@ -204,40 +176,40 @@ func NewZiMaService() ZiMaService {
return &zima{} return &zima{}
} }
func LoopNet() { // func LoopNet() {
netList := MyService.ZiMa().GetNetInfo() // netList := MyService.ZiMa().GetNetInfo()
nets := MyService.ZiMa().GetNet(true) // nets := MyService.ZiMa().GetNet(true)
num := 0 // num := 0
for i := 0; i < len(netList); i++ { // for i := 0; i < len(netList); i++ {
for _, netCardName := range nets { // for _, netCardName := range nets {
if netList[i].Name == netCardName { // if netList[i].Name == netCardName {
var netArray []model.IOCountersStat // var netArray []model.IOCountersStat
if len(NetArray) < (num + 1) { // if len(NetArray) < (num + 1) {
netArray = []model.IOCountersStat{} // netArray = []model.IOCountersStat{}
} else { // } else {
netArray = NetArray[num] // netArray = NetArray[num]
} // }
item := *(*model.IOCountersStat)(unsafe.Pointer(&netList[i])) // item := *(*model.IOCountersStat)(unsafe.Pointer(&netList[i]))
item.State = strings.TrimSpace(MyService.ZiMa().GetNetState(netList[i].Name)) // item.State = strings.TrimSpace(MyService.ZiMa().GetNetState(netList[i].Name))
item.Time = time.Now().Unix() // item.Time = time.Now().Unix()
if len(netArray) >= 60 { // if len(netArray) >= 60 {
netArray = netArray[1:] // netArray = netArray[1:]
} // }
netArray = append(netArray, item) // netArray = append(netArray, item)
if len(NetArray) < (num + 1) { // if len(NetArray) < (num + 1) {
NetArray = append(NetArray, []model.IOCountersStat{}) // NetArray = append(NetArray, []model.IOCountersStat{})
} // }
NetArray[num] = netArray // NetArray[num] = netArray
num++ // num++
break // break
} // }
} // }
} // }
} // }

View File

@@ -32,7 +32,7 @@ GetNetCard() {
GetTimeZone(){ GetTimeZone(){
timedatectl | grep "Time zone" | awk '{print $3}' timedatectl | grep "Time zone" | awk '{printf $3}'
} }
#查看网卡状态 #查看网卡状态
@@ -342,3 +342,7 @@ USB_Remove_File() {
$sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules $sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules
$sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service $sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service
} }
GetDeviceTree(){
cat /proc/device-tree/model
}

View File

@@ -1 +0,0 @@
package types

7
types/friend.go Normal file
View File

@@ -0,0 +1,7 @@
package types
const (
FRIENDSTATEDEFAULT = iota
FRIENDSTATEWAIT
FRIENDSTATEREQUEST
)

View File

@@ -12,6 +12,7 @@ const (
NOTIFY_TYPE_INSTALL_LOG NOTIFY_TYPE_INSTALL_LOG
NOTIFY_TYPE_PERSION_FIRNED_LEAVE NOTIFY_TYPE_PERSION_FIRNED_LEAVE
NOTIFY_TYPE_PERSION_FIRNED_LIVE NOTIFY_TYPE_PERSION_FIRNED_LIVE
NOTIFY_TYPE_HEALTH_CHECK
) )
const ( const (

View File

@@ -1,9 +1,24 @@
package types package types
const PERSONADDFRIEND = "add_user" const PERSONADDFRIEND = "add_user"
const PERSONAGREEFRIEND = "agree_user"
const PERSONDOWNLOAD = "file_data" const PERSONDOWNLOAD = "file_data"
const PERSONSUMMARY = "summary" const PERSONSUMMARY = "summary"
const PERSONGETIP = "get_ip"
const PERSONCONNECTION = "connection" const PERSONCONNECTION = "connection"
const PERSONDIRECTORY = "directory" const PERSONDIRECTORY = "directory"
const PERSONHELLO = "hello" const PERSONHELLO = "hello"
const PERSONSHAREID = "share_id"
const PERSONUPLOAD = "upload"
const PERSONUPLOADDATA = "upload_data"
const PERSONINTERNALINSPECTION = "internal_inspection"
const PERSONPING = "ping"
const PERSONIMAGETHUMBNAIL = "image_thumbnail"
const PERSONCANCEL = "cancel" // Cancel Download const PERSONCANCEL = "cancel" // Cancel Download
const (
PERSONFILEDOWNLOAD = iota //default state
PERSONFILEUPLOAD
PERSONFILERECEIVEUPLOAD //receive upload file
)

View File

@@ -1,5 +1,15 @@
/*
* @Author: LinkLeong link@icewhale.com
* @Date: 2022-02-17 18:53:22
* @LastEditors: LinkLeong
* @LastEditTime: 2022-06-13 19:24:15
* @FilePath: /CasaOS/types/system.go
* @Description:
* @Website: https://www.casaos.io
* Copyright (c) 2022 by icewhale, All Rights Reserved.
*/
package types package types
const CURRENTVERSION = "0.3.0" const CURRENTVERSION = "0.3.2.1"
const BODY = "<li>Add CasaConnect function, now you can share private files peer-to-peer with your friends.</li><li>Add a widget for network traffic monitoring</li><li>Updated the initial directory of Files to the Root directory</li><li>Fix the application ipv6 opening problem</li>" const BODY = ""

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -1,17 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(1)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#9fda1e" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<g transform="matrix(3.7796 0 0 3.7796 -89.043 4.424)" fill="#fff" opacity=".75">
<path d="m34.671 7.0315v1.7198c0 0.07329 0.059 0.13229 0.13229 0.13229h0.79374c0.07329 0 0.13229-0.059 0.13229-0.13229v-1.7198zm0.26458 1.0583h0.52916v0.52916h-0.52916z" color="#000000"/>
<path d="m35.2-0.11215v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916z" color="#000000"/>
</g>
<path d="m32.883 44.933 2.1667-2.1667c0.33333-0.33333 0.33333-0.85 0-1.1833-0.33333-0.33333-0.85-0.33333-1.1833 0l-2.4667 2.4667c-1.3166-0.66667-2.8166-1.05-4.4-1.05-1.6 0-3.1001 0.38333-4.4332 1.05l-2.4833-2.4667c-0.33333-0.33333-0.85-0.33333-1.1833 0-0.33333 0.33333-0.33333 0.85 0 1.1833l2.1833 2.1833c-2.4667 1.8167-4.0833 4.7334-4.0833 8.05h20c0-3.3166-1.6167-6.2501-4.1168-8.0667zm-9.4547 4.4953h-1.4286v-1.4286h1.4286zm8.5713 0h-1.4286v-1.4286h1.4286z" enable-background="new" fill="#fff" opacity=".75" stroke-width="1.6667"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,17 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333 0 0 2.3333 -68.667 -72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(.26458)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#84c835" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<g transform="translate(-14.713 -.1522)">
<path d="m22.651 6.7667v1.7198c0 0.073288 0.059 0.13229 0.13229 0.13229h0.79374c0.07329 0 0.13229-0.059001 0.13229-0.13229v-1.7198zm0.26458 1.0583h0.52916v0.52916h-0.52916z" color="#000000" fill="#fff"/>
<path d="m23.18 1.2105h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916zm0 0.52916h-0.52916v0.52916h0.52916zm0 0.52916v0.52916h0.52916v-0.52916z" color="#000000" fill="#fff"/>
<path d="m25.359 10.922 0.80255-0.80255c0.12347-0.12347 0.12347-0.31485 0-0.43832s-0.31485-0.12347-0.43832 0l-0.91368 0.91368c-0.4877-0.24694-1.0433-0.38893-1.6298-0.38893-0.59266 0-1.1483 0.14199-1.6421 0.38893l-0.91985-0.91368c-0.12347-0.12347-0.31485-0.12347-0.43832 0s-0.12347 0.31485 0 0.43832l0.80873 0.80873c-0.91368 0.67291-1.5125 1.7533-1.5125 2.9818h7.4082c0-1.2285-0.59883-2.3151-1.5249-2.988zm-3.5021 1.6651h-0.52916v-0.52916h0.52916zm3.1749 0h-0.52916v-0.52916h0.52916z" enable-background="new" fill="#0c2809" opacity=".5" stroke-width=".61735"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="64" height="64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333 0 0 2.3333 -68.667 -72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<rect x="8" y="4" width="48" height="56" ry="5" fill="#f55" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
<path d="m30.662 18.545-1.291 1.666-2.0508-0.4668-0.55664 2.0293-2.0742 0.35547 0.26367 2.0879-1.7812 1.123 1.0449 1.8281-1.2168 1.7188 1.6621 1.2891-0.46289 2.0527 2.0293 0.55469 0.35547 2.0742 0.8125-0.10352v10.404l4.5938-3.3418 4.5938 3.3418v-9.832l0.09766 0.02344 0.55664-2.0293 2.0742-0.35742-0.26562-2.0879 1.7812-1.1211-1.043-1.8301 1.2148-1.7168-1.6621-1.291 0.46484-2.0508-2.0293-0.55664-0.35547-2.0723-2.0879 0.26367-1.123-1.7812-1.8281 1.043zm1.3379 4.3066a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5z" color="#4d4d4d" color-rendering="auto" fill="#fff" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -1,13 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333 0 0 2.3333 -68.667 -72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(.26458)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#84c835" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<path d="m8.4664 10.961-2.4942-2.4944 2.4942-2.4941 0.83147 0.83132-1.6629 1.6627 0.83142 0.83147 2.4942-2.4941-2.1727-2.1727c-0.17742-0.17757-0.4652-0.17757-0.64277 0l-3.5142 3.5142c-0.17742 0.17742-0.17742 0.4652 0 0.64277l3.5142 3.5141c0.17757 0.17757 0.46535 0.17757 0.64277 0l3.5142-3.5141c0.17742-0.17757 0.17742-0.46535 0-0.64277l-0.51016-0.51001z" enable-background="new" fill="#fff" stroke-width=".050576"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,13 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(.26458)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#341c05" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".5" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<path class="st1" d="m6.8166 9.7034-0.3832 1.4552c-0.0097 0.03881-0.02425 0.0485-0.07276 0.0485h-0.71304c-0.04851 0-0.05821-0.01455-0.04851-0.07276l1.3776-4.8215c0.02425-0.08731 0.0388-0.16492 0.04851-0.4026 0-0.03395 0.01455-0.0485 0.0388-0.0485h1.0186c0.03395 0 0.04851 0.0097 0.05821 0.0485l1.5425 5.2338c0.0097 0.03881 0 0.06306-0.0388 0.06306h-0.8052c-0.0388 0-0.06306-0.0097-0.07276-0.04366l-0.4026-1.46zm1.3485-0.7858c-0.13582-0.53842-0.45596-1.7123-0.57722-2.2798h-0.0097c-0.10186 0.56752-0.35894 1.5279-0.56267 2.2798zm2.1828-2.6969c0-0.31044 0.21828-0.49476 0.49476-0.49476 0.29589 0 0.49476 0.19887 0.49476 0.49476 0 0.32014-0.20858 0.49476-0.50446 0.49476-0.28134 0-0.48506-0.17462-0.48506-0.49476zm0.05821 1.1011c0-0.0388 0.01455-0.05821 0.05821-0.05821h0.76154c0.0388 0 0.05821 0.01455 0.05821 0.05821v3.8271c0 0.0388-0.0097 0.05821-0.05821 0.05821h-0.75185c-0.04851 0-0.06306-0.02425-0.06306-0.06306v-3.8223z" enable-background="new" fill="#ff7c00" stroke-width=".048506"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,22 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="b" x1="-666.12" x2="-553.27" y1="413.04" y2="525.91" gradientTransform="matrix(.99884 0 0 .9987 689.01 -388.84)" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
<linearGradient id="a">
<stop stop-color="#3b3b3b" offset="0"/>
<stop stop-color="#fff" offset="1"/>
</linearGradient>
<linearGradient id="c" x1="-553.27" x2="-666.12" y1="525.91" y2="413.05" gradientTransform="matrix(.99884 0 0 .9987 689.01 -388.84)" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
<linearGradient id="d" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(.26458)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#f4f4f4" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#d)" fill-rule="evenodd" opacity=".1" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<g transform="matrix(.049608 0 0 .049608 4.4978 4.4978)" enable-background="new" fill-rule="evenodd">
<path d="m79.865 119.1c35.398 48.255 70.04-13.469 69.989-50.587-0.0602-43.886-44.541-68.414-70.018-68.414-40.892 0-79.836 33.796-79.836 80.036 0 51.396 44.64 79.865 79.836 79.865-7.9645-1.1468-34.506-6.834-34.863-67.967-0.23987-41.347 13.488-57.866 34.805-50.599 0.47743 0.17707 23.514 9.2645 23.514 38.951 0 29.56-23.427 38.715-23.427 38.715z" color="#000000" fill="url(#b)"/>
<path d="m79.823 41.401c-23.39-8.0619-52.043 11.216-52.043 49.829 0 63.048 46.721 68.77 52.384 68.77 40.892 0 79.836-33.796 79.836-80.036 0-51.396-44.64-79.865-79.836-79.865 9.7481-1.35 52.541 10.55 52.541 69.037 0 38.141-31.953 58.905-52.735 50.033-0.47743-0.17707-23.514-9.2645-23.514-38.951 0-29.56 23.367-38.818 23.367-38.818z" color="#000000" fill="url(#c)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,13 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(1)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#994b91" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<path d="m22 21c-0.554 0-1 0.446-1 1v20c0 0.554 0.446 1 1 1h18c0.554 0 1-0.446 1-1v-1h1c0.554 0 1-0.446 1-1v-4c0-0.186-0.064344-0.351-0.15234-0.5 0.088-0.149 0.15234-0.314 0.15234-0.5v-4c0-0.186-0.064344-0.351-0.15234-0.5 0.088-0.149 0.15234-0.314 0.15234-0.5v-4c0-0.554-0.446-1-1-1h-1v-3c0-0.554-0.446-1-1-1h-18zm1 3h7v1h-7v-1zm9 0h7v1h-7v-1zm9 2h1v4h-1v-4zm-18 1h7v1h-7v-1zm9 0h7v1h-7v-1zm-9 3h7v1h-7v-1zm9 0h7v1h-7v-1zm9 1h1v4h-1v-4zm-18 2h7v1h-7v-1zm9 0h7v1h-7v-1zm-9 3h7v1h-7v-1zm9 0h7v1h-7v-1zm9 0h1v4h-1v-4zm-18 3h7v1h-7v-1zm9 0h7v1h-7v-1z" color="#000000" color-rendering="auto" fill="#fff" image-rendering="auto" opacity=".75" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,18 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(1)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#576dab" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<g transform="translate(-52.837 -2.8601)">
<path transform="translate(52.837 2.8601)" d="m32 17.301-13.363 10.025c-0.02875 0.0187-0.054801 0.0418-0.082031 0.0625l-0.015626 0.011719v0.001953c-0.3259 0.2559-0.53906 0.64931-0.53906 1.0977v12.199c2e-6 2 1.5771 2 2 2h24s2 0 2-2v-12.199c0-0.45851-0.22189-0.86016-0.56055-1.1152l0.005859-0.007813-13.445-10.076zm0 6.3984a5 5 0 0 1 5 5v1.5c0 0.831-0.669 1.5-1.5 1.5-0.61296 0-1.1359-0.36612-1.3691-0.89062a3 3 0 0 1-2.1309 0.89062 3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3v1.5c0 0.277 0.223 0.5 0.5 0.5s0.5-0.223 0.5-0.5v-1.5a4 4 0 0 0-4-4 4 4 0 0 0-4 4 4 4 0 0 0 4 4h3.5c0.277 0 0.5 0.223 0.5 0.5s-0.223 0.5-0.5 0.5h-3.5a5 5 0 0 1-5-5 5 5 0 0 1 5-5zm0 3a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" fill="#fff" opacity=".75"/>
<path transform="translate(52.837 2.8601)" d="m22.5 20.699c-0.831 0-1.5 0.66967-1.5 1.5v15.002c0 0.83033 0.669 1.498 1.5 1.498h19c0.831 0 1.5-0.66772 1.5-1.498v-15.002c0-0.83033-0.669-1.5-1.5-1.5h-19zm9.5 3a5 5 0 0 1 5 5v1.5c0 0.831-0.669 1.5-1.5 1.5-0.61296 0-1.1359-0.36612-1.3691-0.89062a3 3 0 0 1-2.1309 0.89062 3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3v1.5c0 0.277 0.223 0.5 0.5 0.5s0.5-0.223 0.5-0.5v-1.5a4 4 0 0 0-4-4 4 4 0 0 0-4 4 4 4 0 0 0 4 4h3.5c0.277 0 0.5 0.223 0.5 0.5s-0.223 0.5-0.5 0.5h-3.5a5 5 0 0 1-5-5 5 5 0 0 1 5-5zm0 3a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2z" enable-background="new" fill="#fff"/>
<path d="m70.837 31.36 26.6 18.2-24.6-2e-4c-1 0-2-0.5-2-2z" enable-background="new" fill="#e8ebf0"/>
<path d="m96.837 49.56c2-2e-5 2-2 2-2l-1e-5 -16.2-26.6 18.2z" enable-background="new" fill="#f2f2fa"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,16 +0,0 @@
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="a" x1="49.571" x2="51.714" y1="52.714" y2="54.857" gradientTransform="matrix(2.3333,0,0,2.3333,-68.667,-72.001)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<g transform="scale(1)">
<rect x="8" y="4" width="48" height="56" ry="5" fill="#4747b5" style="paint-order:stroke fill markers"/>
<path d="m56 46-14 14h9c2.77 0 5-2.23 5-5z" fill="url(#a)" fill-rule="evenodd" opacity=".15" stroke-width="8.8191" style="paint-order:stroke fill markers"/>
</g>
<g transform="matrix(3.7796 0 0 3.7796 -75.6 4.949)" fill="#fff" stroke-width=".088193">
<path d="m28.768 3.453c-1.2902 0.22976-2.5811 0.53461-3.8713 0.76016 0 1.9626-8.5e-4 3.9261 0 5.8896 1.2835 0.22471 2.5677 0.52447 3.8486 0.75844h0.38441v-7.4082zm-0.49905 2.3996-0.5944 2.4951-0.48788-0.03847c-0.11193-0.55714-0.24233-1.1109-0.34248-1.6706-0.09847 0.54368-0.2265 1.0823-0.33928 1.6226-0.16159-0.0084-0.32392-0.01852-0.48635-0.02946-0.13971-0.74062-0.30388-1.4762-0.43432-2.2185 0.14392-0.0067 0.28868-0.01258 0.4326-0.01763 0.08668 0.53611 0.18512 1.0697 0.26087 1.6066 0.11867-0.55041 0.23994-1.1008 0.35777-1.6512 0.15991-0.0093 0.31979-0.01599 0.47969-0.02441 0.11193 0.56809 0.22634 1.1352 0.34753 1.7008 0.0951-0.58408 0.20033-1.1664 0.30217-1.7496 0.16832-0.0059 0.33662-0.01517 0.5041-0.02527z" enable-background="new"/>
<path d="m29.395 4.5113h2.6458v5.2916h-2.6458v-0.52916h2.1166v-0.26458h-2.1166v-0.52916h2.1166v-0.26458h-2.1166v-0.52916h2.1166v-0.26458h-2.1166v-0.52916h2.1166v-0.26458h-2.1166v-0.52823h2.1166v-0.2655h-2.1166v-0.52916h2.1166v-0.26458h-2.1166z" enable-background="new"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

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