359
CHANGELOG.md
Normal file
|
@ -0,0 +1,359 @@
|
|||
# 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.1-pre] - 2022-05-13
|
||||
|
||||
### 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
|
||||
|
||||
### Security
|
||||
|
||||
### 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
|
@ -1 +1 @@
|
|||
Subproject commit 4a8f15711ee5520f6bb644107f1eb25f252689b1
|
||||
Subproject commit 2f6deb2253df1d0247d5329cb0ea1aa983053a2e
|
|
@ -16,33 +16,27 @@ RootPath = /casaOS
|
|||
HttpPort = 8089
|
||||
UDPPort =
|
||||
RunMode = release
|
||||
ServerApi = https://api.casaos.zimaboard.com
|
||||
ServerApi = https://api.casaos.io
|
||||
Handshake = socket.casaos.io
|
||||
Token =
|
||||
USBAutoMount = true
|
||||
|
||||
USBAutoMount =
|
||||
|
||||
[user]
|
||||
UserName = admin
|
||||
PWD = zimaboard
|
||||
UserName =
|
||||
PWD =
|
||||
Email = user@gmail.com
|
||||
Description = description
|
||||
Initialized = false
|
||||
Avatar =
|
||||
NickName =
|
||||
|
||||
[redis]
|
||||
Host = 127.0.0.1:6379
|
||||
Password =
|
||||
MaxIdle = 30
|
||||
MaxActive = 30
|
||||
IdleTimeout = 200
|
||||
PublicKey =
|
||||
|
||||
[system]
|
||||
ConfigStr =
|
||||
WidgetList =
|
||||
Analyse =
|
||||
|
||||
|
||||
[file]
|
||||
ShareDir =
|
||||
DownloadDir =
|
BIN
github.com/IceWhaleTech/CasaOS-linux-amd64
Executable file
BIN
github.com/IceWhaleTech/CasaOS-linux-arm64
Executable file
5
go.mod
|
@ -3,16 +3,19 @@ module github.com/IceWhaleTech/CasaOS
|
|||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Curtis-Milo/nat-type-identifier-go v0.0.0-20220215191915-18d42168c63d
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.22 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.7.0
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/containerd/containerd v1.5.7
|
||||
github.com/containerd/continuity v0.2.0 // indirect
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/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/gin-contrib/gzip v0.0.2
|
||||
github.com/gin-gonic/gin v1.7.2
|
||||
|
|
32
go.sum
|
@ -56,6 +56,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
|
|||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
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/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/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
|
@ -82,8 +84,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/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/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.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
|
@ -99,8 +99,6 @@ 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-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/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -269,6 +267,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 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/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/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=
|
||||
|
@ -289,6 +289,18 @@ 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/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/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 v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
|
@ -330,6 +342,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/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.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/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=
|
||||
|
@ -400,6 +415,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|||
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/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/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=
|
||||
|
@ -516,6 +534,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/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/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/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
|
@ -935,6 +954,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/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-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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
|
@ -957,7 +978,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.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
|
||||
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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -991,6 +1011,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-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-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-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
|
@ -1342,6 +1363,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.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.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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
|
|
51
main.go
|
@ -4,7 +4,6 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/cache"
|
||||
|
@ -13,6 +12,8 @@ import (
|
|||
loger2 "github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
"github.com/IceWhaleTech/CasaOS/route"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
|
||||
"github.com/robfig/cron"
|
||||
"gorm.io/gorm"
|
||||
|
@ -21,7 +22,7 @@ import (
|
|||
var sqliteDB *gorm.DB
|
||||
|
||||
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")
|
||||
|
||||
func init() {
|
||||
|
@ -29,25 +30,10 @@ func init() {
|
|||
config.InitSetup(*configFlag)
|
||||
config.UpdateSetup()
|
||||
loger2.LogSetup()
|
||||
sysType := runtime.GOOS
|
||||
if sysType == "windows" {
|
||||
config.AppInfo.ProjectPath = "C:\\CasaOS\\service"
|
||||
config.Cfg.Section("app").Key("ProjectPath").SetValue("C:\\CasaOS\\service")
|
||||
|
||||
config.AppInfo.RootPath = "C:\\CasaOS"
|
||||
config.Cfg.Section("app").Key("RootPath").SetValue("C:\\CasaOS")
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
if len(*dbFlag) == 0 {
|
||||
*dbFlag = config.AppInfo.ProjectPath + "/db"
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
config.AppInfo.ProjectPath = "./CasaOS/service"
|
||||
config.Cfg.Section("app").Key("ProjectPath").SetValue("./CasaOS/service")
|
||||
|
||||
config.AppInfo.RootPath = "./CasaOS"
|
||||
config.Cfg.Section("app").Key("RootPath").SetValue("./CasaOS")
|
||||
config.Cfg.SaveTo(config.SystemConfigInfo.ConfigPath)
|
||||
}
|
||||
|
||||
sqliteDB = sqlite.GetDb(config.AppInfo.ProjectPath)
|
||||
sqliteDB = sqlite.GetDb(*dbFlag)
|
||||
//gredis.GetRedisConn(config.RedisInfo),
|
||||
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
|
||||
service.Cache = cache.Init()
|
||||
|
@ -58,10 +44,13 @@ func init() {
|
|||
service.UDPAddressMap = make(map[string]string)
|
||||
//go service.SocketConnect()
|
||||
service.CancelList = make(map[string]string)
|
||||
service.InternalInspection = make(map[string][]string)
|
||||
service.NewVersionApp = make(map[string]string)
|
||||
route.InitFunction()
|
||||
|
||||
go service.SendIPToServer()
|
||||
go service.LoopFriend()
|
||||
// go service.LoopFriend()
|
||||
// go service.MyService.App().CheckNewImage()
|
||||
|
||||
}
|
||||
|
||||
|
@ -97,20 +86,22 @@ func main() {
|
|||
service.SendIPToServer()
|
||||
|
||||
service.LoopFriend()
|
||||
service.MyService.App().CheckNewImage()
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
err = cron2.AddFunc("0/1 * * * * *", func() {
|
||||
notify := model2.AppNotify{}
|
||||
notify.CustomId = ""
|
||||
notify.Type = types.NOTIFY_TYPE_HEALTH_CHECK
|
||||
|
||||
go service.MyService.Notify().SendText(notify)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
// err = cron2.AddFunc("0/1 * * * * *", func() {
|
||||
|
||||
// //service.SendIPToServer()
|
||||
// //service.LoopNet()
|
||||
|
||||
// })
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
cron2.Start()
|
||||
defer cron2.Stop()
|
||||
s := &http.Server{
|
||||
|
|
|
@ -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
|
||||
|
||||
type AppAnalyse struct {
|
||||
|
@ -5,6 +15,7 @@ type AppAnalyse struct {
|
|||
Type string `json:"type"`
|
||||
UUId string `json:"uuid"`
|
||||
Language string `json:"language"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type ConnectionStatus struct {
|
||||
|
|
|
@ -104,6 +104,7 @@ func (p *PathArray) Scan(input interface{}) error {
|
|||
//}
|
||||
|
||||
type CustomizationPostData struct {
|
||||
CustomId string `json:"custom_id"`
|
||||
Origin string `json:"origin"`
|
||||
NetworkModel string `json:"network_model"`
|
||||
Index string `json:"index"`
|
||||
|
|
1
model/receive/app.go
Normal file
|
@ -0,0 +1 @@
|
|||
package receive
|
|
@ -18,6 +18,7 @@ type UserModel struct {
|
|||
Initialized bool
|
||||
Avatar string
|
||||
NickName string
|
||||
Public string
|
||||
}
|
||||
|
||||
//服务配置
|
||||
|
|
|
@ -4,7 +4,7 @@ import "time"
|
|||
|
||||
type Version struct {
|
||||
Id uint `gorm:"column:id;primary_key" json:"id"`
|
||||
ChangLog string `json:"chang_log"`
|
||||
ChangeLog string `json:"change_log"`
|
||||
Version string `json:"version"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package model
|
||||
|
||||
type ZeroTierUpData struct {
|
||||
Config ZeroTierConfig `json:"config"`
|
||||
}
|
||||
|
||||
type ZeroTierConfig struct {
|
||||
Private bool `json:"private"`
|
||||
}
|
|
@ -10,4 +10,5 @@ type Path struct {
|
|||
Size int64 `json:"size"` //File Size
|
||||
Type string `json:"type,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Write bool `json:"write"`
|
||||
}
|
||||
|
|
|
@ -22,8 +22,7 @@ var UserInfo = &model.UserModel{}
|
|||
//用户相关
|
||||
var AppInfo = &model.APPModel{}
|
||||
|
||||
//redis相关配置
|
||||
var RedisInfo = &model.RedisModel{}
|
||||
//var RedisInfo = &model.RedisModel{}
|
||||
|
||||
//server相关
|
||||
var ServerInfo = &model.ServerModel{}
|
||||
|
@ -53,7 +52,7 @@ func InitSetup(config string) {
|
|||
|
||||
mapTo("user", UserInfo)
|
||||
mapTo("app", AppInfo)
|
||||
mapTo("redis", RedisInfo)
|
||||
//mapTo("redis", RedisInfo)
|
||||
mapTo("server", ServerInfo)
|
||||
mapTo("system", SystemConfigInfo)
|
||||
mapTo("file", FileSettingInfo)
|
||||
|
|
|
@ -12,15 +12,15 @@ import (
|
|||
|
||||
var gdb *gorm.DB
|
||||
|
||||
func GetDb(projectPath string) *gorm.DB {
|
||||
func GetDb(dbPath string) *gorm.DB {
|
||||
if gdb != nil {
|
||||
return gdb
|
||||
}
|
||||
// 参考 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)
|
||||
//db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
|
||||
file.IsNotExistMkDir(projectPath + "/db/")
|
||||
db, err := gorm.Open(sqlite.Open(projectPath+"/db/casaOS.db"), &gorm.Config{})
|
||||
file.IsNotExistMkDir(dbPath)
|
||||
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
|
||||
c, _ := db.DB()
|
||||
c.SetMaxIdleConns(10)
|
||||
c.SetMaxOpenConns(100)
|
||||
|
@ -31,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
|
|||
return nil
|
||||
}
|
||||
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 {
|
||||
fmt.Println("检查和创建数据库出错", err)
|
||||
}
|
||||
|
|
|
@ -283,7 +283,6 @@ func CopyDir(src string, dst string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//文件写入临时目录
|
||||
func WriteToPath(data []byte, path, name string) error {
|
||||
fullPath := path
|
||||
if strings.HasSuffix(path, "/") {
|
||||
|
|
84
pkg/utils/file/image.go
Normal 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
|
||||
}
|
|
@ -2,7 +2,6 @@ package httper
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -23,6 +22,42 @@ func Get(url string, head map[string]string) (response string) {
|
|||
for k, v := range head {
|
||||
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 {
|
||||
return ""
|
||||
}
|
||||
|
@ -78,88 +113,6 @@ func Post(url string, data []byte, contentType string, head map[string]string) (
|
|||
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请求
|
||||
//url:请求地址,data:POST请求提交的数据,contentType:请求体格式,如:application/json
|
||||
//content:请求放回的内容
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package ip_helper
|
||||
|
||||
import (
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
)
|
||||
|
||||
func IsIPv4(address string) bool {
|
||||
|
@ -39,3 +40,35 @@ func GetLoclIp() string {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package ip_helper
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -20,3 +21,7 @@ func TestGetExternalIPV6(t *testing.T) {
|
|||
func TestGetLoclIp(t *testing.T) {
|
||||
fmt.Println(GetLoclIp())
|
||||
}
|
||||
func TestHasLocalIP(t *testing.T) {
|
||||
fmt.Println("dddd")
|
||||
fmt.Println(HasLocalIP(net.ParseIP("192.168.2.10")))
|
||||
}
|
||||
|
|
30
pkg/utils/network_detection.go
Normal 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
|
||||
}
|
||||
|
||||
}
|
29
pkg/utils/network_detection_test.go
Normal 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)
|
||||
}
|
|
@ -13,10 +13,11 @@ const (
|
|||
PWD_INVALID_OLD = 10003
|
||||
ACCOUNT_LOCK = 10004
|
||||
//system
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
DIR_ALREADY_EXISTS = 20001
|
||||
FILE_ALREADY_EXISTS = 20002
|
||||
FILE_OR_DIR_EXISTS = 20003
|
||||
PORT_IS_OCCUPIED = 20004
|
||||
COMMAND_ERROR_INVALID_OPERATION = 20005
|
||||
|
||||
//zerotier
|
||||
GET_TOKEN_ERROR = 30001
|
||||
|
@ -29,9 +30,10 @@ const (
|
|||
FORMAT_ERROR = 40005
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR = 50001
|
||||
PULL_IMAGE_ERROR = 50002
|
||||
DEVICE_NOT_EXIST = 50003
|
||||
UNINSTALL_APP_ERROR = 50001
|
||||
PULL_IMAGE_ERROR = 50002
|
||||
DEVICE_NOT_EXIST = 50003
|
||||
ERROR_APP_NAME_EXIST = 50004
|
||||
|
||||
//file
|
||||
FILE_DOES_NOT_EXIST = 60001
|
||||
|
@ -73,9 +75,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",
|
||||
|
||||
//app
|
||||
UNINSTALL_APP_ERROR: "Error uninstalling app",
|
||||
PULL_IMAGE_ERROR: "Error pulling image",
|
||||
DEVICE_NOT_EXIST: "Device does not exist",
|
||||
UNINSTALL_APP_ERROR: "Error uninstalling app",
|
||||
PULL_IMAGE_ERROR: "Error pulling image",
|
||||
DEVICE_NOT_EXIST: "Device does not exist",
|
||||
ERROR_APP_NAME_EXIST: "App name already exists",
|
||||
|
||||
//disk
|
||||
NAME_NOT_AVAILABLE: "Name not available",
|
||||
|
@ -93,12 +96,13 @@ var MsgFlags = map[int]string{
|
|||
FILE_DELETE_ERROR: "Delete error",
|
||||
SHORTCUTS_URL_ERROR: "URL error",
|
||||
|
||||
PERSON_REMOTE_ERROR: "Remote connection error",
|
||||
PERSON_DOWN_NOT_EXIST: "Download record does not exist",
|
||||
PERSON_EXIST_DOWNLOAD: "The same download task exists",
|
||||
PERSON_EXIST_FRIEND: "Friend already exist",
|
||||
PERSON_NOT_EXIST_USER: "User does not exist",
|
||||
PERSON_MYSELF: "You can not add yourself",
|
||||
PERSON_REMOTE_ERROR: "Remote connection error",
|
||||
PERSON_DOWN_NOT_EXIST: "Download record does not exist",
|
||||
PERSON_EXIST_DOWNLOAD: "The same download task exists",
|
||||
PERSON_EXIST_FRIEND: "Friend already exist",
|
||||
PERSON_NOT_EXIST_USER: "User does not exist",
|
||||
PERSON_MYSELF: "You can not add yourself",
|
||||
COMMAND_ERROR_INVALID_OPERATION: "invalid operation",
|
||||
}
|
||||
|
||||
//获取错误信息
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -37,6 +37,31 @@ func IsNeedUpdate() (bool, model.Version) {
|
|||
return false, version
|
||||
}
|
||||
|
||||
func IsClientNeedUpdate() (bool, model.Version) {
|
||||
var version model.Version
|
||||
v := httper.OasisGet(config.ServerInfo.ServerApi + "/v1/sys/client/version")
|
||||
data := gjson.Get(v, "data")
|
||||
json2.Unmarshal([]byte(data.String()), &version)
|
||||
|
||||
v1 := strings.Split(version.Version, ".")
|
||||
v2 := strings.Split(types.CURRENTVERSION, ".")
|
||||
|
||||
for len(v1) < len(v2) {
|
||||
v1 = append(v1, "0")
|
||||
}
|
||||
for len(v2) < len(v1) {
|
||||
v2 = append(v2, "0")
|
||||
}
|
||||
for i := 0; i < len(v1); i++ {
|
||||
a, _ := strconv.Atoi(v1[i])
|
||||
b, _ := strconv.Atoi(v2[i])
|
||||
if a > b {
|
||||
return true, version
|
||||
}
|
||||
}
|
||||
return false, version
|
||||
}
|
||||
|
||||
//a版本大于b版本
|
||||
func VersionCompared(a string, b string) bool {
|
||||
v1 := strings.Split(a, ".")
|
||||
|
|
125
route/init.go
|
@ -1,17 +1,16 @@
|
|||
package route
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/model/system_app"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/env_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
|
@ -27,6 +26,9 @@ func InitFunction() {
|
|||
CheckSerialDiskMount()
|
||||
|
||||
CheckToken2_11()
|
||||
ImportApplications()
|
||||
ChangeAPIUrl()
|
||||
InitSystemApplication()
|
||||
|
||||
}
|
||||
|
||||
|
@ -102,8 +104,9 @@ func installSyncthing(appId string) {
|
|||
m.Ports = appInfo.Ports
|
||||
m.Restart = "always"
|
||||
m.Volumes = appInfo.Volumes
|
||||
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
|
||||
m.Label = id
|
||||
m.CustomId = id
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
if err != nil {
|
||||
fmt.Println("container create error", err)
|
||||
// create container error
|
||||
|
@ -111,83 +114,46 @@ func installSyncthing(appId string) {
|
|||
}
|
||||
|
||||
//step:start container
|
||||
err = service.MyService.Docker().DockerContainerStart(id)
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
if err != nil {
|
||||
//start container error
|
||||
return
|
||||
}
|
||||
|
||||
portsStr, _ := json.Marshal(appInfo.Ports)
|
||||
envsStr, _ := json.Marshal(appInfo.Envs)
|
||||
volumesStr, _ := json.Marshal(appInfo.Volumes)
|
||||
devicesStr, _ := json.Marshal(appInfo.Devices)
|
||||
//step: 保存数据到数据库
|
||||
md := model2.AppListDBModel{
|
||||
CustomId: id,
|
||||
Title: appInfo.Title,
|
||||
//ScreenshotLink: appInfo.ScreenshotLink,
|
||||
Slogan: appInfo.Tagline,
|
||||
Description: appInfo.Description,
|
||||
//Tags: appInfo.Tags,
|
||||
Icon: appInfo.Icon,
|
||||
Version: dockerImageVersion,
|
||||
ContainerId: containerId,
|
||||
Image: dockerImage,
|
||||
Index: appInfo.Index,
|
||||
PortMap: appInfo.PortMap,
|
||||
Label: appInfo.Title,
|
||||
EnableUPNP: false,
|
||||
Ports: string(portsStr),
|
||||
Envs: string(envsStr),
|
||||
Volumes: string(volumesStr),
|
||||
Position: true,
|
||||
NetModel: appInfo.NetworkModel,
|
||||
Restart: m.Restart,
|
||||
CpuShares: 50,
|
||||
Memory: int64(appInfo.MaxMemory),
|
||||
Devices: string(devicesStr),
|
||||
Origin: m.Origin,
|
||||
CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
|
||||
}
|
||||
service.MyService.App().SaveContainer(md)
|
||||
|
||||
checkSystemApp()
|
||||
}
|
||||
|
||||
// check if the system application is installed
|
||||
func checkSystemApp() {
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range *list {
|
||||
if v.Image == "linuxserver/syncthing" {
|
||||
for _, v := range list {
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(v.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(info.Config.Image, "linuxserver/syncthing") {
|
||||
if v.State != "running" {
|
||||
//step:start container
|
||||
service.MyService.Docker().DockerContainerStart(v.CustomId)
|
||||
service.MyService.Docker().DockerContainerStart(v.ID)
|
||||
}
|
||||
syncIsExistence = true
|
||||
if config.SystemConfigInfo.SyncPort != v.Port {
|
||||
config.SystemConfigInfo.SyncPort = v.Port
|
||||
if config.SystemConfigInfo.SyncPort != v.Labels["web"] {
|
||||
config.SystemConfigInfo.SyncPort = v.Labels["web"]
|
||||
}
|
||||
var paths []model.PathMap
|
||||
json.Unmarshal([]byte(v.Volumes), &paths)
|
||||
|
||||
path := ""
|
||||
for _, i := range paths {
|
||||
if i.ContainerPath == "/config" {
|
||||
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml"
|
||||
for i := 0; i < 10; i++ {
|
||||
if file.CheckNotExist(path) {
|
||||
time.Sleep(1 * time.Second)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, i := range info.HostConfig.Mounts {
|
||||
if i.Target == "/config" {
|
||||
path = i.Source
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
content := file.ReadFullFile(path)
|
||||
content := file.ReadFullFile(path + "config.xml")
|
||||
syncConfig := &system_app.SyncConfig{}
|
||||
xml.Unmarshal(content, &syncConfig)
|
||||
config.SystemConfigInfo.SyncKey = syncConfig.Key
|
||||
break
|
||||
}
|
||||
}
|
||||
if !syncIsExistence {
|
||||
|
@ -261,7 +227,7 @@ func CheckToken2_11() {
|
|||
downloadPath = "C:\\CasaOS\\DATA\\Downloads"
|
||||
}
|
||||
if sysType == "darwin" {
|
||||
downloadPath = "~/CasaOS/DATA/Downloads"
|
||||
downloadPath = "./CasaOS/DATA/Downloads"
|
||||
}
|
||||
config.Cfg.Section("file").Key("DownloadDir").SetValue(downloadPath)
|
||||
config.FileSettingInfo.DownloadDir = downloadPath
|
||||
|
@ -280,7 +246,10 @@ func CheckToken2_11() {
|
|||
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 = append(str, "ddd")
|
||||
|
@ -291,3 +260,39 @@ func CheckToken2_11() {
|
|||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ func InitRouter() *gin.Engine {
|
|||
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
|
||||
//get user info
|
||||
r.GET("/v1/user/info", v1.GetUserInfo)
|
||||
|
||||
//get user info
|
||||
r.GET("/v1/person/shareid", v1.GetPersonShareId)
|
||||
v1Group := r.Group("/v1")
|
||||
|
||||
v1Group.Use(jwt2.JWT(swagHandler))
|
||||
|
@ -102,7 +103,7 @@ func InitRouter() *gin.Engine {
|
|||
v1AppGroup.Use()
|
||||
{
|
||||
//获取我的已安装的列表
|
||||
v1AppGroup.GET("/mylist", v1.MyAppList)
|
||||
v1AppGroup.GET("/my/list", v1.MyAppList)
|
||||
//
|
||||
v1AppGroup.GET("/usage", v1.AppUsageList)
|
||||
//app详情
|
||||
|
@ -117,8 +118,8 @@ func InitRouter() *gin.Engine {
|
|||
v1AppGroup.GET("/category", v1.CategoryList)
|
||||
//容器相关
|
||||
v1AppGroup.GET("/terminal/:id", v1.DockerTerminal)
|
||||
//准备安装
|
||||
//v1AppGroup.GET("/ready/:id", v1.ReadyInstall)
|
||||
v1AppGroup.GET("/order", v1.GetAppOrder)
|
||||
v1AppGroup.POST("/order", v1.PostAppOrder)
|
||||
//app容器详情
|
||||
v1AppGroup.GET("/info/:id", v1.ContainerInfo)
|
||||
//app容器日志
|
||||
|
@ -139,17 +140,17 @@ func InitRouter() *gin.Engine {
|
|||
v1AppGroup.GET("/update/:id/info", v1.ContainerUpdateInfo)
|
||||
v1AppGroup.GET("/rely/:id/info", v1.ContainerRelyInfo)
|
||||
v1AppGroup.GET("/install/config", v1.GetDockerInstallConfig)
|
||||
//v1AppGroup.POST("/custom/install", v1.CustomInstallApp)
|
||||
v1AppGroup.PUT("/update/:id", v1.PutAppUpdate)
|
||||
v1AppGroup.POST("/share", v1.ShareAppFile)
|
||||
}
|
||||
|
||||
v1SysGroup := v1Group.Group("/sys")
|
||||
v1SysGroup.Use()
|
||||
{
|
||||
//获取检查版本是否需要升级
|
||||
v1SysGroup.GET("/check", v1.CheckVersion)
|
||||
v1SysGroup.GET("/hardware/info", v1.GetSystemHardwareInfo)
|
||||
v1SysGroup.GET("/client/version", v1.GetClientVersion)
|
||||
v1SysGroup.POST("/update", v1.SystemUpdate)
|
||||
v1SysGroup.GET("/sys", v1.Sys)
|
||||
v1SysGroup.GET("/wsssh", v1.WsSsh)
|
||||
v1SysGroup.GET("/config", v1.GetSystemConfig)
|
||||
v1SysGroup.GET("/error/logs", v1.GetCasaOSErrorLogs)
|
||||
|
@ -161,13 +162,12 @@ func InitRouter() *gin.Engine {
|
|||
v1SysGroup.POST("/kill", v1.PostKillCasaOS)
|
||||
v1SysGroup.GET("/info", v1.Info)
|
||||
v1SysGroup.PUT("/usb/off", v1.PutSystemOffUSBAutoMount)
|
||||
v1SysGroup.GET("/usb/on", v1.PutSystemOnUSBAutoMount)
|
||||
v1SysGroup.PUT("/usb/on", v1.PutSystemOnUSBAutoMount)
|
||||
v1SysGroup.GET("/usb", v1.GetSystemUSBAutoMount)
|
||||
}
|
||||
v1FileGroup := v1Group.Group("/file")
|
||||
v1FileGroup.Use()
|
||||
{
|
||||
//修改文件名称/目录名称
|
||||
v1FileGroup.PUT("/rename", v1.RenamePath)
|
||||
v1FileGroup.GET("/read", v1.GetFilerContent)
|
||||
v1FileGroup.POST("/upload", v1.PostFileUpload)
|
||||
|
@ -182,6 +182,7 @@ func InitRouter() *gin.Engine {
|
|||
v1FileGroup.POST("/operate", v1.PostOperateFileOrDir)
|
||||
v1FileGroup.DELETE("/delete", v1.DeleteFile)
|
||||
v1FileGroup.PUT("/update", v1.PutFileContent)
|
||||
v1FileGroup.GET("/image", v1.GetFileImage)
|
||||
|
||||
//v1FileGroup.GET("/download", v1.UserFileDownloadCommonService)
|
||||
}
|
||||
|
@ -233,29 +234,18 @@ func InitRouter() *gin.Engine {
|
|||
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.Use()
|
||||
{
|
||||
v1PersonGroup.GET("/test", v1.PersonTest)
|
||||
v1PersonGroup.GET("/detection", v1.GetPersonDetection)
|
||||
v1PersonGroup.GET("/users", v1.GetPersonFriend)
|
||||
v1PersonGroup.POST("/user/:shareids", v1.PostAddPersonFriend)
|
||||
v1PersonGroup.DELETE("/user/:shareid", v1.DeletePersonFriend)
|
||||
|
@ -267,11 +257,15 @@ func InitRouter() *gin.Engine {
|
|||
v1PersonGroup.DELETE("/file/:uuid", v1.DeletePersonDownloadFile)
|
||||
|
||||
v1PersonGroup.POST("/share", v1.PostPersonShare)
|
||||
v1PersonGroup.POST("/file/:shareid", v1.PostPersonFile)
|
||||
v1PersonGroup.GET("/share", v1.GetPersonShare)
|
||||
v1PersonGroup.POST("/down/dir", v1.PostPersonDownDir)
|
||||
v1PersonGroup.GET("/down/dir", v1.GetPersonDownDir)
|
||||
v1PersonGroup.PUT("/block/:shareid", v1.PutPersonBlock)
|
||||
v1PersonGroup.GET("/public", v1.GetPersonPublic)
|
||||
v1PersonGroup.PUT("/friend/:shareid", v1.PutPersonAgreeFriend)
|
||||
v1PersonGroup.PUT("/write/:shareid", v1.PutPersonWrite)
|
||||
v1PersonGroup.GET("/image/thumbnail/:shareid", v1.GetPersonImageThumbnail)
|
||||
|
||||
}
|
||||
v1AnalyseGroup := v1Group.Group("/analyse")
|
||||
|
|
|
@ -106,13 +106,18 @@ func PortCheck(c *gin.Context) {
|
|||
// @Param size query int false "size"
|
||||
// @Param position query bool false "是否是首页应用"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /app/mylist [get]
|
||||
// @Router /app/my/list [get]
|
||||
func MyAppList(c *gin.Context) {
|
||||
index, _ := strconv.Atoi(c.DefaultQuery("index", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "0"))
|
||||
position, _ := strconv.ParseBool(c.DefaultQuery("position", "true"))
|
||||
list := 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})
|
||||
list, unTranslation := service.MyService.App().GetMyList(index, size, position)
|
||||
|
||||
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
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
json2 "encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -16,6 +16,7 @@ import (
|
|||
upnp2 "github.com/IceWhaleTech/CasaOS/pkg/upnp"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
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"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/random"
|
||||
|
@ -27,7 +28,6 @@ import (
|
|||
"github.com/gorilla/websocket"
|
||||
"github.com/jinzhu/copier"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"github.com/tidwall/gjson"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
|
@ -154,6 +154,27 @@ func InstallApp(c *gin.Context) {
|
|||
const CUSTOM = "custom"
|
||||
var dockerImage string
|
||||
var dockerImageVersion string
|
||||
|
||||
//check app name is exist
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//检查端口
|
||||
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)})
|
||||
|
@ -248,12 +269,12 @@ func InstallApp(c *gin.Context) {
|
|||
//
|
||||
//}
|
||||
id := uuid.NewV4().String()
|
||||
|
||||
m.CustomId = id
|
||||
var relyMap = make(map[string]string)
|
||||
go func() {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.State = 0
|
||||
installLog.CustomId = id
|
||||
installLog.CustomId = m.Label
|
||||
installLog.Message = "installing rely"
|
||||
installLog.Class = types.NOTIFY_APP
|
||||
installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
|
||||
|
@ -281,7 +302,7 @@ func InstallApp(c *gin.Context) {
|
|||
rely.Type = types.RELY_TYPE_MYSQL
|
||||
rely.ContainerId = mysqlContainerId
|
||||
rely.CustomId = mid
|
||||
rely.ContainerCustomId = id
|
||||
rely.ContainerCustomId = m.Label
|
||||
var mysqlConfig model2.MysqlConfigs
|
||||
|
||||
//结构体转换
|
||||
|
@ -333,7 +354,7 @@ func InstallApp(c *gin.Context) {
|
|||
// service.MyService.Notify().UpdateLog(installLog)
|
||||
// return
|
||||
// }
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, m, appInfo.NetworkModel)
|
||||
installLog.Name = appInfo.Title
|
||||
installLog.Icon = appInfo.Icon
|
||||
if err != nil {
|
||||
|
@ -352,7 +373,7 @@ func InstallApp(c *gin.Context) {
|
|||
// echo -e "hellow\nworld" >>
|
||||
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(id)
|
||||
err = service.MyService.Docker().DockerContainerStart(m.Label)
|
||||
if err != nil {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
|
||||
installLog.State = 0
|
||||
|
@ -418,7 +439,7 @@ func InstallApp(c *gin.Context) {
|
|||
}
|
||||
|
||||
//step: 启动成功 检查容器状态确认启动成功
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(id)
|
||||
container, err := service.MyService.Docker().DockerContainerInfo(m.Label)
|
||||
if err != nil && container.ContainerJSONBase.State.Running {
|
||||
//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
|
||||
installLog.State = 0
|
||||
|
@ -449,7 +470,7 @@ func InstallApp(c *gin.Context) {
|
|||
capAdd, _ := json.Marshal(m.CapAdd)
|
||||
//step: 保存数据到数据库
|
||||
md := model2.AppListDBModel{
|
||||
CustomId: id,
|
||||
CustomId: "",
|
||||
Title: appInfo.Title,
|
||||
//ScreenshotLink: appInfo.ScreenshotLink,
|
||||
Slogan: appInfo.Tagline,
|
||||
|
@ -485,12 +506,13 @@ func InstallApp(c *gin.Context) {
|
|||
//if appInfo.NetworkModel == "host" {
|
||||
// m.PortMap = m.Port
|
||||
//}
|
||||
service.MyService.App().SaveContainer(md)
|
||||
fmt.Println(md)
|
||||
//service.MyService.App().SaveContainer(md)
|
||||
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,10 +713,16 @@ func UnInstallApp(c *gin.Context) {
|
|||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
|
||||
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:停止容器
|
||||
err := service.MyService.Docker().DockerContainerStop(appId)
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.UNINSTALL_APP_ERROR, Message: oasis_err2.GetMsg(oasis_err2.UNINSTALL_APP_ERROR), Data: err.Error()})
|
||||
return
|
||||
|
@ -709,17 +737,16 @@ func UnInstallApp(c *gin.Context) {
|
|||
|
||||
//存在镜像正在使用的情况
|
||||
// step:删除镜像
|
||||
service.MyService.Docker().DockerImageRemove(info.Image + ":" + info.Version)
|
||||
service.MyService.Docker().DockerImageRemove(info.Image)
|
||||
|
||||
//step: 删除本地数据
|
||||
service.MyService.App().RemoveContainerById(appId)
|
||||
if info.Origin != "custom" {
|
||||
|
||||
//service.MyService.App().RemoveContainerById(appId)
|
||||
if info.Config.Labels["origin"] != "custom" {
|
||||
fmt.Println(info.HostConfig.Mounts)
|
||||
//step: 删除文件夹
|
||||
vol := gjson.Get(info.Volumes, "#.host")
|
||||
for _, v := range vol.Array() {
|
||||
if strings.Contains(v.String(), appId) {
|
||||
service.MyService.App().DelAppConfigDir(v.String())
|
||||
for _, v := range info.HostConfig.Mounts {
|
||||
if strings.Contains(v.Source, info.Name) {
|
||||
service.MyService.App().DelAppConfigDir(v.Source)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,7 +820,7 @@ func ChangAppState(c *gin.Context) {
|
|||
} else if state == "start" {
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
} else if state == "restart" {
|
||||
err = service.MyService.Docker().DockerContainerStop(appId)
|
||||
service.MyService.Docker().DockerContainerStop(appId)
|
||||
err = service.MyService.Docker().DockerContainerStart(appId)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -889,19 +916,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)})
|
||||
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
|
||||
containerId = appInfo.ContainerId
|
||||
// //check app name is exist
|
||||
// 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)
|
||||
|
||||
portMap, _ := strconv.Atoi(m.PortMap)
|
||||
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})
|
||||
return
|
||||
}
|
||||
|
@ -911,77 +942,54 @@ func UpdateSetting(c *gin.Context) {
|
|||
if u.Protocol == "udp" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
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})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "tcp" {
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
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})
|
||||
return
|
||||
}
|
||||
} else if u.Protocol == "both" {
|
||||
t, _ := strconv.Atoi(u.CommendPort)
|
||||
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})
|
||||
return
|
||||
}
|
||||
|
||||
te, _ := strconv.Atoi(u.CommendPort)
|
||||
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})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
service.MyService.Docker().DockerContainerUpdateName(id, id)
|
||||
//service.MyService.Docker().DockerContainerRemove(id, true)
|
||||
|
||||
//如果容器端口均未修改,这不进行处理
|
||||
portsStr, _ := json2.Marshal(m.Ports)
|
||||
|
||||
envsStr, _ := json2.Marshal(m.Envs)
|
||||
volumesStr, _ := json2.Marshal(m.Volumes)
|
||||
devicesStr, _ := json2.Marshal(m.Devices)
|
||||
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)
|
||||
containerId, err := service.MyService.Docker().DockerContainerCreate(m.Image, m, m.NetworkModel)
|
||||
if err != nil {
|
||||
service.MyService.Docker().DockerContainerUpdateName(m.Label, id)
|
||||
service.MyService.Docker().DockerContainerStart(id)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: oasis_err2.GetMsg(oasis_err2.ERROR)})
|
||||
return
|
||||
}
|
||||
// echo -e "hellow\nworld" >>
|
||||
|
||||
//step:启动容器
|
||||
err = service.MyService.Docker().DockerContainerStart(containerId)
|
||||
|
||||
err := service.MyService.Docker().DockerContainerStart(id)
|
||||
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)
|
||||
//更新upnp
|
||||
if m.Origin != CUSTOM {
|
||||
//if appInfo.EnableUPNP != appInfo.EnableUPNP {
|
||||
|
@ -1047,31 +1055,96 @@ func UpdateSetting(c *gin.Context) {
|
|||
//}
|
||||
}
|
||||
|
||||
appInfo.ContainerId = containerId
|
||||
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)
|
||||
//service.MyService.App().UpdateApp(appInfo)
|
||||
|
||||
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, model2.AppNotify{})
|
||||
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 获取容器详情
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -1160,7 +1233,7 @@ func ContainerRelyInfo(c *gin.Context) {
|
|||
// @Router /app/update/{id}/info [get]
|
||||
func ContainerUpdateInfo(c *gin.Context) {
|
||||
appId := c.Param("id")
|
||||
appInfo := service.MyService.App().GetAppDBInfo(appId)
|
||||
//appInfo := service.MyService.App().GetAppDBInfo(appId)
|
||||
info, err := service.MyService.Docker().DockerContainerInfo(appId)
|
||||
if err != nil {
|
||||
//todo 需要自定义错误
|
||||
|
@ -1168,50 +1241,81 @@ func ContainerUpdateInfo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
var port model.PortArray
|
||||
json2.Unmarshal([]byte(appInfo.Ports), &port)
|
||||
// json2.Unmarshal([]byte(appInfo.Ports), &port)
|
||||
|
||||
var envs model.EnvArray
|
||||
json2.Unmarshal([]byte(appInfo.Envs), &envs)
|
||||
for k, v := range info.HostConfig.PortBindings {
|
||||
temp := model.PortMap{
|
||||
CommendPort: v[0].HostPort,
|
||||
ContainerPort: k.Port(),
|
||||
|
||||
var vol model.PathArray
|
||||
json2.Unmarshal([]byte(appInfo.Volumes), &vol)
|
||||
|
||||
for i := 0; i < len(vol); i++ {
|
||||
vol[i].Path = strings.ReplaceAll(vol[i].Path, "$AppID", appId)
|
||||
Protocol: k.Proto(),
|
||||
}
|
||||
port = append(port, temp)
|
||||
}
|
||||
|
||||
var dir model.PathArray
|
||||
json2.Unmarshal([]byte(appInfo.Devices), &dir)
|
||||
var envs model.EnvArray
|
||||
// json2.Unmarshal([]byte(appInfo.Envs), &envs)
|
||||
|
||||
for _, v := range info.Config.Env {
|
||||
|
||||
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.HostConfig.Mounts); i++ {
|
||||
temp := model.PathMap{
|
||||
Path: strings.ReplaceAll(info.HostConfig.Mounts[i].Source, "$AppID", info.Name),
|
||||
ContainerPath: info.HostConfig.Mounts[i].Target,
|
||||
}
|
||||
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)
|
||||
//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.Index = appInfo.Index
|
||||
m.Icon = appInfo.Icon
|
||||
m.Icon = info.Config.Labels["icon"]
|
||||
m.Ports = port
|
||||
m.Image = appInfo.Image + ":" + appInfo.Version
|
||||
m.Origin = appInfo.Origin
|
||||
m.NetworkModel = appInfo.NetModel
|
||||
m.Description = appInfo.Description
|
||||
m.Label = appInfo.Label
|
||||
m.PortMap = appInfo.PortMap
|
||||
m.Devices = dir //appInfo.Devices
|
||||
m.Image = info.Config.Image
|
||||
m.Origin = info.Config.Labels["origin"]
|
||||
if len(m.Origin) == 0 {
|
||||
m.Origin = "local"
|
||||
}
|
||||
m.NetworkModel = string(info.HostConfig.NetworkMode)
|
||||
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.Memory = info.HostConfig.Memory >> 20
|
||||
m.CpuShares = info.HostConfig.CPUShares
|
||||
m.Volumes = vol //appInfo.Volumes
|
||||
m.Restart = info.HostConfig.RestartPolicy.Name
|
||||
m.EnableUPNP = appInfo.EnableUPNP
|
||||
m.Position = appInfo.Position
|
||||
|
||||
m.CapAdd = capAdd
|
||||
m.Cmd = cmd
|
||||
m.HostName = appInfo.HostName
|
||||
m.Privileged = appInfo.Privileged
|
||||
m.EnableUPNP = false
|
||||
m.Index = info.Config.Labels["index"]
|
||||
m.Position = false
|
||||
m.CustomId = info.Config.Labels["custom_id"]
|
||||
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
|
||||
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: m})
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
oasis_err2 "github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
|
@ -224,10 +225,10 @@ func DirPath(c *gin.Context) {
|
|||
path := c.DefaultQuery("path", "")
|
||||
info := service.MyService.ZiMa().GetDirPath(path)
|
||||
if path == "/DATA/AppData" {
|
||||
list := service.MyService.App().GetAllDBApps()
|
||||
list := service.MyService.Docker().DockerContainerList()
|
||||
apps := make(map[string]string, len(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++ {
|
||||
if v, ok := apps[info[i].Name]; ok {
|
||||
|
@ -342,7 +343,7 @@ func GetFileUpload(c *gin.Context) {
|
|||
path := c.Query("path")
|
||||
dirPath := ""
|
||||
hash := file.GetHashByContent([]byte(fileName))
|
||||
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
tempDir += dirPath
|
||||
|
@ -381,7 +382,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)})
|
||||
return
|
||||
}
|
||||
tempDir := "/casaOS/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
tempDir := config.AppInfo.RootPath + "/temp/" + hash + strconv.Itoa(totalChunks) + "/"
|
||||
|
||||
if fileName != relative {
|
||||
dirPath = strings.TrimSuffix(relative, fileName)
|
||||
|
@ -504,7 +505,7 @@ func PutFileContent(c *gin.Context) {
|
|||
path := c.PostForm("path")
|
||||
content := c.PostForm("content")
|
||||
if !file.Exists(path) {
|
||||
c.JSON(oasis_err2.FILE_ALREADY_EXISTS, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.FILE_ALREADY_EXISTS, Message: oasis_err2.GetMsg(oasis_err2.FILE_ALREADY_EXISTS)})
|
||||
return
|
||||
}
|
||||
//err := os.Remove(path)
|
||||
|
@ -522,3 +523,42 @@ func PutFileContent(c *gin.Context) {
|
|||
}
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
natType "github.com/Curtis-Milo/nat-type-identifier-go"
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"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"
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
|
@ -21,33 +27,6 @@ import (
|
|||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func PersonTest(c *gin.Context) {
|
||||
token := c.Query("token")
|
||||
_, err := uuid.FromString(token)
|
||||
fmt.Println(err)
|
||||
|
||||
//service.MyService.Person().GetPersionInfo("fb2333a1-72b2-4cb4-9e31-61ccaffa55b9")
|
||||
|
||||
msg := model.MessageModel{}
|
||||
msg.Type = types.PERSONHELLO
|
||||
msg.Data = ""
|
||||
msg.From = config.ServerInfo.Token
|
||||
msg.To = token
|
||||
msg.UUId = uuid.NewV4().String()
|
||||
|
||||
dd, err := service.Dial(msg, true)
|
||||
if err == nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(dd)
|
||||
user := service.MyService.Casa().GetUserInfoByShareId(token)
|
||||
if reflect.DeepEqual(user, model.UserInfo{}) {
|
||||
fmt.Println("空数据")
|
||||
}
|
||||
fmt.Println(user)
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
|
||||
}
|
||||
|
||||
// @Summary Retry the file that failed to download
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -135,7 +114,7 @@ func GetPersonFile(c *gin.Context) {
|
|||
task.Size = 0
|
||||
task.State = types.DOWNLOADAWAIT
|
||||
task.Created = time.Now().Unix()
|
||||
task.Type = 0
|
||||
task.Type = types.PERSONFILEDOWNLOAD
|
||||
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)})
|
||||
|
@ -197,7 +176,7 @@ func DeletePersonDownloadFile(c *gin.Context) {
|
|||
// @Router /person/list [get]
|
||||
func GetPersonDownloadList(c *gin.Context) {
|
||||
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'
|
||||
for i := 0; i < len(list); i++ {
|
||||
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)})
|
||||
}
|
||||
|
||||
// @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
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -247,11 +299,39 @@ func GetPersonFriend(c *gin.Context) {
|
|||
for i := 0; i < len(list); i++ {
|
||||
if v, ok := service.UDPAddressMap[list[i].Token]; ok && len(v) > 0 {
|
||||
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})
|
||||
}
|
||||
|
||||
// @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
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -296,10 +376,20 @@ func PostAddPersonFriend(c *gin.Context) {
|
|||
|
||||
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.Token = v
|
||||
friend.Avatar = user.Avatar
|
||||
friend.Block = false
|
||||
friend.State = types.FRIENDSTATEWAIT
|
||||
friend.NickName = user.NickName
|
||||
friend.Profile = user.Desc
|
||||
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})
|
||||
}
|
||||
|
||||
// @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
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -489,8 +590,214 @@ func DeletePersonFriend(c *gin.Context) {
|
|||
// @Tags person
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /person/public [delete]
|
||||
// @Router /person/public [get]
|
||||
func GetPersonPublic(c *gin.Context) {
|
||||
list := service.MyService.Casa().GetPersonPublic()
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
|
||||
}
|
||||
|
||||
// @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)})
|
||||
// }
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary 系统信息
|
||||
// @Summary check version
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
|
@ -50,6 +50,32 @@ func CheckVersion(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// @Summary check client version
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/client/version [get]
|
||||
func GetClientVersion(c *gin.Context) {
|
||||
need, version := version.IsClientNeedUpdate()
|
||||
if need {
|
||||
installLog := model2.AppNotify{}
|
||||
installLog.State = 0
|
||||
installLog.Message = "New version " + version.Version + " is ready, ready to upgrade"
|
||||
installLog.Type = types.NOTIFY_TYPE_NEED_CONFIRM
|
||||
installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
installLog.Name = "CasaOS System"
|
||||
service.MyService.Notify().AddLog(installLog)
|
||||
}
|
||||
data := make(map[string]interface{}, 1)
|
||||
data["is_need"] = need
|
||||
data["version"] = version
|
||||
data["current_version"] = types.CURRENTVERSION
|
||||
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
||||
}
|
||||
|
||||
// @Summary 系统信息
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
@ -115,7 +141,7 @@ func GetSystemConfigDebug(c *gin.Context) {
|
|||
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
|
||||
|
||||
list := service.MyService.App().GetSystemAppList()
|
||||
for _, v := range *list {
|
||||
for _, v := range list {
|
||||
systemAppStatus += v.Image + ",\n\t"
|
||||
}
|
||||
|
||||
|
@ -136,9 +162,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})
|
||||
}
|
||||
func Sys(c *gin.Context) {
|
||||
service.DockerPull()
|
||||
}
|
||||
|
||||
//widget配置
|
||||
func GetWidgetConfig(c *gin.Context) {
|
||||
|
@ -155,9 +178,7 @@ func GetWidgetConfig(c *gin.Context) {
|
|||
func PostSetWidgetConfig(c *gin.Context) {
|
||||
buf := make([]byte, 1024)
|
||||
n, _ := c.Request.Body.Read(buf)
|
||||
fmt.Println("错误", strconv.Itoa(n))
|
||||
service.MyService.System().UpSystemConfig("", string(buf[0:n]))
|
||||
fmt.Println("错误1", string(buf[0:n]))
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
|
@ -257,7 +278,7 @@ func PostKillCasaOS(c *gin.Context) {
|
|||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/usg/off [put]
|
||||
// @Router /sys/usb/off [put]
|
||||
func PutSystemOffUSBAutoMount(c *gin.Context) {
|
||||
service.MyService.System().UpdateUSBAutoMount("False")
|
||||
service.MyService.System().ExecUSBAutoMountShell("False")
|
||||
|
@ -280,6 +301,7 @@ func GetSystemUSBAutoMount(c *gin.Context) {
|
|||
if config.ServerInfo.USBAutoMount == "False" {
|
||||
state = "False"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
|
@ -288,6 +310,25 @@ func GetSystemUSBAutoMount(c *gin.Context) {
|
|||
})
|
||||
}
|
||||
|
||||
// @Summary get system hardware info
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
// @Tags sys
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Router /sys/hardware/info [get]
|
||||
func GetSystemHardwareInfo(c *gin.Context) {
|
||||
|
||||
data := make(map[string]string, 1)
|
||||
data["drive_model"] = service.MyService.ZiMa().GetDeviceTree()
|
||||
c.JSON(http.StatusOK,
|
||||
model.Result{
|
||||
Success: oasis_err.SUCCESS,
|
||||
Message: oasis_err.GetMsg(oasis_err.SUCCESS),
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Turn off usb auto-mount
|
||||
// @Produce application/json
|
||||
// @Accept application/json
|
||||
|
|
364
service/app.go
|
@ -3,9 +3,11 @@ package service
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -19,24 +21,32 @@ import (
|
|||
"github.com/docker/docker/api/types/filters"
|
||||
client2 "github.com/docker/docker/client"
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
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)
|
||||
GetUninstallInfo(id string) model2.AppListDBModel
|
||||
RemoveContainerById(id string)
|
||||
DeleteApp(id string)
|
||||
GetContainerInfo(name string) (types.Container, error)
|
||||
GetAppDBInfo(id string) model2.AppListDBModel
|
||||
UpdateApp(m model2.AppListDBModel)
|
||||
GetSimpleContainerInfo(name string) (types.Container, error)
|
||||
DelAppConfigDir(path string)
|
||||
GetSystemAppList() *[]model2.MyAppList
|
||||
GetSystemAppList() []types.Container
|
||||
GetHardwareUsageSteam()
|
||||
GetHardwareUsage() []model.DockerStatsModel
|
||||
GetAppStats(id string) string
|
||||
GetAllDBApps() []model2.AppListDBModel
|
||||
ImportApplications(casaApp bool)
|
||||
CheckNewImage()
|
||||
}
|
||||
|
||||
type appStruct struct {
|
||||
|
@ -44,73 +54,253 @@ type appStruct struct {
|
|||
log loger2.OLog
|
||||
}
|
||||
|
||||
func (a *appStruct) GetApplicationById(id string) (m model2.ApplicationModel) {
|
||||
a.db.Where("id = ?", id).First(&m)
|
||||
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 {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
return 0
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "casaos=casaos")
|
||||
//fts.Add("label", "casaos:casaos")
|
||||
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{Filters: fts, Limit: 200})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
systemApp := MyService.App().GetApplicationList()
|
||||
return len(containers) + len(systemApp)
|
||||
}
|
||||
|
||||
//获取我的应用列表
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) *[]model2.MyAppList {
|
||||
func (a *appStruct) GetMyList(index, size int, position bool) (*[]model2.MyAppList, *[]model2.MyAppList) {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv, client2.WithTimeout(time.Second*5))
|
||||
if err != nil {
|
||||
a.log.Error("初始化client失败", "app.getmylist", "line:36", err)
|
||||
}
|
||||
defer cli.Close()
|
||||
fts := filters.NewArgs()
|
||||
fts.Add("label", "origin")
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true, Filters: fts})
|
||||
// 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 {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
}
|
||||
//获取本地数据库应用
|
||||
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image").Find(&lm)
|
||||
unTranslation := []model2.MyAppList{}
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
lMap := make(map[string]interface{})
|
||||
for _, dbModel := range lm {
|
||||
if position {
|
||||
if dbModel.Position {
|
||||
lMap[dbModel.ContainerId] = dbModel
|
||||
}
|
||||
} else {
|
||||
lMap[dbModel.ContainerId] = dbModel
|
||||
}
|
||||
|
||||
systemApp := MyService.App().GetApplicationList()
|
||||
for _, v := range systemApp {
|
||||
list = append(list, model2.MyAppList{
|
||||
Name: v.Name,
|
||||
Icon: v.Icon,
|
||||
State: strconv.Itoa(v.State),
|
||||
Id: strconv.Itoa(v.Id),
|
||||
CustomId: strconv.Itoa(v.Id),
|
||||
Port: "",
|
||||
//Order: strconv.Itoa(v.Order),
|
||||
Index: "/",
|
||||
Image: "",
|
||||
Type: v.Type,
|
||||
NewVersion: false,
|
||||
})
|
||||
}
|
||||
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
|
||||
for _, m := range containers {
|
||||
if m.Labels["casaos"] == "casaos" {
|
||||
if m.Labels["origin"] == "system" {
|
||||
continue
|
||||
}
|
||||
|
||||
// info, err := cli.ContainerInspect(context.Background(), container.ID)
|
||||
// var tm string
|
||||
// if err != nil {
|
||||
// tm = time.Now().String()
|
||||
// } else {
|
||||
// tm = info.State.StartedAt
|
||||
//}
|
||||
_, newVersion := NewVersionApp[m.ID]
|
||||
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,
|
||||
Name: strings.ReplaceAll(m.Names[0], "/", ""),
|
||||
Icon: m.Labels["icon"],
|
||||
State: m.State,
|
||||
CustomId: m.Labels["custom_id"],
|
||||
Id: m.ID,
|
||||
Port: m.Labels["web"],
|
||||
Index: m.Labels["index"],
|
||||
//Order: m.Labels["order"],
|
||||
Image: m.Image,
|
||||
NewVersion: newVersion,
|
||||
Type: m.Labels["origin"],
|
||||
//Slogan: m.Slogan,
|
||||
//Rely: m.Rely,
|
||||
})
|
||||
} 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,
|
||||
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
|
||||
func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
|
||||
func (a *appStruct) GetSystemAppList() []types.Container {
|
||||
//获取docker应用
|
||||
cli, err := client2.NewClientWithOpts(client2.FromEnv)
|
||||
if err != nil {
|
||||
|
@ -126,51 +316,21 @@ func (a *appStruct) GetSystemAppList() *[]model2.MyAppList {
|
|||
|
||||
//获取本地数据库应用
|
||||
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
|
||||
// var lm []model2.AppListDBModel
|
||||
// a.db.Table(model2.CONTAINERTABLENAME).Select("title,icon,port_map,`index`,container_id,position,label,slogan,image,volumes").Find(&lm)
|
||||
|
||||
list := []model2.MyAppList{}
|
||||
lMap := make(map[string]interface{})
|
||||
for _, dbModel := range lm {
|
||||
lMap[dbModel.ContainerId] = dbModel
|
||||
}
|
||||
for _, container := range containers {
|
||||
//list := []model2.MyAppList{}
|
||||
//lMap := make(map[string]interface{})
|
||||
// for _, dbModel := range lm {
|
||||
// lMap[dbModel.ContainerId] = dbModel
|
||||
// }
|
||||
|
||||
if lMap[container.ID] != nil {
|
||||
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
|
||||
return containers
|
||||
|
||||
}
|
||||
func (a *appStruct) GetAllDBApps() []model2.AppListDBModel {
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image").Find(&lm)
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("custom_id,title,icon,container_id,label,slogan,image,port_map").Find(&lm)
|
||||
return lm
|
||||
}
|
||||
|
||||
|
@ -242,7 +402,7 @@ func (a *appStruct) DelAppConfigDir(path string) {
|
|||
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{})
|
||||
}
|
||||
|
||||
|
@ -298,31 +458,29 @@ func (a *appStruct) GetHardwareUsageSteam() {
|
|||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
var lm []model2.AppListDBModel
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||
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, Filters: fts})
|
||||
if err != nil {
|
||||
a.log.Error("获取docker容器失败", "app.getmylist", "line:42", err)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
if config.CasaOSGlobalVariables.AppChange {
|
||||
lm = []model2.AppListDBModel{}
|
||||
config.CasaOSGlobalVariables.AppChange = false
|
||||
a.db.Table(model2.CONTAINERTABLENAME).Select("label,title,icon,container_id").Where("origin != ?", "system").Find(&lm)
|
||||
dataApps := dataStats
|
||||
|
||||
dataStats.Range(func(key, value interface{}) bool {
|
||||
dataStats.Delete(key)
|
||||
return true
|
||||
})
|
||||
for _, v := range lm {
|
||||
m, _ := dataApps.Load(v.ContainerId)
|
||||
if m != nil {
|
||||
dataStats.Store(v.ContainerId, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range lm {
|
||||
for _, v := range containers {
|
||||
wg.Add(1)
|
||||
go func(v model2.AppListDBModel, i int) {
|
||||
go func(v types.Container, i int) {
|
||||
defer wg.Done()
|
||||
stats, err := cli.ContainerStats(ctx, v.ContainerId, true)
|
||||
stats, err := cli.ContainerStats(ctx, v.ID, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -331,19 +489,15 @@ func (a *appStruct) GetHardwareUsageSteam() {
|
|||
if err := decode.Decode(&data); err == io.EOF {
|
||||
return
|
||||
}
|
||||
m, _ := dataStats.Load(v.ContainerId)
|
||||
m, _ := dataStats.Load(v.ID)
|
||||
dockerStats := model.DockerStatsModel{}
|
||||
if m != nil {
|
||||
dockerStats.Pre = m.(model.DockerStatsModel).Data
|
||||
}
|
||||
dockerStats.Data = data
|
||||
dockerStats.Icon = v.Icon
|
||||
if len(v.Label) > 0 {
|
||||
dockerStats.Title = v.Label
|
||||
} else {
|
||||
dockerStats.Title = v.Title
|
||||
}
|
||||
dataStats.Store(v.ContainerId, dockerStats)
|
||||
dockerStats.Icon = v.Labels["icon"]
|
||||
dockerStats.Title = strings.ReplaceAll(v.Names[0], "/", "")
|
||||
dataStats.Store(v.ID, dockerStats)
|
||||
if i == 99 {
|
||||
stats.Body.Close()
|
||||
}
|
||||
|
|
9
service/app_test.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetCasaOSCount(t *testing.T) {
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
|
@ -154,6 +155,7 @@ func (o *casaService) PushAppAnalyse(uuid, t string, name, language string) {
|
|||
m.Type = t
|
||||
m.Name = name
|
||||
m.Language = language
|
||||
m.Version = types.CURRENTVERSION
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
head := make(map[string]string)
|
||||
|
|
|
@ -137,8 +137,42 @@ func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel {
|
|||
return nil
|
||||
}
|
||||
var m []model.LSBLKModel
|
||||
// strStr := `{
|
||||
// "blockdevices": [
|
||||
// {"name":"loop0", "kname":"loop0", "path":"/dev/loop0", "maj:min":"7:0", "fsavail":"0", "fssize":"62M", "fstype":"squashfs", "fsused":"62M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core20/1405", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":619, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop1", "kname":"loop1", "path":"/dev/loop1", "maj:min":"7:1", "fsavail":"0", "fssize":"55.6M", "fstype":"squashfs", "fsused":"55.6M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core18/2344", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":55, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop2", "kname":"loop2", "path":"/dev/loop2", "maj:min":"7:2", "fsavail":"0", "fssize":"44.8M", "fstype":"squashfs", "fsused":"44.8M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/snapd/15314", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":446, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop3", "kname":"loop3", "path":"/dev/loop3", "maj:min":"7:3", "fsavail":"0", "fssize":"78.9M", "fstype":"squashfs", "fsused":"78.9M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/lxd/22754", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":788, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop4", "kname":"loop4", "path":"/dev/loop4", "maj:min":"7:4", "fsavail":"0", "fssize":"43.8M", "fstype":"squashfs", "fsused":"43.8M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/snapd/15177", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":436, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop5", "kname":"loop5", "path":"/dev/loop5", "maj:min":"7:5", "fsavail":"0", "fssize":"55.5M", "fstype":"squashfs", "fsused":"55.5M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/core18/1997", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":554, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"loop6", "kname":"loop6", "path":"/dev/loop6", "maj:min":"7:6", "fsavail":"0", "fssize":"80M", "fstype":"squashfs", "fsused":"80M", "fsuse%":"100%", "fsver":"4.0", "mountpoint":"/snap/lxd/22826", "label":null, "uuid":null, "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":true, "rm":false, "hotplug":false, "model":null, "serial":null, "size":799, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"mq-deadline", "rq-size":256, "type":"loop", "disc-aln":0, "disc-gran":"4K", "disc-max":"4G", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":null, "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"sda", "kname":"sda", "path":"/dev/sda", "maj:min":"8:0", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"1596101a-e20d-4296-96e2-0870efce554a", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"ST1000DM003-1ER1", "serial":"Z4YCS1B6", "size":9315, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"disk", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c50090db103a", "rand":true, "pkname":null, "hctl":"0:0:0:0", "tran":"sata", "subsystems":"block:scsi:pci", "rev":"CC61", "vendor":"ATA ", "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"sda1", "kname":"sda1", "path":"/dev/sda1", "maj:min":"8:1", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"1596101a-e20d-4296-96e2-0870efce554a", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":9315, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":3072, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"part", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c50090db103a", "rand":true, "pkname":"sda", "hctl":null, "tran":null, "subsystems":"block:scsi:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// },
|
||||
// {"name":"sdb", "kname":"sdb", "path":"/dev/sdb", "maj:min":"8:16", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"baed02d0-e92d-4a00-9609-f94f31271a0e", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"ST1000DM003-1ER1", "serial":"W4Y51MFH", "size":9315, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"disk", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c5008acd2f00", "rand":true, "pkname":null, "hctl":"1:0:0:0", "tran":"sata", "subsystems":"block:scsi:pci", "rev":"CC46", "vendor":"ATA ", "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"sdb1", "kname":"sdb1", "path":"/dev/sdb1", "maj:min":"8:17", "fsavail":null, "fssize":null, "fstype":"zfs_member", "fsused":null, "fsuse%":null, "fsver":"5000", "mountpoint":null, "label":null, "uuid":null, "ptuuid":"baed02d0-e92d-4a00-9609-f94f31271a0e", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":"primary", "partuuid":"57880cc0-2695-41c3-bf14-7161693e5bff", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":9315, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":3072, "min-io":4096, "opt-io":0, "phy-sec":4096, "log-sec":512, "rota":true, "sched":"mq-deadline", "rq-size":64, "type":"part", "disc-aln":0, "disc-gran":"0B", "disc-max":"0B", "disc-zero":false, "wsame":"0B", "wwn":"0x5000c5008acd2f00", "rand":true, "pkname":"sdb", "hctl":null, "tran":null, "subsystems":"block:scsi:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// },
|
||||
// {"name":"nvme0n1", "kname":"nvme0n1", "path":"/dev/nvme0n1", "maj:min":"259:0", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":"LITEON CL1-8D128-HP", "serial":"UJDJA01PJDH3UI", "size":1192, "state":"live", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"disk", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":null, "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"nvme0n1p1", "kname":"nvme0n1p1", "path":"/dev/nvme0n1p1", "maj:min":"259:1", "fsavail":null, "fssize":null, "fstype":null, "fsused":null, "fsuse%":null, "fsver":null, "mountpoint":null, "label":null, "uuid":null, "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"21686148-6449-6e6f-744e-656564454649", "parttypename":"BIOS boot", "partlabel":null, "partuuid":"b2bac638-9468-449f-9669-79be44e3c80d", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"nvme0n1p2", "kname":"nvme0n1p2", "path":"/dev/nvme0n1p2", "maj:min":"259:2", "fsavail":"1.2G", "fssize":"1.4G", "fstype":"ext4", "fsused":"131.5M", "fsuse%":"9%", "fsver":"1.0", "mountpoint":"/boot", "label":null, "uuid":"cd8164e9-bf7a-4684-8a3b-1d9f209b4930", "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":null, "partuuid":"42ed9ed6-1221-4bea-901a-bc2f7b7cb9e1", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":15, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false},
|
||||
// {"name":"nvme0n1p3", "kname":"nvme0n1p3", "path":"/dev/nvme0n1p3", "maj:min":"259:3", "fsavail":null, "fssize":null, "fstype":"LVM2_member", "fsused":null, "fsuse%":null, "fsver":"LVM2 001", "mountpoint":null, "label":null, "uuid":"0G7ryL-p2Ks-i9HS-wvEO-lXHs-oyZX-1KIlZO", "ptuuid":"338abc31-a3d4-4af2-9342-b53268d9e5ac", "pttype":"gpt", "parttype":"0fc63daf-8483-4772-8e79-3d69d8477de4", "parttypename":"Linux filesystem", "partlabel":null, "partuuid":"f6ae2e8c-14ae-4d94-89f1-2c154e909843", "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1177, "state":null, "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":"none", "rq-size":255, "type":"part", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":"eui.0023035630392fe7", "rand":false, "pkname":"nvme0n1", "hctl":null, "tran":"nvme", "subsystems":"block:nvme:pci", "rev":null, "vendor":null, "zoned":"none", "dax":false,
|
||||
// "children": [
|
||||
// {"name":"ubuntu--vg-ubuntu--lv", "kname":"dm-0", "path":"/dev/mapper/ubuntu--vg-ubuntu--lv", "maj:min":"253:0", "fsavail":"78.6G", "fssize":"115.4G", "fstype":"ext4", "fsused":"30.9G", "fsuse%":"27%", "fsver":"1.0", "mountpoint":"/", "label":null, "uuid":"e8a9082f-3643-4820-a5e5-05817d7738c6", "ptuuid":null, "pttype":null, "parttype":null, "parttypename":null, "partlabel":null, "partuuid":null, "partflags":null, "ra":128, "ro":false, "rm":false, "hotplug":false, "model":null, "serial":null, "size":1177, "state":"running", "owner":"root", "group":"disk", "mode":"brw-rw----", "alignment":0, "min-io":512, "opt-io":0, "phy-sec":512, "log-sec":512, "rota":false, "sched":null, "rq-size":128, "type":"lvm", "disc-aln":0, "disc-gran":"512B", "disc-max":"2T", "disc-zero":false, "wsame":"0B", "wwn":null, "rand":false, "pkname":"nvme0n1p3", "hctl":null, "tran":null, "subsystems":"block", "rev":null, "vendor":null, "zoned":"none", "dax":false}
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }`
|
||||
// fmt.Println(gjson.Get(strStr, "blockdevices").String())
|
||||
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
d.log.Error("json ummarshal error", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/docker"
|
||||
|
@ -45,7 +46,8 @@ import (
|
|||
type DockerService interface {
|
||||
DockerPullImage(imageName string, m model2.AppNotify) error
|
||||
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
|
||||
DockerContainerStats(name string) (string, error)
|
||||
DockerListByName(name string) (*types.Container, error)
|
||||
|
@ -58,8 +60,9 @@ type DockerService interface {
|
|||
DockerContainerUpdate(m model.CustomizationPostData, id string) (err error)
|
||||
DockerContainerLog(name string) (string, error)
|
||||
DockerContainerCommit(name string)
|
||||
DockerContainerList() []types.Container
|
||||
DockerNetworkModelList() []types.NetworkResource
|
||||
DockerImageInfo(image string)
|
||||
DockerImageInfo(image string) (types.ImageInspect, error)
|
||||
GetNetWorkNameByNetWorkID(id string) (string, error)
|
||||
ContainerExecShell(container_id string) string
|
||||
}
|
||||
|
@ -69,6 +72,19 @@ type dockerService struct {
|
|||
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 {
|
||||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
exec, err := cli.ContainerExecCreate(context.Background(), container_id, types.ExecConfig{
|
||||
|
@ -119,10 +135,7 @@ func DockerPull() {
|
|||
cli, _ := client2.NewClientWithOpts(client2.FromEnv)
|
||||
defer cli.Close()
|
||||
|
||||
authConfig := types.AuthConfig{
|
||||
Username: "cn-north-4@M4OW0IULZ3U6PCQPBUZC",
|
||||
Password: "7390181a1565f90927bbd98038436b57d6ebc66a3828d7a11dfda42b9c19d91d",
|
||||
}
|
||||
authConfig := types.AuthConfig{}
|
||||
encodedJSON, err := json2.Marshal(authConfig)
|
||||
fmt.Println(err)
|
||||
|
||||
|
@ -174,18 +187,16 @@ func DockerEx() {
|
|||
//
|
||||
//}
|
||||
|
||||
func (ds *dockerService) DockerImageInfo(image string) {
|
||||
func (ds *dockerService) DockerImageInfo(image string) (types.ImageInspect, error) {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -342,6 +353,18 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
|||
}
|
||||
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 containerDbId 数据库的id
|
||||
|
@ -349,7 +372,7 @@ func (ds *dockerService) DockerPullImage(imageName string, m model2.AppNotify) e
|
|||
//param mapPort 容器主端口映射到外部的端口
|
||||
//param tcp 容器其他tcp端口
|
||||
//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 {
|
||||
net = "bridge"
|
||||
}
|
||||
|
@ -442,12 +465,12 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
|||
for _, v := range m.Volumes {
|
||||
path := v.Path
|
||||
if len(path) == 0 {
|
||||
path = docker.GetDir(containerDbId, v.Path)
|
||||
path = docker.GetDir(m.Label, v.Path)
|
||||
if len(path) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
path = strings.ReplaceAll(path, "$AppID", containerDbId)
|
||||
path = strings.ReplaceAll(path, "$AppID", m.Label)
|
||||
//reg1 := regexp.MustCompile(`([^<>/\\\|:""\*\?]+\.\w+$)`)
|
||||
//result1 := reg1.FindAllStringSubmatch(path, -1)
|
||||
//if len(result1) == 0 {
|
||||
|
@ -495,12 +518,19 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
|||
}
|
||||
config := &container.Config{
|
||||
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,
|
||||
// Healthcheck: health,
|
||||
Hostname: m.HostName,
|
||||
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["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}
|
||||
//if net != "host" {
|
||||
config.ExposedPorts = ports
|
||||
|
@ -512,7 +542,7 @@ func (ds *dockerService) DockerContainerCreate(imageName string, containerDbId s
|
|||
hostConfig,
|
||||
&network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{net: {NetworkID: "", Aliases: []string{}}}},
|
||||
nil,
|
||||
containerDbId)
|
||||
m.Label)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -695,6 +725,9 @@ func (ds *dockerService) DockerListByName(name string) (*types.Container, error)
|
|||
if err != nil {
|
||||
return &types.Container{}, err
|
||||
}
|
||||
if len(containers) == 0 {
|
||||
return &types.Container{}, errors.New("not found")
|
||||
}
|
||||
return &containers[0], nil
|
||||
}
|
||||
|
||||
|
|
33
service/down_record.go
Normal 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}
|
||||
}
|
|
@ -11,7 +11,7 @@ type DownloadService interface {
|
|||
SaveDownload(m model2.PersonDownloadDBModel)
|
||||
DelDownload(uuid string)
|
||||
GetDownloadById(uuid string) model2.PersonDownloadDBModel
|
||||
GetDownloadListByState(state string) []model2.PersonDownloadDBModel
|
||||
GetDownloadListByState(state string, t int) []model2.PersonDownloadDBModel
|
||||
SetDownloadError(m model2.PersonDownloadDBModel)
|
||||
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)
|
||||
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 {
|
||||
d.db.Find(&list)
|
||||
d.db.Where("type = ?", t).Find(&list)
|
||||
} else {
|
||||
d.db.Where("state = ?", state).Find(&list)
|
||||
d.db.Where("state = ? AND type= ?", state, t).Find(&list)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"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"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
@ -11,17 +22,26 @@ type FriendService interface {
|
|||
AddFriend(m model2.FriendModel)
|
||||
DeleteFriend(m model2.FriendModel)
|
||||
EditFriendMark(m model2.FriendModel)
|
||||
EditFriendWrite(m model2.FriendModel)
|
||||
EditFriendBlock(m model2.FriendModel)
|
||||
GetFriendById(m model2.FriendModel) model2.FriendModel
|
||||
GetFriendList() (list []model2.FriendModel)
|
||||
GetFriendListRemote() (list []model2.FriendModel)
|
||||
UpdateAddFriendType(m model2.FriendModel)
|
||||
AgreeFrined(id string)
|
||||
GetFriendByToken(token string) model2.FriendModel
|
||||
UpdateOrCreate(m model2.FriendModel)
|
||||
InternalInspection(ips []string, token string)
|
||||
}
|
||||
|
||||
type friendService struct {
|
||||
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) {
|
||||
p.db.Create(&m)
|
||||
}
|
||||
|
@ -31,6 +51,9 @@ func (p *friendService) DeleteFriend(m model2.FriendModel) {
|
|||
func (p *friendService) EditFriendMark(m model2.FriendModel) {
|
||||
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) {
|
||||
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)
|
||||
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) {
|
||||
friend := model2.FriendModel{}
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
return &friendService{db: db}
|
||||
}
|
||||
|
|
20
service/model/o_application.go
Normal 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"
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
)
|
||||
|
||||
const CONTAINERTABLENAME = "o_container"
|
||||
|
||||
//Soon to be removed
|
||||
type AppListDBModel struct {
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Title string `json:"title"`
|
||||
|
@ -52,15 +49,19 @@ func (p *AppListDBModel) TableName() string {
|
|||
}
|
||||
|
||||
type MyAppList struct {
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
State string `json:"state"`
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Index string `json:"index"`
|
||||
Port string `json:"port"`
|
||||
UpTime string `json:"up_time"`
|
||||
Slogan string `json:"slogan"`
|
||||
Rely model.MapStrings `json:"rely"` //[{"mysql":"id"},{"mysql":"id"}]
|
||||
Image string `json:"image"`
|
||||
Volumes string `json:"volumes"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
State string `json:"state"`
|
||||
CustomId string `gorm:"column:custom_id;primary_key" json:"custom_id"`
|
||||
Index string `json:"index"`
|
||||
//Order string `json:"order"`
|
||||
Port string `json:"port"`
|
||||
UpTime string `json:"up_time"`
|
||||
Slogan string `json:"slogan"`
|
||||
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"`
|
||||
}
|
||||
|
|
16
service/model/o_down_record.go
Normal 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"
|
||||
}
|
|
@ -3,7 +3,7 @@ package model
|
|||
type PersonDownloadDBModel struct {
|
||||
UUID string `gorm:"column:uuid;primary_key" json:"uuid"`
|
||||
State int `json:"state"` //
|
||||
Type int `json:"type"` //defult 1
|
||||
Type int `json:"type"` //defult 0
|
||||
Name string `json:"name"` //file name
|
||||
Size int64 `json:"size"` //file size
|
||||
BlockSize int `json:"block_size"` //Size of each file block
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package model
|
||||
|
||||
type FriendModel struct {
|
||||
State int `json:"state"` //Reserved
|
||||
State int `json:"state"`
|
||||
CreatedAt int64 `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt int64 `gorm:"autoCreateTime;autoUpdateTime" json:"updated_at"`
|
||||
NickName string `json:"nick_name"`
|
||||
|
@ -12,6 +12,8 @@ type FriendModel struct {
|
|||
Profile string `json:"profile"` //Description
|
||||
OnLine bool `json:"on_line" gorm:"-"`
|
||||
Version int `json:"version"`
|
||||
Write bool `json:"write"`
|
||||
LocalIP string `json:"local_ip"`
|
||||
}
|
||||
|
||||
func (p *FriendModel) TableName() string {
|
||||
|
|
|
@ -15,8 +15,10 @@ import (
|
|||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
httper2 "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
port2 "github.com/IceWhaleTech/CasaOS/pkg/utils/port"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
|
@ -26,6 +28,7 @@ import (
|
|||
|
||||
type PersonService interface {
|
||||
GetPersionInfo(token string) (m model.PersionModel, err error)
|
||||
GetPersionNetWorkTypeDetection() string
|
||||
}
|
||||
|
||||
type personService struct {
|
||||
|
@ -34,11 +37,12 @@ type personService struct {
|
|||
|
||||
var IpInfo model.PersionModel
|
||||
var CancelList map[string]string
|
||||
var InternalInspection map[string][]string
|
||||
|
||||
func PushIpInfo(token string) {
|
||||
|
||||
m := model.PersionModel{}
|
||||
m.Ips = GetDeviceAllIP()
|
||||
m.Ips = ip_helper.GetDeviceAllIP("")
|
||||
m.Token = token
|
||||
b, _ := json.Marshal(m)
|
||||
|
||||
|
@ -54,6 +58,16 @@ func (p *personService) GetPersionInfo(token string) (m model.PersionModel, err
|
|||
err = json.Unmarshal([]byte(infoS), &m)
|
||||
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 {
|
||||
return &personService{db: db}
|
||||
|
@ -193,6 +207,11 @@ func ProcessingContent(stream quic.Stream) {
|
|||
} else {
|
||||
list = []model.Path{}
|
||||
}
|
||||
if rFriend.Write {
|
||||
for i := 0; i < len(list); i++ {
|
||||
list[i].Write = true
|
||||
}
|
||||
}
|
||||
m.To = m.From
|
||||
m.Data = list
|
||||
m.From = config.ServerInfo.Token
|
||||
|
@ -200,10 +219,9 @@ func ProcessingContent(stream quic.Stream) {
|
|||
break
|
||||
} 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
|
||||
} else if m.Type == types.PERSONADDFRIEND {
|
||||
fmt.Println("有用户来请求加好友", m)
|
||||
friend := model2.FriendModel{}
|
||||
dataModelByte, _ := json.Marshal(m.Data)
|
||||
err := json.Unmarshal(dataModelByte, &friend)
|
||||
|
@ -225,6 +243,7 @@ func ProcessingContent(stream quic.Stream) {
|
|||
break
|
||||
} else if m.Type == types.PERSONCONNECTION {
|
||||
if len(m.Data.(string)) > 0 {
|
||||
fmt.Println("设置ip", m.Data.(string))
|
||||
UDPAddressMap[m.From] = m.Data.(string)
|
||||
} else {
|
||||
delete(UDPAddressMap, m.From)
|
||||
|
@ -236,14 +255,18 @@ func ProcessingContent(stream quic.Stream) {
|
|||
// mi.Token = config.ServerInfo.Token
|
||||
|
||||
user := MyService.Casa().GetUserInfoByShareId(m.From)
|
||||
|
||||
//好友申请 //不是好友
|
||||
friend := model2.FriendModel{}
|
||||
friend.Token = m.From
|
||||
friend.Avatar = user.Avatar
|
||||
friend.Block = false
|
||||
friend.NickName = user.NickName
|
||||
friend.Profile = user.Avatar
|
||||
friend.Write = false
|
||||
friend.Version = user.Version
|
||||
if len(config.UserInfo.Public) > 0 {
|
||||
friend.State = types.FRIENDSTATEREQUEST
|
||||
}
|
||||
MyService.Friend().AddFriend(friend)
|
||||
|
||||
msg := model.MessageModel{}
|
||||
|
@ -254,10 +277,96 @@ func ProcessingContent(stream quic.Stream) {
|
|||
msg.UUId = m.UUId
|
||||
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
|
||||
} else if m.Type == types.PERSONCANCEL {
|
||||
CancelList[m.UUId] = "cancel"
|
||||
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 {
|
||||
//不应有不做返回的数据
|
||||
//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{}
|
||||
|
||||
msg := model.MessageModel{}
|
||||
|
@ -341,7 +450,7 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
|
|||
tran.Length = length
|
||||
|
||||
fileMsg := model.MessageModel{}
|
||||
fileMsg.Type = types.PERSONDOWNLOAD
|
||||
fileMsg.Type = t
|
||||
fileMsg.Data = tran
|
||||
fileMsg.From = config.ServerInfo.Token
|
||||
fileMsg.To = to
|
||||
|
@ -356,5 +465,18 @@ func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ var Cache *cache.Cache
|
|||
var MyService Repository
|
||||
|
||||
var WebSocketConns []*websocket.Conn
|
||||
|
||||
var NewVersionApp map[string]string
|
||||
var SocketRun bool
|
||||
|
||||
type Repository interface {
|
||||
|
@ -34,6 +34,7 @@ type Repository interface {
|
|||
Person() PersonService
|
||||
Friend() FriendService
|
||||
Download() DownloadService
|
||||
DownRecord() DownRecordService
|
||||
}
|
||||
|
||||
func NewService(db *gorm.DB, log loger2.OLog) Repository {
|
||||
|
@ -57,6 +58,7 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
|
|||
person: NewPersonService(db),
|
||||
friend: NewFriendService(db),
|
||||
download: NewDownloadService(db),
|
||||
downrecord: NewDownRecordService(db),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +81,11 @@ type store struct {
|
|||
person PersonService
|
||||
friend FriendService
|
||||
download DownloadService
|
||||
downrecord DownRecordService
|
||||
}
|
||||
|
||||
func (c *store) DownRecord() DownRecordService {
|
||||
return c.downrecord
|
||||
}
|
||||
|
||||
func (c *store) Download() DownloadService {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/loger"
|
||||
)
|
||||
|
||||
|
@ -20,6 +21,8 @@ type SystemService interface {
|
|||
GetTimeZone() string
|
||||
UpdateUSBAutoMount(state string)
|
||||
ExecUSBAutoMountShell(state string)
|
||||
UpAppOrderFile(str string)
|
||||
GetAppOrderFile() []byte
|
||||
}
|
||||
type systemService struct {
|
||||
log loger.OLog
|
||||
|
@ -62,9 +65,15 @@ func (s *systemService) UpSystemConfig(str string, widget string) {
|
|||
}
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
func (s *systemService) UpSystemPort(port string) {
|
||||
|
|
|
@ -11,13 +11,16 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
path2 "path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/model"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/quic_helper"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
||||
"github.com/IceWhaleTech/CasaOS/pkg/utils/ip_helper"
|
||||
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
||||
"github.com/IceWhaleTech/CasaOS/types"
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
|
@ -29,6 +32,65 @@ var PeopleMap map[string]quic.Stream
|
|||
var Message chan model.MessageModel
|
||||
var UDPAddressMap map[string]string
|
||||
|
||||
func UDPSendData(msg model.MessageModel, localFilePath string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*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
|
||||
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(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
@ -142,139 +204,17 @@ func ReadContent(stream quic.Stream) {
|
|||
}
|
||||
m := model.MessageModel{}
|
||||
err = json.Unmarshal(messageByte, &m)
|
||||
fmt.Println("客户端", m)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
break
|
||||
}
|
||||
|
||||
if m.Type == types.PERSONDOWNLOAD {
|
||||
|
||||
dataModelByte, _ := json.Marshal(m.Data)
|
||||
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)
|
||||
}
|
||||
|
||||
r := SaveFile(m, stream)
|
||||
if r {
|
||||
break
|
||||
}
|
||||
} else if m.Type == types.PERSONSUMMARY {
|
||||
|
||||
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)
|
||||
|
||||
Summary(m, "download")
|
||||
} else if m.Type == types.PERSONCONNECTION {
|
||||
if len(m.Data.(string)) > 0 {
|
||||
UDPAddressMap[m.From] = m.Data.(string)
|
||||
|
@ -295,7 +235,7 @@ func ReadContent(stream quic.Stream) {
|
|||
go Dial(msg, false)
|
||||
Message <- m
|
||||
break
|
||||
} else if m.Type == "get_ip" {
|
||||
} else if m.Type == types.PERSONGETIP {
|
||||
notify := model2.AppNotify{}
|
||||
notify.CustomId = m.From
|
||||
if len(m.Data.(string)) == 0 {
|
||||
|
@ -312,9 +252,32 @@ func ReadContent(stream quic.Stream) {
|
|||
go MyService.Notify().SendText(notify)
|
||||
}
|
||||
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
|
||||
break
|
||||
} else {
|
||||
|
||||
Message <- m
|
||||
}
|
||||
}
|
||||
|
@ -334,23 +297,55 @@ func SendIPToServer() {
|
|||
|
||||
func LoopFriend() {
|
||||
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++ {
|
||||
msg := model.MessageModel{}
|
||||
msg.Type = "get_ip"
|
||||
if _, ok := UDPAddressMap[list[i].Token]; !ok {
|
||||
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.From = config.ServerInfo.Token
|
||||
msg.To = list[i].Token
|
||||
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 := model2.AppNotify{}
|
||||
notify.CustomId = data.From
|
||||
notify.Type = types.NOTIFY_TYPE_PERSION_FIRNED_LEAVE
|
||||
go MyService.Notify().SendText(notify)
|
||||
|
||||
msg.Type = types.PERSONHELLO
|
||||
msg.Data = ""
|
||||
msg.From = config.ServerInfo.Token
|
||||
msg.To = list[i].Token
|
||||
msg.UUId = uuid.NewV4().String()
|
||||
if _, ok := UDPAddressMap[list[i].Token]; ok {
|
||||
go Dial(msg, false)
|
||||
delete(UDPAddressMap, list[i].Token)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
go func(shareId string) {
|
||||
user := MyService.Casa().GetUserInfoByShareId(shareId)
|
||||
|
@ -368,3 +363,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
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ type ZiMaService interface {
|
|||
CreateFile(path string) (int, error)
|
||||
RenameFile(oldF, newF string) (int, error)
|
||||
GetCpuInfo() []cpu.InfoStat
|
||||
GetDeviceTree() string
|
||||
}
|
||||
|
||||
var NetArray [][]model.IOCountersStat
|
||||
|
@ -86,6 +87,16 @@ func (c *zima) GetDiskInfo() *disk.UsageStat {
|
|||
|
||||
//获取硬盘目录
|
||||
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)
|
||||
dirs := []model.Path{}
|
||||
|
@ -139,6 +150,10 @@ func (c *zima) GetNet(physics bool) []string {
|
|||
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetNetCard " + t)
|
||||
}
|
||||
|
||||
func (c *zima) GetDeviceTree() string {
|
||||
return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDeviceTree")
|
||||
}
|
||||
|
||||
//shell脚本参数 { 网卡名称 }
|
||||
func (c *zima) GetNetState(name string) string {
|
||||
return command2.ExecResultStr("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;CatNetCardState " + name)
|
||||
|
|
|
@ -32,7 +32,7 @@ GetNetCard() {
|
|||
|
||||
|
||||
GetTimeZone(){
|
||||
timedatectl | grep "Time zone" | awk '{print $3}'
|
||||
timedatectl | grep "Time zone" | awk '{printf $3}'
|
||||
}
|
||||
|
||||
#查看网卡状态
|
||||
|
@ -341,4 +341,8 @@ USB_Remove_File() {
|
|||
((EUID)) && sudo_cmd="sudo"
|
||||
$sudo_cmd rm -fr /etc/udev/rules.d/11-usb-mount.rules
|
||||
$sudo_cmd rm -fr /etc/systemd/system/usb-mount@.service
|
||||
}
|
||||
}
|
||||
|
||||
GetDeviceTree(){
|
||||
cat /proc/device-tree/model
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package types
|
7
types/friend.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package types
|
||||
|
||||
const (
|
||||
FRIENDSTATEDEFAULT = iota
|
||||
FRIENDSTATEWAIT
|
||||
FRIENDSTATEREQUEST
|
||||
)
|
|
@ -12,6 +12,7 @@ const (
|
|||
NOTIFY_TYPE_INSTALL_LOG
|
||||
NOTIFY_TYPE_PERSION_FIRNED_LEAVE
|
||||
NOTIFY_TYPE_PERSION_FIRNED_LIVE
|
||||
NOTIFY_TYPE_HEALTH_CHECK
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
package types
|
||||
|
||||
const PERSONADDFRIEND = "add_user"
|
||||
const PERSONAGREEFRIEND = "agree_user"
|
||||
const PERSONDOWNLOAD = "file_data"
|
||||
const PERSONSUMMARY = "summary"
|
||||
const PERSONGETIP = "get_ip"
|
||||
const PERSONCONNECTION = "connection"
|
||||
const PERSONDIRECTORY = "directory"
|
||||
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 (
|
||||
PERSONFILEDOWNLOAD = iota //default state
|
||||
PERSONFILEUPLOAD
|
||||
PERSONFILERECEIVEUPLOAD //receive upload file
|
||||
)
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
/*
|
||||
* @Author: LinkLeong link@icewhale.com
|
||||
* @Date: 2022-02-17 18:53:22
|
||||
* @LastEditors: LinkLeong
|
||||
* @LastEditTime: 2022-05-13 18:08:25
|
||||
* @FilePath: /CasaOS/types/system.go
|
||||
* @Description:
|
||||
* @Website: https://www.casaos.io
|
||||
* Copyright (c) 2022 by icewhale, All Rights Reserved.
|
||||
*/
|
||||
package types
|
||||
|
||||
const CURRENTVERSION = "0.3.0"
|
||||
const CURRENTVERSION = "0.3.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 = ""
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/ui/img/icon/mstile-150x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/ui/img/icon/mstile-150x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#363636;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
@media ( prefers-color-scheme: dark ) {
|
||||
.st0{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
}
|
||||
</style>
|
||||
<path class="st0" d="M12,22c5.5,0,10-4.5,10-10S17.5,2,12,2S2,6.5,2,12S6.5,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c3.9,0,7-3.1,7-7s-3.1-7-7-7s-7,3.1-7,7S8.1,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c2.2,0,4-1.8,4-4s-1.8-4-4-4s-4,1.8-4,4S9.8,22,12,22z"/>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#363636;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
@media ( prefers-color-scheme: dark ) {
|
||||
.st0{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
}
|
||||
</style>
|
||||
<path class="st0" d="M12,22c5.5,0,10-4.5,10-10S17.5,2,12,2S2,6.5,2,12S6.5,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c3.9,0,7-3.1,7-7s-3.1-7-7-7s-7,3.1-7,7S8.1,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c2.2,0,4-1.8,4-4s-1.8-4-4-4s-4,1.8-4,4S9.8,22,12,22z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 863 B After Width: | Height: | Size: 877 B |
BIN
web/fonts/materialdesignicons-webfont.0fb040cb.woff2
Normal file
BIN
web/fonts/materialdesignicons-webfont.1514bb9f.ttf
Normal file
BIN
web/fonts/materialdesignicons-webfont.5a409f9f.woff
Normal file
BIN
web/fonts/materialdesignicons-webfont.ff90567b.eot
Normal file
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
67
web/img/Files.svg
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" 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#" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<style type="text/css"/>
|
||||
<linearGradient id="linearGradient1951" x1="100" x2="133.19" y1="17.453" y2="51.606" gradientTransform="matrix(.26458 0 0 .24792 -20.108 .79576)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#26abe7" offset="0"/>
|
||||
<stop stop-color="#0669bc" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient11110" x1=".52917" x2="16.404" y1="5.3815" y2="5.3815" gradientTransform="matrix(1 0 0 .93702 6.5e-7 .92263)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#fff" offset="0"/>
|
||||
<stop stop-color="#fff" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient1911" x1="25.085" x2="25.085" y1="24.031" y2="26.412" gradientTransform="translate(-17.897,-21.369)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0271ca" offset="0"/>
|
||||
<stop stop-color="#0768ba" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient9169" x1="7.4082" x2="7.4082" y1="4.2333" y2="5.5561" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#fff" offset="0"/>
|
||||
<stop stop-color="#e3e4e5" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient23227" x1=".52916" x2="16.404" y1="14.196" y2="14.196" gradientTransform="translate(-18.282 -.015458)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0a5ba8" stop-opacity=".99608" offset="0"/>
|
||||
<stop stop-color="#104a8c" stop-opacity=".99608" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path d="m1.1977 2.2644c-0.3653 0-0.66145 0.32575-0.66145 0.72759v2.9636c-0.0026 0.02629-0.0072 0.052-0.0072 0.07906v7.9373c0 0.40184 0.29614 0.72759 0.66144 0.72759h14.552c0.36531 0 0.66144-0.32575 0.66144-0.72759v-9.393c0-0.40184-0.29614-0.72759-0.66144-0.72759v5.16e-4h-8.1993l-0.89864-1.1095s-0.36607-0.478-1.0583-0.478h-1.3229z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="url(#linearGradient1911)" image-rendering="auto" shape-rendering="auto" solid-color="#000000" stop-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;font-variation-settings:normal;inline-size:0;isolation:auto;mix-blend-mode:normal;shape-margin:0;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
|
||||
<g fill="#5e4aa6" stroke-width=".26458">
|
||||
<circle cx="-330.35" cy="-328.38" r="0"/>
|
||||
<circle cx="-312.11" cy="-326.25" r="0"/>
|
||||
<circle cx="-306.02" cy="-333.07" r="0"/>
|
||||
<circle cx="-308.84" cy="-326.01" r="0"/>
|
||||
<circle cx="-328.8" cy="-330.45" r="0"/>
|
||||
<g transform="translate(24.108 -4.592)">
|
||||
<circle cx="-330.35" cy="-328.38" r="0"/>
|
||||
<circle cx="-312.11" cy="-326.25" r="0"/>
|
||||
<circle cx="-306.02" cy="-333.07" r="0"/>
|
||||
<circle cx="-308.84" cy="-326.01" r="0"/>
|
||||
<circle cx="-328.8" cy="-330.45" r="0"/>
|
||||
</g>
|
||||
<g transform="translate(2.3479 -14.944)">
|
||||
<circle cx="-330.35" cy="-328.38" r="0"/>
|
||||
<circle cx="-312.11" cy="-326.25" r="0"/>
|
||||
<circle cx="-306.02" cy="-333.07" r="0"/>
|
||||
<circle cx="-308.84" cy="-326.01" r="0"/>
|
||||
<circle cx="-328.8" cy="-330.45" r="0"/>
|
||||
</g>
|
||||
<g transform="translate(.000295 -.00036978)">
|
||||
<circle cx="-330.35" cy="-328.38" r="0"/>
|
||||
<circle cx="-312.11" cy="-326.25" r="0"/>
|
||||
<circle cx="-306.02" cy="-333.07" r="0"/>
|
||||
<circle cx="-308.84" cy="-326.01" r="0"/>
|
||||
<circle cx="-328.8" cy="-330.45" r="0"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="m0.52916 13.691v0.28215c0 0.20092 0.07357 0.3825 0.19327 0.51417s0.28553 0.21342 0.46818 0.21342h14.552c0.18265 0 0.34796-0.08175 0.46766-0.21342s0.19378-0.31325 0.19378-0.51417v-0.28215c0 0.20092-0.07409 0.3825-0.19378 0.51417-0.1197 0.13167-0.28501 0.21342-0.46766 0.21342h-14.552c-0.18265 0-0.34848-0.08176-0.46818-0.21342s-0.19327-0.31325-0.19327-0.51417z" fill="url(#linearGradient23227)" stroke-width=".26458"/>
|
||||
<rect x=".79373" y="4.2333" width="15.346" height="8.9957" ry=".79373" fill="url(#linearGradient9169)" stroke-linecap="round" stroke-linejoin="round" stroke-width=".1077"/>
|
||||
<path d="m7.542 4.7624s-0.35919 0.44853-1.1575 0.74229c-0.03271 0.0055-0.06509 0.010846-0.10077 0.015978h-5.4967c-0.21986 0-0.41824 0.082975-0.56171 0.21741-0.13937 0.13058-0.22042 0.31234-0.2253 0.51133v0.48421c0 0.02369-0.0021296 0.045593 0 0.073482l0.52916 6.9301c0.014339 0.18779 0.07357 0.35841 0.19327 0.48179s0.28553 0.19998 0.46818 0.19998h14.552c0.18265 0 0.34796-0.0766 0.46766-0.19998s0.18179-0.29386 0.19378-0.48179l0.52916-8.2935c0.011991-0.18793-0.07408-0.35889-0.19378-0.48227-0.11945-0.1231-0.28449-0.19866-0.46665-0.19901h-8.0112z" fill="url(#linearGradient1951)"/>
|
||||
<path d="m7.542 4.7624s-0.35919 0.44853-1.1575 0.74229c-0.03271 0.0055-0.06509 0.010846-0.10077 0.015978h-5.49c-0.21986 0-0.41824 0.082975-0.56171 0.21741-0.13937 0.13058-0.22041 0.31234-0.2253 0.51132l-0.0067094 0.36074c0.0049-0.19899 0.092639-0.38123 0.23201-0.51181 0.14347-0.13443 0.34185-0.21741 0.56171-0.21741h5.49c0.03568-0.00513 0.06806-0.01048 0.10077-0.015978 0.75911-0.24646 1.2883-0.74229 1.2883-0.74229h8.5998c0.18216 3.471e-4 0.34718 0.075914 0.46663 0.19901 0.1197 0.12338 0.19378 0.29401 0.19378 0.48227v-0.36025c0-0.18827-0.07408-0.35889-0.19378-0.48227-0.11945-0.1231-0.28447-0.19866-0.46663-0.19901h-8.0112z" fill="url(#linearGradient11110)" opacity=".3"/>
|
||||
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
|
@ -1,11 +1,11 @@
|
|||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.32" x="0.435625" y="0.435625" width="71.1288" height="71.1288" rx="7.56437" fill="white" stroke="url(#paint0_linear_812_2050)" stroke-width="0.87125"/>
|
||||
<path d="M36.0606 22L36.0239 50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M22 36H50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_812_2050" x1="77.6757" y1="64.5405" x2="35.9839" y2="53.5747" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#CBEFFF" stop-opacity="0.16"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect opacity="0.32" x="0.435625" y="0.435625" width="71.1288" height="71.1288" rx="7.56437" fill="white" stroke="url(#paint0_linear_812_2050)" stroke-width="0.87125"/>
|
||||
<path d="M36.0606 22L36.0239 50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M22 36H50" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_812_2050" x1="77.6757" y1="64.5405" x2="35.9839" y2="53.5747" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#CBEFFF" stop-opacity="0.16"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 763 B |
|
@ -1,25 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#A4C639" d="M32,0c17.7,0,32,14.3,32,32S49.7,64,32,64S0,49.7,0,32S14.3,0,32,0z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M16.6,24.6c-1.4,0-2.6,1.2-2.6,2.6L14,38c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-10.9
|
||||
C19.3,25.7,18.1,24.6,16.6,24.6 M37.8,14.8l1.8-3.3c0.1-0.2,0-0.4-0.1-0.5c-0.2-0.1-0.4,0-0.5,0.1l-1.9,3.3
|
||||
c-1.6-0.7-3.3-1.1-5.1-1.1c-1.8,0-3.6,0.4-5.1,1.1L25,11.2C24.9,11,24.7,11,24.5,11c-0.2,0.1-0.2,0.3-0.1,0.5l1.8,3.3
|
||||
c-3.6,1.8-6,5.3-6,9.3l23.6,0C43.8,20.2,41.4,16.7,37.8,14.8 M26.6,19.9c-0.5,0-1-0.4-1-1c0-0.5,0.4-1,1-1c0.5,0,1,0.4,1,1
|
||||
C27.6,19.5,27.2,19.9,26.6,19.9 M37.4,19.9c-0.5,0-1-0.4-1-1c0-0.5,0.4-1,1-1c0.5,0,1,0.4,1,1C38.4,19.5,37.9,19.9,37.4,19.9
|
||||
M20.3,25.1l0,16.8c0,1.5,1.3,2.8,2.8,2.8l1.9,0l0,5.7c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-5.7l3.5,0l0,5.7
|
||||
c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-5.7l1.9,0c1.5,0,2.8-1.2,2.8-2.8l0-16.8L20.3,25.1z M50,27.2
|
||||
c0-1.4-1.2-2.6-2.6-2.6c-1.4,0-2.6,1.2-2.6,2.6l0,10.9c0,1.4,1.2,2.6,2.6,2.6c1.4,0,2.6-1.2,2.6-2.6L50,27.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#A4C639" d="M32,0c17.7,0,32,14.3,32,32S49.7,64,32,64S0,49.7,0,32S14.3,0,32,0z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M16.6,24.6c-1.4,0-2.6,1.2-2.6,2.6L14,38c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-10.9
|
||||
C19.3,25.7,18.1,24.6,16.6,24.6 M37.8,14.8l1.8-3.3c0.1-0.2,0-0.4-0.1-0.5c-0.2-0.1-0.4,0-0.5,0.1l-1.9,3.3
|
||||
c-1.6-0.7-3.3-1.1-5.1-1.1c-1.8,0-3.6,0.4-5.1,1.1L25,11.2C24.9,11,24.7,11,24.5,11c-0.2,0.1-0.2,0.3-0.1,0.5l1.8,3.3
|
||||
c-3.6,1.8-6,5.3-6,9.3l23.6,0C43.8,20.2,41.4,16.7,37.8,14.8 M26.6,19.9c-0.5,0-1-0.4-1-1c0-0.5,0.4-1,1-1c0.5,0,1,0.4,1,1
|
||||
C27.6,19.5,27.2,19.9,26.6,19.9 M37.4,19.9c-0.5,0-1-0.4-1-1c0-0.5,0.4-1,1-1c0.5,0,1,0.4,1,1C38.4,19.5,37.9,19.9,37.4,19.9
|
||||
M20.3,25.1l0,16.8c0,1.5,1.3,2.8,2.8,2.8l1.9,0l0,5.7c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-5.7l3.5,0l0,5.7
|
||||
c0,1.4,1.2,2.6,2.6,2.6c1.5,0,2.6-1.2,2.6-2.6l0-5.7l1.9,0c1.5,0,2.8-1.2,2.8-2.8l0-16.8L20.3,25.1z M50,27.2
|
||||
c0-1.4-1.2-2.6-2.6-2.6c-1.4,0-2.6,1.2-2.6,2.6l0,10.9c0,1.4,1.2,2.6,2.6,2.6c1.4,0,2.6-1.2,2.6-2.6L50,27.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -1,28 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#F4F4F4;}
|
||||
.st1{opacity:0.1;fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_1_);enable-background:new ;}
|
||||
.st2{fill:#999999;}
|
||||
</style>
|
||||
<g id="图层_1">
|
||||
<g transform="scale(.26458)">
|
||||
<path class="st0" d="M49.1,15.1h143.6c10.4,0,18.9,8.5,18.9,18.9v173.9c0,10.4-8.5,18.9-18.9,18.9H49.1
|
||||
c-10.4,0-18.9-8.5-18.9-18.9V34C30.2,23.6,38.7,15.1,49.1,15.1z"/>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-957.3084" y1="2609.5137" x2="-955.1654" y2="2607.3706" gradientTransform="matrix(2.3333 0 0 -2.3333 2411.3325 6281.5693)">
|
||||
<stop offset="0" style="stop-color:#000000"/>
|
||||
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M211.7,173.9l-52.9,52.9h34c10.5,0,18.9-8.4,18.9-18.9V173.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="图层_2">
|
||||
<path class="st2" d="M41.1,31.4c0-4.2,3.4-6.2,3.6-6.3c-2-2.9-5-3.3-6.1-3.3c-2.6-0.3-5.1,1.5-6.4,1.5c-1.3,0-3.3-1.5-5.5-1.4
|
||||
c-2.8,0-5.4,1.6-6.9,4.2c-2.9,5.1-0.8,12.6,2.1,16.8c1.4,2,3.1,4.3,5.3,4.2c2.1-0.1,2.9-1.4,5.4-1.4c2.5,0,3.3,1.4,5.5,1.3
|
||||
c2.3,0,3.7-2.1,5.1-4.1c1.6-2.3,2.3-4.6,2.3-4.7C45.5,38.1,41.1,36.4,41.1,31.4L41.1,31.4z M36.9,19c1.2-1.4,1.9-3.4,1.7-5.3
|
||||
c-1.7,0.1-3.7,1.1-4.9,2.5c-1.1,1.2-2,3.2-1.8,5.1C33.8,21.5,35.7,20.5,36.9,19L36.9,19z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#F4F4F4;}
|
||||
.st1{opacity:0.1;fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_1_);enable-background:new ;}
|
||||
.st2{fill:#999999;}
|
||||
</style>
|
||||
<g id="图层_1">
|
||||
<g transform="scale(.26458)">
|
||||
<path class="st0" d="M49.1,15.1h143.6c10.4,0,18.9,8.5,18.9,18.9v173.9c0,10.4-8.5,18.9-18.9,18.9H49.1
|
||||
c-10.4,0-18.9-8.5-18.9-18.9V34C30.2,23.6,38.7,15.1,49.1,15.1z"/>
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-957.3084" y1="2609.5137" x2="-955.1654" y2="2607.3706" gradientTransform="matrix(2.3333 0 0 -2.3333 2411.3325 6281.5693)">
|
||||
<stop offset="0" style="stop-color:#000000"/>
|
||||
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M211.7,173.9l-52.9,52.9h34c10.5,0,18.9-8.4,18.9-18.9V173.9z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="图层_2">
|
||||
<path class="st2" d="M41.1,31.4c0-4.2,3.4-6.2,3.6-6.3c-2-2.9-5-3.3-6.1-3.3c-2.6-0.3-5.1,1.5-6.4,1.5c-1.3,0-3.3-1.5-5.5-1.4
|
||||
c-2.8,0-5.4,1.6-6.9,4.2c-2.9,5.1-0.8,12.6,2.1,16.8c1.4,2,3.1,4.3,5.3,4.2c2.1-0.1,2.9-1.4,5.4-1.4c2.5,0,3.3,1.4,5.5,1.3
|
||||
c2.3,0,3.7-2.1,5.1-4.1c1.6-2.3,2.3-4.6,2.3-4.7C45.5,38.1,41.1,36.4,41.1,31.4L41.1,31.4z M36.9,19c1.2-1.4,1.9-3.4,1.7-5.3
|
||||
c-1.7,0.1-3.7,1.1-4.9,2.5c-1.1,1.2-2,3.2-1.8,5.1C33.8,21.5,35.7,20.5,36.9,19L36.9,19z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 84 KiB |
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
</style>
|
||||
<path class="st0" d="M12,22c5.5,0,10-4.5,10-10S17.5,2,12,2S2,6.5,2,12S6.5,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c3.9,0,7-3.1,7-7s-3.1-7-7-7s-7,3.1-7,7S8.1,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c2.2,0,4-1.8,4-4s-1.8-4-4-4s-4,1.8-4,4S9.8,22,12,22z"/>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:2;}
|
||||
</style>
|
||||
<path class="st0" d="M12,22c5.5,0,10-4.5,10-10S17.5,2,12,2S2,6.5,2,12S6.5,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c3.9,0,7-3.1,7-7s-3.1-7-7-7s-7,3.1-7,7S8.1,22,12,22z"/>
|
||||
<path class="st0" d="M12,22c2.2,0,4-1.8,4-4s-1.8-4-4-4s-4,1.8-4,4S9.8,22,12,22z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 729 B After Width: | Height: | Size: 740 B |
|
@ -1,39 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 120 120" style="enable-background:new 0 0 120 120;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#SVGID_2_);}
|
||||
.st2{fill:url(#SVGID_3_);}
|
||||
</style>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="60" y1="122" x2="60" y2="2" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="0" style="stop-color:#5A9CFF"/>
|
||||
<stop offset="0.879" style="stop-color:#2A23D5"/>
|
||||
<stop offset="1" style="stop-color:#4A3CEC"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M0,60C0,26.9,26.9,0,60,0l0,0c33.1,0,60,26.9,60,60l0,0c0,33.1-26.9,60-60,60l0,0C26.9,120,0,93.1,0,60L0,60z"
|
||||
/>
|
||||
<g>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="59.9999" y1="82" x2="59.9997" y2="29" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="3.509020e-02" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.5256" style="stop-color:#B0D4FF"/>
|
||||
<stop offset="0.8371" style="stop-color:#DEEDFF"/>
|
||||
<stop offset="1" style="stop-color:#FEFEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M75.1,42.1c0,8.4-6.8,15.1-15.1,15.1c-8.4,0-15.1-6.8-15.1-15.1S51.6,27,60,27C68.4,27,75.1,33.8,75.1,42.1z"
|
||||
/>
|
||||
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="60" y1="82" x2="59.9998" y2="29" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="3.509020e-02" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.5256" style="stop-color:#B0D4FF"/>
|
||||
<stop offset="0.8371" style="stop-color:#DEEDFF"/>
|
||||
<stop offset="1" style="stop-color:#FEFEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M34.4,71.7c6.9-5.6,15.8-9,25.6-9c9.8,0,18.7,3.4,25.6,9c3.9,3.2,3.9,9.1,0,12.3c-6.9,5.6-15.8,9-25.6,9
|
||||
c-9.8,0-18.7-3.4-25.6-9C30.5,80.8,30.5,74.9,34.4,71.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 120 120" style="enable-background:new 0 0 120 120;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#SVGID_2_);}
|
||||
.st2{fill:url(#SVGID_3_);}
|
||||
</style>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="60" y1="122" x2="60" y2="2" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="0" style="stop-color:#5A9CFF"/>
|
||||
<stop offset="0.879" style="stop-color:#2A23D5"/>
|
||||
<stop offset="1" style="stop-color:#4A3CEC"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M0,60C0,26.9,26.9,0,60,0l0,0c33.1,0,60,26.9,60,60l0,0c0,33.1-26.9,60-60,60l0,0C26.9,120,0,93.1,0,60L0,60z"
|
||||
/>
|
||||
<g>
|
||||
<g>
|
||||
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="59.9999" y1="82" x2="59.9997" y2="29" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="3.509020e-02" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.5256" style="stop-color:#B0D4FF"/>
|
||||
<stop offset="0.8371" style="stop-color:#DEEDFF"/>
|
||||
<stop offset="1" style="stop-color:#FEFEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M75.1,42.1c0,8.4-6.8,15.1-15.1,15.1c-8.4,0-15.1-6.8-15.1-15.1S51.6,27,60,27C68.4,27,75.1,33.8,75.1,42.1z"
|
||||
/>
|
||||
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="60" y1="82" x2="59.9998" y2="29" gradientTransform="matrix(1 0 0 -1 0 122)">
|
||||
<stop offset="3.509020e-02" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="0.5256" style="stop-color:#B0D4FF"/>
|
||||
<stop offset="0.8371" style="stop-color:#DEEDFF"/>
|
||||
<stop offset="1" style="stop-color:#FEFEFF"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M34.4,71.7c6.9-5.6,15.8-9,25.6-9c9.8,0,18.7,3.4,25.6,9c3.9,3.2,3.9,9.1,0,12.3c-6.9,5.6-15.8,9-25.6,9
|
||||
c-9.8,0-18.7-3.4-25.6-9C30.5,80.8,30.5,74.9,34.4,71.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
|
@ -1,121 +1,121 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="图层_1" 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#"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 64 64"
|
||||
style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#5E4AA6;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:1.000000e-03;fill:#1E5992;enable-background:new ;}
|
||||
.st3{fill:url(#SVGID_2_);}
|
||||
.st4{opacity:0.3;fill:url(#SVGID_3_);enable-background:new ;}
|
||||
.st5{fill:url(#SVGID_4_);}
|
||||
.st6{fill:url(#SVGID_5_);}
|
||||
.st7{fill:url(#SVGID_6_);}
|
||||
</style>
|
||||
<g>
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<g transform="translate(.000295 -.00032978)">
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
</g>
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
<g transform="translate(2.95e-4,-3.2978e-4)">
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-363.3979" y1="913.4439" x2="-363.3979" y2="911.0629" gradientTransform="matrix(3.7796 0 0 -3.7796 1405.5416 3462.4551)">
|
||||
<stop offset="0" style="stop-color:#0272CB"/>
|
||||
<stop offset="1" style="stop-color:#0768BA"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st1" d="M4.6,8.5c-1.4,0-2.5,1.2-2.5,2.8v11.2
|
||||
c0,0.1,0,0.2,0,0.3v30c0,1.5,1.1,2.8,2.5,2.8h55c1.4,0,2.5-1.2,2.5-2.8V17.2c0-1.5-1.1-2.8-2.5-2.8v0h-31l-3.4-4.2
|
||||
c0,0-1.4-1.8-4-1.8h-5L4.6,8.5z"/>
|
||||
<path class="st2" d="M31.6,14.4c-0.4,0-1.2-0.1-2,0.4c-2.8,1.4-2.9,2.2-5.9,2.7H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1
|
||||
v1c0-0.8,0.3-1.5,0.9-2.1c0.5-0.5,1.3-0.9,2.1-0.9h18.7c3-0.5,3.1-1.3,5.9-2.7c0.8-0.4,1.5-0.4,2-0.4h27.9c0.7,0,1.3,0.3,1.8,0.8
|
||||
c0.5,0.5,0.7,1.2,0.7,1.9v-1c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8h-4.4H31.6z M2.1,22.4c0,0.1,0,0.2,0,0.3v1
|
||||
c0-0.1,0-0.2,0-0.3V22.4z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="95.1452" y1="43.801" x2="128.3352" y2="9.648" gradientTransform="matrix(1 0 0 -1 -75.9965 65.4973)">
|
||||
<stop offset="0" style="stop-color:#27AEE9"/>
|
||||
<stop offset="1" style="stop-color:#0669BC"/>
|
||||
</linearGradient>
|
||||
<path class="st3" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1v2
|
||||
c0,0.1,0,0.2,0,0.3v28c0,0.8,0.3,1.4,0.7,1.9c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8c0.5-0.5,0.7-1.2,0.7-1.9V18.2
|
||||
c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.3L28.5,15.5z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-389.233" y1="932.0934" x2="-373.3582" y2="932.0934" gradientTransform="matrix(3.7796 0 0 -3.7796 1473.188 3543.282)">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1v1.5
|
||||
c0-0.8,0.3-1.5,0.9-2.1C3.5,20.3,4.2,20,5,20h18.7c0.1,0,0.3,0,0.4-0.1c2.9-1,4.9-3,4.9-3h30.5c0.7,0,1.3,0.3,1.8,0.8
|
||||
c0.5,0.5,0.7,1.2,0.7,1.9v-1.5c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.3H28.5z M2.1,23.4c0,0.1,0,0.2,0,0.3v1.5
|
||||
c0-0.1,0-0.2,0-0.3V23.4z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-389.2331" y1="923.2966" x2="-373.3582" y2="923.2966" gradientTransform="matrix(3.7796 0 0 -3.7796 1473.188 3543.2234)">
|
||||
<stop offset="0" style="stop-color:#0A5BA8;stop-opacity:0.9961"/>
|
||||
<stop offset="1" style="stop-color:#104A8C;stop-opacity:0.9961"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st5" d="M2,51.6v1.1c0,0.8,0.3,1.4,0.7,1.9
|
||||
c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8c0.5-0.5,0.7-1.2,0.7-1.9v-1.1c0,0.8-0.3,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.8,0.8
|
||||
h-55c-0.7,0-1.3-0.3-1.8-0.8S2,52.4,2,51.6z"/>
|
||||
<g>
|
||||
|
||||
<image style="overflow:visible;opacity:0.25;" width="34" height="44" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAsCAYAAAAATWqyAAAACXBIWXMAAAsSAAALEgHS3X78AAAA
|
||||
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA/JJREFUeNrMmFtv00AQhX2LyYUk
|
||||
pS0VIEA88P9/ES8IqZTShtI0JXHsmE31TXW6dRzb7UMtHSVO1rvHM2cuu0HwQq6wwX/hM61Vep97
|
||||
iYQgAqGgKwHDBpQ+IX9yWzx26IGE+y5kbMHCIXdYg0JI3V2JRypi8b7D0GHkMOC3uCORgsX/OSwc
|
||||
bh2W/HZvGZ9IDImJw7HDEd/7kGljFVtkzcLXDpcOF/yvbronotYYQeKLwyeHE4exwyvGBHWi84hu
|
||||
F1o5zB3OHX7weyEuuiOcePowIkeQ+OrwwWEKkdATnopORR7K2C2Rv1g2gNQNbsog88AiIffmmreQ
|
||||
+Ohw4JB6Ps+BEkmAairDooEQ6jPunnCVRnoIdIIlpnyPxd9m8gwy9lKpRN4rEX6JJSa7xJ9U5I9Y
|
||||
Jk1FpDmKv+LNrrlXIkN5gQPcbC63+SrTQbIjmemggtC7RfFnCO83vl4xbmuB17h0K/B3iH5oOtgx
|
||||
fyURX/m5xP8Fqv/u8JNQXHgWMaG/FzEeY5W8rmQkDRLRDdbYkvgGkXN8nnliTXHZgmftGnrh2prI
|
||||
ku8ziGxxymK56EldaBFlgt2K9RAXdiayYuIZmrjEQgVuGLNQAOk51rth7BRXpURaKyKlR2RDpFxh
|
||||
8g2mfgemkiPOwIqx9twYCxVVlbfOIsY+A5oJI6LjhOx7yDMznpnLcwvRWCpVt7FrAknjVsJtgphJ
|
||||
zTVjxi4lY0Ze+S+0wLUlEkpvkgg2kpBKWWgFLO1rcoylBrUiEsmbJ2TLiYSlpfuFRJeJ+RayZrXX
|
||||
aCoSQo2IaKq30v8G9WcsOpBK+hdcQOYfz45I85bqN3WdXl1mjSUPmAZ6fNrbhpLA5rgmwQpHpPtD
|
||||
7ld1Xd4+In2vYk6xSgyWEt5Grsfin8BbXBM+hUjK29hbHkvqzrHGBncE/DcktD9DxGpNJ4somQGT
|
||||
j6VeWJT0JULe8H2CW6z6jrBi0iVqNHwTyQ+aW+ztB5BY8oyR1n6k7Bq+fhhbYxMKmVx+n3AfisAH
|
||||
kneW+7r/fUQCb9cXSQmIvIa79PpW08N6nzWaEvHzSyATR+KyoOK/TdN9UBsiVaTKHZmy9Qa+K5Gg
|
||||
7UJBAzG+iCvZs2/deGh7+c+XTTs0XdyOETLZMkQdiNhGbC19zaPeJKkgkUurZ9U1kF1cWyIZc8yZ
|
||||
cyWEyl1ECmkNZ/SfATUl7Xg+kkHijDlvZPP9iEgp3ZZtK0+lKR7tqxU1RHIsMWPOK9mqVh7UqDV+
|
||||
MeCSqps+8cTI5v3D5kytUmsRK/NX0i4+5QwtZ+Fb6eofWCSsaZbTpo1vAzK6G8iqOvuw5jTAP958
|
||||
6hlr1fFmuS9FP/dhb6ND3xdx/RdgADBglifWgXLhAAAAAElFTkSuQmCC" transform="matrix(1 0 0 1 15 15)">
|
||||
</image>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="32" y1="21.5142" x2="32" y2="51.1873">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="0.9716" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<path class="st6" d="M22.9,51.9h18.2c1,0,1.8-0.8,1.8-1.8V22.7c0-1-0.8-1.8-1.8-1.8H22.9c-1,0-1.8,0.8-1.8,1.8v27.4
|
||||
C21.1,51.1,21.9,51.9,22.9,51.9z M39.8,49.7c-0.6,0-1.1-0.5-1.1-1.1c0-0.6,0.5-1.1,1.1-1.1c0.6,0,1.1,0.5,1.1,1.1
|
||||
C40.9,49.3,40.4,49.7,39.8,49.7z M39.8,23.4c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1c-0.6,0-1.1-0.5-1.1-1.1
|
||||
S39.2,23.4,39.8,23.4z M32,24.2c4.6,0,8.4,3.7,8.4,8.4s-3.7,8.4-8.4,8.4c-0.7,0-1.4-0.1-2.1-0.3l1.6-2.7
|
||||
c0.5-0.8-0.4-1.7-1.2-1.2l-3.6,2.1c0,0,0,0,0,0c-1.8-1.5-2.9-3.8-2.9-6.4C23.6,27.9,27.4,24.2,32,24.2z M24.4,23.4
|
||||
c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1s-1.1-0.5-1.1-1.1S23.8,23.4,24.4,23.4z M24.4,47.6c0.6,0,1.1,0.5,1.1,1.1
|
||||
c0,0.6-0.5,1.1-1.1,1.1s-1.1-0.5-1.1-1.1C23.3,48.1,23.8,47.6,24.4,47.6z"/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="31.9994" y1="32.4788" x2="32.0716" y2="36.9457">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="1" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<circle class="st7" cx="32" cy="32.5" r="2.2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="图层_1" 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#"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 64 64"
|
||||
style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#5E4AA6;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:1.000000e-03;fill:#1E5992;enable-background:new ;}
|
||||
.st3{fill:url(#SVGID_2_);}
|
||||
.st4{opacity:0.3;fill:url(#SVGID_3_);enable-background:new ;}
|
||||
.st5{fill:url(#SVGID_4_);}
|
||||
.st6{fill:url(#SVGID_5_);}
|
||||
.st7{fill:url(#SVGID_6_);}
|
||||
</style>
|
||||
<g>
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<g transform="translate(.000295 -.00032978)">
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
</g>
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
<g transform="translate(2.95e-4,-3.2978e-4)">
|
||||
<rect x="-1248.6" y="-1241.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1179.7" y="-1233.1" class="st0" width="0" height="0"/>
|
||||
<rect x="-1156.6" y="-1258.9" class="st0" width="0" height="0"/>
|
||||
<rect x="-1167.3" y="-1232.2" class="st0" width="0" height="0"/>
|
||||
<rect x="-1242.7" y="-1249" class="st0" width="0" height="0"/>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-363.3979" y1="913.4439" x2="-363.3979" y2="911.0629" gradientTransform="matrix(3.7796 0 0 -3.7796 1405.5416 3462.4551)">
|
||||
<stop offset="0" style="stop-color:#0272CB"/>
|
||||
<stop offset="1" style="stop-color:#0768BA"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st1" d="M4.6,8.5c-1.4,0-2.5,1.2-2.5,2.8v11.2
|
||||
c0,0.1,0,0.2,0,0.3v30c0,1.5,1.1,2.8,2.5,2.8h55c1.4,0,2.5-1.2,2.5-2.8V17.2c0-1.5-1.1-2.8-2.5-2.8v0h-31l-3.4-4.2
|
||||
c0,0-1.4-1.8-4-1.8h-5L4.6,8.5z"/>
|
||||
<path class="st2" d="M31.6,14.4c-0.4,0-1.2-0.1-2,0.4c-2.8,1.4-2.9,2.2-5.9,2.7H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1
|
||||
v1c0-0.8,0.3-1.5,0.9-2.1c0.5-0.5,1.3-0.9,2.1-0.9h18.7c3-0.5,3.1-1.3,5.9-2.7c0.8-0.4,1.5-0.4,2-0.4h27.9c0.7,0,1.3,0.3,1.8,0.8
|
||||
c0.5,0.5,0.7,1.2,0.7,1.9v-1c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8h-4.4H31.6z M2.1,22.4c0,0.1,0,0.2,0,0.3v1
|
||||
c0-0.1,0-0.2,0-0.3V22.4z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="95.1452" y1="43.801" x2="128.3352" y2="9.648" gradientTransform="matrix(1 0 0 -1 -75.9965 65.4973)">
|
||||
<stop offset="0" style="stop-color:#27AEE9"/>
|
||||
<stop offset="1" style="stop-color:#0669BC"/>
|
||||
</linearGradient>
|
||||
<path class="st3" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1v2
|
||||
c0,0.1,0,0.2,0,0.3v28c0,0.8,0.3,1.4,0.7,1.9c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8c0.5-0.5,0.7-1.2,0.7-1.9V18.2
|
||||
c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.3L28.5,15.5z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-389.233" y1="932.0934" x2="-373.3582" y2="932.0934" gradientTransform="matrix(3.7796 0 0 -3.7796 1473.188 3543.282)">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9c-0.5,0.5-0.8,1.3-0.9,2.1v1.5
|
||||
c0-0.8,0.3-1.5,0.9-2.1C3.5,20.3,4.2,20,5,20h18.7c0.1,0,0.3,0,0.4-0.1c2.9-1,4.9-3,4.9-3h30.5c0.7,0,1.3,0.3,1.8,0.8
|
||||
c0.5,0.5,0.7,1.2,0.7,1.9v-1.5c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.3H28.5z M2.1,23.4c0,0.1,0,0.2,0,0.3v1.5
|
||||
c0-0.1,0-0.2,0-0.3V23.4z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-389.2331" y1="923.2966" x2="-373.3582" y2="923.2966" gradientTransform="matrix(3.7796 0 0 -3.7796 1473.188 3543.2234)">
|
||||
<stop offset="0" style="stop-color:#0A5BA8;stop-opacity:0.9961"/>
|
||||
<stop offset="1" style="stop-color:#104A8C;stop-opacity:0.9961"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st5" d="M2,51.6v1.1c0,0.8,0.3,1.4,0.7,1.9
|
||||
c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8c0.5-0.5,0.7-1.2,0.7-1.9v-1.1c0,0.8-0.3,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.8,0.8
|
||||
h-55c-0.7,0-1.3-0.3-1.8-0.8S2,52.4,2,51.6z"/>
|
||||
<g>
|
||||
|
||||
<image style="overflow:visible;opacity:0.25;" width="34" height="44" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAsCAYAAAAATWqyAAAACXBIWXMAAAsSAAALEgHS3X78AAAA
|
||||
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA/JJREFUeNrMmFtv00AQhX2LyYUk
|
||||
pS0VIEA88P9/ES8IqZTShtI0JXHsmE31TXW6dRzb7UMtHSVO1rvHM2cuu0HwQq6wwX/hM61Vep97
|
||||
iYQgAqGgKwHDBpQ+IX9yWzx26IGE+y5kbMHCIXdYg0JI3V2JRypi8b7D0GHkMOC3uCORgsX/OSwc
|
||||
bh2W/HZvGZ9IDImJw7HDEd/7kGljFVtkzcLXDpcOF/yvbronotYYQeKLwyeHE4exwyvGBHWi84hu
|
||||
F1o5zB3OHX7weyEuuiOcePowIkeQ+OrwwWEKkdATnopORR7K2C2Rv1g2gNQNbsog88AiIffmmreQ
|
||||
+Ohw4JB6Ps+BEkmAairDooEQ6jPunnCVRnoIdIIlpnyPxd9m8gwy9lKpRN4rEX6JJSa7xJ9U5I9Y
|
||||
Jk1FpDmKv+LNrrlXIkN5gQPcbC63+SrTQbIjmemggtC7RfFnCO83vl4xbmuB17h0K/B3iH5oOtgx
|
||||
fyURX/m5xP8Fqv/u8JNQXHgWMaG/FzEeY5W8rmQkDRLRDdbYkvgGkXN8nnliTXHZgmftGnrh2prI
|
||||
ku8ziGxxymK56EldaBFlgt2K9RAXdiayYuIZmrjEQgVuGLNQAOk51rth7BRXpURaKyKlR2RDpFxh
|
||||
8g2mfgemkiPOwIqx9twYCxVVlbfOIsY+A5oJI6LjhOx7yDMznpnLcwvRWCpVt7FrAknjVsJtgphJ
|
||||
zTVjxi4lY0Ze+S+0wLUlEkpvkgg2kpBKWWgFLO1rcoylBrUiEsmbJ2TLiYSlpfuFRJeJ+RayZrXX
|
||||
aCoSQo2IaKq30v8G9WcsOpBK+hdcQOYfz45I85bqN3WdXl1mjSUPmAZ6fNrbhpLA5rgmwQpHpPtD
|
||||
7ld1Xd4+In2vYk6xSgyWEt5Grsfin8BbXBM+hUjK29hbHkvqzrHGBncE/DcktD9DxGpNJ4somQGT
|
||||
j6VeWJT0JULe8H2CW6z6jrBi0iVqNHwTyQ+aW+ztB5BY8oyR1n6k7Bq+fhhbYxMKmVx+n3AfisAH
|
||||
kneW+7r/fUQCb9cXSQmIvIa79PpW08N6nzWaEvHzSyATR+KyoOK/TdN9UBsiVaTKHZmy9Qa+K5Gg
|
||||
7UJBAzG+iCvZs2/deGh7+c+XTTs0XdyOETLZMkQdiNhGbC19zaPeJKkgkUurZ9U1kF1cWyIZc8yZ
|
||||
cyWEyl1ECmkNZ/SfATUl7Xg+kkHijDlvZPP9iEgp3ZZtK0+lKR7tqxU1RHIsMWPOK9mqVh7UqDV+
|
||||
MeCSqps+8cTI5v3D5kytUmsRK/NX0i4+5QwtZ+Fb6eofWCSsaZbTpo1vAzK6G8iqOvuw5jTAP958
|
||||
6hlr1fFmuS9FP/dhb6ND3xdx/RdgADBglifWgXLhAAAAAElFTkSuQmCC" transform="matrix(1 0 0 1 15 15)">
|
||||
</image>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="32" y1="21.5142" x2="32" y2="51.1873">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="0.9716" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<path class="st6" d="M22.9,51.9h18.2c1,0,1.8-0.8,1.8-1.8V22.7c0-1-0.8-1.8-1.8-1.8H22.9c-1,0-1.8,0.8-1.8,1.8v27.4
|
||||
C21.1,51.1,21.9,51.9,22.9,51.9z M39.8,49.7c-0.6,0-1.1-0.5-1.1-1.1c0-0.6,0.5-1.1,1.1-1.1c0.6,0,1.1,0.5,1.1,1.1
|
||||
C40.9,49.3,40.4,49.7,39.8,49.7z M39.8,23.4c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1c-0.6,0-1.1-0.5-1.1-1.1
|
||||
S39.2,23.4,39.8,23.4z M32,24.2c4.6,0,8.4,3.7,8.4,8.4s-3.7,8.4-8.4,8.4c-0.7,0-1.4-0.1-2.1-0.3l1.6-2.7
|
||||
c0.5-0.8-0.4-1.7-1.2-1.2l-3.6,2.1c0,0,0,0,0,0c-1.8-1.5-2.9-3.8-2.9-6.4C23.6,27.9,27.4,24.2,32,24.2z M24.4,23.4
|
||||
c0.6,0,1.1,0.5,1.1,1.1s-0.5,1.1-1.1,1.1s-1.1-0.5-1.1-1.1S23.8,23.4,24.4,23.4z M24.4,47.6c0.6,0,1.1,0.5,1.1,1.1
|
||||
c0,0.6-0.5,1.1-1.1,1.1s-1.1-0.5-1.1-1.1C23.3,48.1,23.8,47.6,24.4,47.6z"/>
|
||||
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="31.9994" y1="32.4788" x2="32.0716" y2="36.9457">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="1" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<circle class="st7" cx="32" cy="32.5" r="2.2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.1 KiB |
|
@ -1,113 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="图层_1" 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#"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 64 64"
|
||||
style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#5E4AA6;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:1.000000e-03;fill:#1E5992;enable-background:new ;}
|
||||
.st3{fill:url(#SVGID_2_);}
|
||||
.st4{opacity:0.3;fill:url(#SVGID_3_);enable-background:new ;}
|
||||
.st5{fill:url(#SVGID_4_);}
|
||||
.st6{fill:url(#SVGID_5_);}
|
||||
</style>
|
||||
<g>
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<g transform="translate(.000295 -.00032978)">
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
</g>
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
<g transform="translate(2.95e-4,-3.2978e-4)">
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-753.1828" y1="651.0814" x2="-753.1828" y2="653.4623" gradientTransform="matrix(3.7796 0 0 3.7796 2878.7295 -2450.8245)">
|
||||
<stop offset="0" style="stop-color:#0272CB"/>
|
||||
<stop offset="1" style="stop-color:#0768BA"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st1" d="M4.5,8.5C3.1,8.5,2,9.7,2,11.2v11.2
|
||||
c0,0.1,0,0.2,0,0.3v30c0,1.5,1.1,2.8,2.5,2.8h55c1.4,0,2.5-1.2,2.5-2.8V17.2c0-1.5-1.1-2.8-2.5-2.8l0,0h-31l-3.4-4.2
|
||||
c0,0-1.4-1.8-4-1.8h-5L4.5,8.5z"/>
|
||||
<path class="st2" d="M31.6,14.4c-0.4,0-1.2-0.1-2,0.4c-2.8,1.4-2.9,2.2-5.9,2.7H5c-0.8,0-1.6,0.3-2.1,0.9c-0.6,0.5-0.9,1.2-0.9,2v1
|
||||
c0-0.8,0.3-1.5,0.9-2.1c0.5-0.5,1.3-0.9,2.1-0.9h18.7c3-0.5,3.1-1.3,5.9-2.7c0.8-0.4,1.5-0.4,2-0.4h27.9c0.7,0,1.3,0.3,1.8,0.8
|
||||
S62,17.3,62,18v-1c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8h-4.4L31.6,14.4L31.6,14.4z M2,22.4c0,0.1,0,0.2,0,0.3v1
|
||||
c0-0.1,0-0.2,0-0.3V22.4z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="95.0853" y1="2392.217" x2="128.2754" y2="2426.3699" gradientTransform="matrix(1 0 0 1 -75.9965 -2370.5027)">
|
||||
<stop offset="0" style="stop-color:#27AEE9"/>
|
||||
<stop offset="1" style="stop-color:#0669BC"/>
|
||||
</linearGradient>
|
||||
<path class="st3" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9C2.4,20,2,20.7,2,21.5v2
|
||||
c0,0.1,0,0.2,0,0.3v28c0,0.8,0.3,1.4,0.7,1.9c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8s0.7-1.2,0.7-1.9V18.2
|
||||
c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.2L28.5,15.5z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-779.0179" y1="632.4208" x2="-763.1432" y2="632.4208" gradientTransform="matrix(3.7796 0 0 3.7796 2946.376 -2369.9976)">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9C2.4,20,2,20.7,2,21.5V23
|
||||
c0-0.8,0.3-1.5,0.9-2.1C3.4,20.3,4.2,20,5,20h18.7c0.1,0,0.3,0,0.4-0.1c2.9-1,4.9-3,4.9-3h30.5c0.7,0,1.3,0.3,1.8,0.8
|
||||
s0.7,1.2,0.7,1.9v-1.5c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.2h-2.7V15.5z M2,23.4c0,0.1,0,0.2,0,0.3v1.5
|
||||
c0-0.1,0-0.2,0-0.3V23.4z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-779.0179" y1="641.2203" x2="-763.1432" y2="641.2203" gradientTransform="matrix(3.7796 0 0 3.7796 2946.376 -2370.0562)">
|
||||
<stop offset="0" style="stop-color:#0A5BA8;stop-opacity:0.9961"/>
|
||||
<stop offset="1" style="stop-color:#104A8C;stop-opacity:0.9961"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st5" d="M2,51.6v1.1c0,0.8,0.3,1.4,0.7,1.9
|
||||
c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8s0.7-1.2,0.7-1.9v-1.1c0,0.8-0.3,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.8,0.8h-55
|
||||
c-0.7,0-1.3-0.3-1.8-0.8S2,52.4,2,51.6z"/>
|
||||
<g>
|
||||
|
||||
<image style="overflow:visible;opacity:0.25;" width="33" height="45" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAtCAYAAAAgJgIUAAAACXBIWXMAAAsSAAALEgHS3X78AAAA
|
||||
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABD9JREFUeNrMmAlv20YQhcXLoi6f
|
||||
cRzkQAv0//+m1i6ay67pIxYjiuR2CXwDvNCURSpOUgMPNKnl7tuZN8dyNPof/AXP/K77WSQCELbe
|
||||
bwjUXN2PJBGCyCMGIYuXoOK+7jtpNJBwMz7xmHgsPPY95tzHYpFB1ogGEAghMPU49HjhceZxAqFE
|
||||
XDLIEvFAK4zZ/SuPtx4vPVKPrx6X/B4IiXUfi8QDhNjsdOZx7PHG4w+ujWVyjwPGNbooRB9bXRMP
|
||||
cNseJBrzv/b4zeMdz3KssPJ48PiCddYSMd9FImRciitOscAbyMxYMIDArUcGkRUWedIacU9XmB4W
|
||||
uOOE6yHumOCCDJ188LiGVCEidbuSsKhIWXBBWE55ZmKcStgusFCKS0aSPx5ZJX4igYVCwBBjFYuA
|
||||
SsQXoBsjc4BWAq4rCD1KZtGGnVtSGjPpTHZ5zAK205DJl+jggf8riapENvcomUUdBGIWt4UPxcTm
|
||||
/5RdW4IqIJCLBiyxTZkvEsupa74hoVGwQHwvJSvuM1ncyh1OLOEgNxcBH7KhAIKFuMWpJnTSKRO8
|
||||
IzO+gFhFKFZMdA/MbWsINJY6Yt5m3A2bcvKORU3VFqbpYE4u+B2cSSK6Jg9Y/K8gNuI+lSjaw+RT
|
||||
rhlzp2LNUZclzB0HuOItCWmMv1PI3kiErEWcY+Yzizp2a+GctPqQ5uriDaU6FVEecb9k5xYBgSxi
|
||||
FlFdpTKm7hJkWxObOqdQmhfLEboTs8QaclY1E8ZGPDct5KIF15WsnEy64oVcdlgIylbJrhlXSNKy
|
||||
zTQ6+uTxGTcupbB9Q8KSRykmz5hgn+e5KHvFu04WM1IrFgp5ryHwj8dHSOTt6hq1UrUmLEtGewzO
|
||||
iYwv7DhBwBYJIxmfYPJm/HuPvyByKe/XmzKmamEPWEjV4oqQfHCMpSwrTiSBPeCCc48LLHErucZt
|
||||
6zG1ek5YIBELWaN7KnXExFiy2yt2f0Fpz7r00KfRNdckYpVZK3zn/G7izFj0AqgbVl2d1iYSrker
|
||||
f8DVMmNj/n9Z9BwYgfsuN/SxhGvV/Uiq6xwyE+kXrhDhnyLE5tkdv5eb+s34icULdqcnrrG4opax
|
||||
X1nsipC8JLy3EniqvXNSLR+EwJzyfMpVBWaJroBUu5Ma3Og6qYwFu1lK/ahFtBFuURdZoep1Uo+3
|
||||
aGLUKj6VRE0kYTsVsWoCi/ocuoccAwMJ16QVujUkjiRsUzm1V9vywNDPCO2GNRDNpNJ/xh3fMHa2
|
||||
hBOhrhGd6SNnjJXzcpcPJX1JlCx+TxheYvIQ/5eEZCZhud6UnIaScC0St+SBfUlSM37P+tSJXS1R
|
||||
Sz+RIcYRteCzNLJ3EPgbqyy3Jamh0WHNyr1o4IbUPGaRJc+upXkp+7gjGBAZejqbyElMT2G5CFaz
|
||||
5bN9vetqfjUzVhIhg6Jk6CdEPbG3v2Vq1R0Uos/9RXfnr7q//O8/AQYAxhWve3m9fqQAAAAASUVO
|
||||
RK5CYII=" transform="matrix(1 0 0 1 16 15)">
|
||||
</image>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="32.3842" y1="22.1772" x2="32.3842" y2="51.1664">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="0.9716" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<path class="st6" d="M28.6,34.1c0-1.7-1.4-3.2-3.1-3.2c-1.8,0-3.3,1.4-3.3,3.2c0,1.4,0.9,2.6,2.2,3v1.2c0,0.7,0.4,1.5,1,1.9
|
||||
l6.2,4.7c-1.6,0.5-2.7,1.9-2.7,3.6c0,2.1,1.7,3.8,3.8,3.8s3.8-1.7,3.8-3.8c0-1.7-1.2-3.2-2.8-3.7v-1.8l5.7-3.9c0.6-0.4,1-1.2,1-2
|
||||
v-1.7h0.6c0.9,0,1.7-0.8,1.7-1.7V31c0-0.9-0.8-1.7-1.7-1.7h-3.3c-0.9,0-1.7,0.8-1.7,1.7v2.8c0,0.9,0.8,1.7,1.7,1.7h0.6v1.9
|
||||
l-4.7,3.3V28.2h1.7c1.2,0,1.9-1.3,1.3-2.3L34,21.7c-0.7-1.1-2.2-1.1-2.9,0l-2.6,4.2c-0.6,1,0.1,2.3,1.3,2.3h1.8v14.3l-5.2-3.9
|
||||
v-1.4C27.6,36.7,28.6,35.5,28.6,34.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="图层_1" 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#"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 64 64"
|
||||
style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#5E4AA6;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:1.000000e-03;fill:#1E5992;enable-background:new ;}
|
||||
.st3{fill:url(#SVGID_2_);}
|
||||
.st4{opacity:0.3;fill:url(#SVGID_3_);enable-background:new ;}
|
||||
.st5{fill:url(#SVGID_4_);}
|
||||
.st6{fill:url(#SVGID_5_);}
|
||||
</style>
|
||||
<g>
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<g transform="translate(.000295 -.00032978)">
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
</g>
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
<g transform="translate(2.95e-4,-3.2978e-4)">
|
||||
<polygon class="st0" points="-1248.6,-1241.1 -1248.6,-1241.1 -1248.6,-1241.1 "/>
|
||||
<polygon class="st0" points="-1179.7,-1233.1 -1179.7,-1233.1 -1179.7,-1233.1 "/>
|
||||
<polygon class="st0" points="-1156.6,-1258.9 -1156.6,-1258.9 -1156.6,-1258.9 "/>
|
||||
<polygon class="st0" points="-1167.3,-1232.2 -1167.3,-1232.2 -1167.3,-1232.2 "/>
|
||||
<polygon class="st0" points="-1242.7,-1249 -1242.7,-1249 -1242.7,-1249 "/>
|
||||
</g>
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-753.1828" y1="651.0814" x2="-753.1828" y2="653.4623" gradientTransform="matrix(3.7796 0 0 3.7796 2878.7295 -2450.8245)">
|
||||
<stop offset="0" style="stop-color:#0272CB"/>
|
||||
<stop offset="1" style="stop-color:#0768BA"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st1" d="M4.5,8.5C3.1,8.5,2,9.7,2,11.2v11.2
|
||||
c0,0.1,0,0.2,0,0.3v30c0,1.5,1.1,2.8,2.5,2.8h55c1.4,0,2.5-1.2,2.5-2.8V17.2c0-1.5-1.1-2.8-2.5-2.8l0,0h-31l-3.4-4.2
|
||||
c0,0-1.4-1.8-4-1.8h-5L4.5,8.5z"/>
|
||||
<path class="st2" d="M31.6,14.4c-0.4,0-1.2-0.1-2,0.4c-2.8,1.4-2.9,2.2-5.9,2.7H5c-0.8,0-1.6,0.3-2.1,0.9c-0.6,0.5-0.9,1.2-0.9,2v1
|
||||
c0-0.8,0.3-1.5,0.9-2.1c0.5-0.5,1.3-0.9,2.1-0.9h18.7c3-0.5,3.1-1.3,5.9-2.7c0.8-0.4,1.5-0.4,2-0.4h27.9c0.7,0,1.3,0.3,1.8,0.8
|
||||
S62,17.3,62,18v-1c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8h-4.4L31.6,14.4L31.6,14.4z M2,22.4c0,0.1,0,0.2,0,0.3v1
|
||||
c0-0.1,0-0.2,0-0.3V22.4z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="95.0853" y1="2392.217" x2="128.2754" y2="2426.3699" gradientTransform="matrix(1 0 0 1 -75.9965 -2370.5027)">
|
||||
<stop offset="0" style="stop-color:#27AEE9"/>
|
||||
<stop offset="1" style="stop-color:#0669BC"/>
|
||||
</linearGradient>
|
||||
<path class="st3" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9C2.4,20,2,20.7,2,21.5v2
|
||||
c0,0.1,0,0.2,0,0.3v28c0,0.8,0.3,1.4,0.7,1.9c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8s0.7-1.2,0.7-1.9V18.2
|
||||
c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.2L28.5,15.5z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-779.0179" y1="632.4208" x2="-763.1432" y2="632.4208" gradientTransform="matrix(3.7796 0 0 3.7796 2946.376 -2369.9976)">
|
||||
<stop offset="0" style="stop-color:#FFFFFF"/>
|
||||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M28.5,15.5c0,0-1.4,1.8-4.4,3c-0.1,0-0.2,0-0.4,0.1H5c-0.8,0-1.6,0.3-2.1,0.9C2.4,20,2,20.7,2,21.5V23
|
||||
c0-0.8,0.3-1.5,0.9-2.1C3.4,20.3,4.2,20,5,20h18.7c0.1,0,0.3,0,0.4-0.1c2.9-1,4.9-3,4.9-3h30.5c0.7,0,1.3,0.3,1.8,0.8
|
||||
s0.7,1.2,0.7,1.9v-1.5c0-0.8-0.3-1.4-0.7-1.9c-0.5-0.5-1.1-0.8-1.8-0.8H31.2h-2.7V15.5z M2,23.4c0,0.1,0,0.2,0,0.3v1.5
|
||||
c0-0.1,0-0.2,0-0.3V23.4z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-779.0179" y1="641.2203" x2="-763.1432" y2="641.2203" gradientTransform="matrix(3.7796 0 0 3.7796 2946.376 -2370.0562)">
|
||||
<stop offset="0" style="stop-color:#0A5BA8;stop-opacity:0.9961"/>
|
||||
<stop offset="1" style="stop-color:#104A8C;stop-opacity:0.9961"/>
|
||||
</linearGradient>
|
||||
<path image-rendering="auto" shape-rendering="auto" color-rendering="auto" class="st5" d="M2,51.6v1.1c0,0.8,0.3,1.4,0.7,1.9
|
||||
c0.5,0.5,1.1,0.8,1.8,0.8h55c0.7,0,1.3-0.3,1.8-0.8s0.7-1.2,0.7-1.9v-1.1c0,0.8-0.3,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.8,0.8h-55
|
||||
c-0.7,0-1.3-0.3-1.8-0.8S2,52.4,2,51.6z"/>
|
||||
<g>
|
||||
|
||||
<image style="overflow:visible;opacity:0.25;" width="33" height="45" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAtCAYAAAAgJgIUAAAACXBIWXMAAAsSAAALEgHS3X78AAAA
|
||||
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABD9JREFUeNrMmAlv20YQhcXLoi6f
|
||||
cRzkQAv0//+m1i6ay67pIxYjiuR2CXwDvNCURSpOUgMPNKnl7tuZN8dyNPof/AXP/K77WSQCELbe
|
||||
bwjUXN2PJBGCyCMGIYuXoOK+7jtpNJBwMz7xmHgsPPY95tzHYpFB1ogGEAghMPU49HjhceZxAqFE
|
||||
XDLIEvFAK4zZ/SuPtx4vPVKPrx6X/B4IiXUfi8QDhNjsdOZx7PHG4w+ujWVyjwPGNbooRB9bXRMP
|
||||
cNseJBrzv/b4zeMdz3KssPJ48PiCddYSMd9FImRciitOscAbyMxYMIDArUcGkRUWedIacU9XmB4W
|
||||
uOOE6yHumOCCDJ188LiGVCEidbuSsKhIWXBBWE55ZmKcStgusFCKS0aSPx5ZJX4igYVCwBBjFYuA
|
||||
SsQXoBsjc4BWAq4rCD1KZtGGnVtSGjPpTHZ5zAK205DJl+jggf8riapENvcomUUdBGIWt4UPxcTm
|
||||
/5RdW4IqIJCLBiyxTZkvEsupa74hoVGwQHwvJSvuM1ncyh1OLOEgNxcBH7KhAIKFuMWpJnTSKRO8
|
||||
IzO+gFhFKFZMdA/MbWsINJY6Yt5m3A2bcvKORU3VFqbpYE4u+B2cSSK6Jg9Y/K8gNuI+lSjaw+RT
|
||||
rhlzp2LNUZclzB0HuOItCWmMv1PI3kiErEWcY+Yzizp2a+GctPqQ5uriDaU6FVEecb9k5xYBgSxi
|
||||
FlFdpTKm7hJkWxObOqdQmhfLEboTs8QaclY1E8ZGPDct5KIF15WsnEy64oVcdlgIylbJrhlXSNKy
|
||||
zTQ6+uTxGTcupbB9Q8KSRykmz5hgn+e5KHvFu04WM1IrFgp5ryHwj8dHSOTt6hq1UrUmLEtGewzO
|
||||
iYwv7DhBwBYJIxmfYPJm/HuPvyByKe/XmzKmamEPWEjV4oqQfHCMpSwrTiSBPeCCc48LLHErucZt
|
||||
6zG1ek5YIBELWaN7KnXExFiy2yt2f0Fpz7r00KfRNdckYpVZK3zn/G7izFj0AqgbVl2d1iYSrker
|
||||
f8DVMmNj/n9Z9BwYgfsuN/SxhGvV/Uiq6xwyE+kXrhDhnyLE5tkdv5eb+s34icULdqcnrrG4opax
|
||||
X1nsipC8JLy3EniqvXNSLR+EwJzyfMpVBWaJroBUu5Ma3Og6qYwFu1lK/ahFtBFuURdZoep1Uo+3
|
||||
aGLUKj6VRE0kYTsVsWoCi/ocuoccAwMJ16QVujUkjiRsUzm1V9vywNDPCO2GNRDNpNJ/xh3fMHa2
|
||||
hBOhrhGd6SNnjJXzcpcPJX1JlCx+TxheYvIQ/5eEZCZhud6UnIaScC0St+SBfUlSM37P+tSJXS1R
|
||||
Sz+RIcYRteCzNLJ3EPgbqyy3Jamh0WHNyr1o4IbUPGaRJc+upXkp+7gjGBAZejqbyElMT2G5CFaz
|
||||
5bN9vetqfjUzVhIhg6Jk6CdEPbG3v2Vq1R0Uos/9RXfnr7q//O8/AQYAxhWve3m9fqQAAAAASUVO
|
||||
RK5CYII=" transform="matrix(1 0 0 1 16 15)">
|
||||
</image>
|
||||
<g>
|
||||
<g>
|
||||
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="32.3842" y1="22.1772" x2="32.3842" y2="51.1664">
|
||||
<stop offset="0" style="stop-color:#FBFDFE"/>
|
||||
<stop offset="0.9716" style="stop-color:#C6E8F5"/>
|
||||
</linearGradient>
|
||||
<path class="st6" d="M28.6,34.1c0-1.7-1.4-3.2-3.1-3.2c-1.8,0-3.3,1.4-3.3,3.2c0,1.4,0.9,2.6,2.2,3v1.2c0,0.7,0.4,1.5,1,1.9
|
||||
l6.2,4.7c-1.6,0.5-2.7,1.9-2.7,3.6c0,2.1,1.7,3.8,3.8,3.8s3.8-1.7,3.8-3.8c0-1.7-1.2-3.2-2.8-3.7v-1.8l5.7-3.9c0.6-0.4,1-1.2,1-2
|
||||
v-1.7h0.6c0.9,0,1.7-0.8,1.7-1.7V31c0-0.9-0.8-1.7-1.7-1.7h-3.3c-0.9,0-1.7,0.8-1.7,1.7v2.8c0,0.9,0.8,1.7,1.7,1.7h0.6v1.9
|
||||
l-4.7,3.3V28.2h1.7c1.2,0,1.9-1.3,1.3-2.3L34,21.7c-0.7-1.1-2.2-1.1-2.9,0l-2.6,4.2c-0.6,1,0.1,2.3,1.3,2.3h1.8v14.3l-5.2-3.9
|
||||
v-1.4C27.6,36.7,28.6,35.5,28.6,34.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.9 KiB |
BIN
web/img/gradient.6c5a7f30.png
Normal file
After Width: | Height: | Size: 11 KiB |
|
@ -1,25 +1,25 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M875 1894 c-11 -2 -51 -11 -88 -20 -341 -78 -610 -364 -673 -714 -82
|
||||
-459 197 -902 647 -1030 94 -27 277 -37 378 -21 303 47 575 261 690 540 55
|
||||
133 66 192 65 361 -1 136 -4 165 -27 235 -36 116 -62 170 -123 261 -123 186
|
||||
-347 336 -566 379 -42 8 -276 15 -303 9z m250 -168 c11 -2 42 -9 70 -16 131
|
||||
-30 288 -135 387 -260 160 -201 198 -506 93 -745 l-22 -50 2 80 c3 180 -64
|
||||
351 -184 476 -209 216 -544 260 -807 105 -201 -117 -326 -347 -319 -587 l2
|
||||
-74 -19 44 c-63 140 -80 332 -44 476 24 94 87 219 147 292 109 133 290 238
|
||||
448 259 25 3 47 7 49 9 5 4 173 -3 197 -9z m8 -501 c33 -8 85 -31 116 -50 227
|
||||
-137 305 -418 183 -651 l-21 -39 -1 35 c-9 251 -245 439 -490 389 -186 -38
|
||||
-323 -200 -330 -389 l-1 -35 -23 45 c-101 194 -61 429 99 578 130 122 292 162
|
||||
468 117z m-27 -499 c182 -85 183 -345 1 -438 -53 -27 -161 -26 -215 1 -146 75
|
||||
-180 267 -69 390 63 69 190 90 283 47z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M875 1894 c-11 -2 -51 -11 -88 -20 -341 -78 -610 -364 -673 -714 -82
|
||||
-459 197 -902 647 -1030 94 -27 277 -37 378 -21 303 47 575 261 690 540 55
|
||||
133 66 192 65 361 -1 136 -4 165 -27 235 -36 116 -62 170 -123 261 -123 186
|
||||
-347 336 -566 379 -42 8 -276 15 -303 9z m250 -168 c11 -2 42 -9 70 -16 131
|
||||
-30 288 -135 387 -260 160 -201 198 -506 93 -745 l-22 -50 2 80 c3 180 -64
|
||||
351 -184 476 -209 216 -544 260 -807 105 -201 -117 -326 -347 -319 -587 l2
|
||||
-74 -19 44 c-63 140 -80 332 -44 476 24 94 87 219 147 292 109 133 290 238
|
||||
448 259 25 3 47 7 49 9 5 4 173 -3 197 -9z m8 -501 c33 -8 85 -31 116 -50 227
|
||||
-137 305 -418 183 -651 l-21 -39 -1 35 c-9 251 -245 439 -490 389 -186 -38
|
||||
-323 -200 -330 -389 l-1 -35 -23 45 c-101 194 -61 429 99 578 130 122 292 162
|
||||
468 117z m-27 -499 c182 -85 183 -345 1 -438 -53 -27 -161 -26 -215 1 -146 75
|
||||
-180 267 -69 390 63 69 190 90 283 47z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -1,159 +1,159 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 407 407"
|
||||
style="enable-background:new 0 0 407 407;"
|
||||
xml:space="preserve"><metadata
|
||||
id="metadata36"><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></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs34"><linearGradient
|
||||
xlink:href="#SVGID_1_"
|
||||
id="linearGradient46"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
x1="203.7169"
|
||||
y1="7.7039"
|
||||
x2="203.7169"
|
||||
y2="402.0255" /><linearGradient
|
||||
xlink:href="#SVGID_1_"
|
||||
id="linearGradient48"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
x1="203.7169"
|
||||
y1="7.7039"
|
||||
x2="203.7169"
|
||||
y2="402.0255" />
|
||||
|
||||
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient120"><stop
|
||||
id="stop6-9"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" /><stop
|
||||
id="stop8-1"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" /><stop
|
||||
id="stop10-7"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" /></linearGradient><filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1002"
|
||||
x="-0.013201674"
|
||||
width="1.0264033"
|
||||
y="-0.013198327"
|
||||
height="1.0263967"><feGaussianBlur
|
||||
stdDeviation="2.168925"
|
||||
id="feGaussianBlur1004" /></filter></defs>
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:#515151;}
|
||||
</style>
|
||||
<g
|
||||
transform="matrix(1,0,0,0.98477354,0,6.0829719)"
|
||||
id="g15-0"
|
||||
style="fill:#4d4d4d;filter:url(#filter1002)"><linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient91"><stop
|
||||
id="stop85"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" /><stop
|
||||
id="stop87"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" /><stop
|
||||
id="stop89"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" /></linearGradient><path
|
||||
style="fill:#4d4d4d"
|
||||
id="path13-7"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
class="st0" /><path
|
||||
style="fill:#4d4d4d"
|
||||
class="st0"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
id="path40-7" /></g><g
|
||||
id="g15">
|
||||
|
||||
|
||||
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="SVGID_1_">
|
||||
<stop
|
||||
id="stop6"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop8"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" />
|
||||
<stop
|
||||
id="stop10"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="fill:url(#linearGradient46)"
|
||||
id="path13"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
class="st0" />
|
||||
<path
|
||||
style="fill:url(#linearGradient48)"
|
||||
class="st0"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
id="path40" /></g><g
|
||||
id="g27">
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path17"
|
||||
d="m 223.7,137.8 h 0.2 v 6.9 h 7.9 v -28.5 c 0,-2.1 -0.4,-3.9 -1.2,-5.6 -0.8,-1.7 -1.9,-3.1 -3.4,-4.3 -1.5,-1.2 -3.2,-2.1 -5.3,-2.7 -2.1,-0.6 -4.3,-1 -6.9,-1 -2.3,0 -4.5,0.3 -6.5,1 -2,0.6 -3.7,1.5 -5.2,2.7 -1.5,1.2 -2.6,2.5 -3.5,4.1 -0.9,1.6 -1.3,3.3 -1.4,5.1 h 7.8 c 0.2,-0.9 0.5,-1.7 1,-2.4 0.5,-0.7 1.1,-1.4 1.8,-1.9 0.7,-0.5 1.6,-0.9 2.6,-1.2 1,-0.3 2,-0.4 3.1,-0.4 2.8,0 4.9,0.6 6.5,1.9 1.5,1.2 2.3,3.1 2.3,5.5 v 3.2 l -11.2,0.6 c -5.2,0.3 -9.1,1.5 -11.8,3.6 -2.7,2.1 -4.1,4.9 -4.1,8.6 0,1.9 0.3,3.6 1,5.1 0.7,1.5 1.7,2.8 2.9,3.9 1.2,1.1 2.7,1.9 4.4,2.5 1.7,0.6 3.6,0.9 5.7,0.9 1.4,0 2.8,-0.2 4.1,-0.5 1.3,-0.3 2.6,-0.8 3.7,-1.5 1.1,-0.6 2.1,-1.4 3.1,-2.3 1,-1.2 1.8,-2.2 2.4,-3.3 z m -3.2,-2 c -1,0.8 -2.1,1.5 -3.4,2 -1.3,0.5 -2.8,0.7 -4.3,0.7 -2.4,0 -4.3,-0.5 -5.7,-1.6 -1.4,-1.1 -2.1,-2.5 -2.1,-4.3 0,-1.8 0.7,-3.3 2.2,-4.3 1.4,-1 3.6,-1.6 6.5,-1.8 l 10.1,-0.7 v 3.2 c 0,1.4 -0.3,2.6 -0.8,3.8 -0.8,1.2 -1.5,2.2 -2.5,3 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path19"
|
||||
d="m 278.5,228.7 -13.7,-3.4 c -16.7,-4.2 -23.6,-9.7 -23.6,-18.9 0,-11.7 10.9,-19.8 26.7,-19.8 15.8,0 26.5,8 27.7,21 h 17.9 c -0.7,-21.6 -19,-36.7 -45.2,-36.7 -26.8,0 -45.7,15 -45.7,36.5 0,17.5 10.6,28.2 34.1,34 l 16.3,4 c 16.7,4.2 23.9,10.4 23.9,20.6 0,11.8 -11.9,20.4 -28.4,20.4 -17.2,0 -29.8,-8.6 -31.2,-21.7 h -18 c 1.3,22.8 20.2,37.3 47.9,37.3 29.7,0 48.4,-14.7 48.4,-38.3 -0.3,-18.4 -11,-28.7 -37.1,-35 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path21"
|
||||
d="m 187.7,144.7 v -28.3 c 0,-2.1 -0.3,-4 -1,-5.6 -0.7,-1.6 -1.5,-3.1 -2.7,-4.3 -1.2,-1.2 -2.6,-2.1 -4.3,-2.8 -1.7,-0.7 -3.5,-1 -5.6,-1 -1.5,0 -2.9,0.2 -4.2,0.6 -1.3,0.4 -2.6,0.9 -3.7,1.6 -1.1,0.7 -2.1,1.6 -3,2.5 -0.9,0.9 -1.6,2.1 -2.1,3.4 h -0.2 c -0.8,-2.6 -2.3,-4.6 -4.3,-6 -2,-1.4 -4.5,-2.1 -7.4,-2.1 -1.3,0 -2.6,0.2 -3.9,0.5 -1.2,0.3 -2.3,0.8 -3.4,1.5 -1,0.7 -1.9,1.4 -2.7,2.4 -0.8,0.9 -1.4,2 -1.9,3.1 h -0.2 v -7 h -7.9 v 41.6 h 7.8 v -25.5 c 0,-1.3 0.7,-2.6 1.1,-3.7 0.4,-1.1 1,-2.1 1.8,-3 0.8,-0.8 1.7,-1.5 2.8,-2 1.1,-0.5 2.3,-0.7 3.5,-0.7 1.2,0 2.3,0.2 3.3,0.6 1,0.4 1.8,0.9 2.5,1.6 0.7,0.7 1.2,1.5 1.6,2.5 0.4,1 0.6,2.1 0.6,3.2 v 27 h 8.2 V 119 c 0,-1.3 0.2,-2.6 0.7,-3.7 0.4,-1.1 1,-2.1 1.8,-2.9 0.8,-0.8 1.7,-1.4 2.7,-1.9 1.1,-0.4 2.2,-0.7 3.5,-0.7 2.6,0 4.6,0.8 6,2.2 1.4,1.5 2.1,3.6 2.1,6.3 v 26.3 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path23"
|
||||
d="m 147.4,170.9 c -36.3,0 -59.1,25.3 -59.1,65.6 0,40.3 22.8,65.6 59.1,65.6 36.3,0 59.1,-25.3 59.1,-65.6 -0.1,-40.3 -22.8,-65.6 -59.1,-65.6 z m 0,115 c -24.9,0 -40.5,-19.1 -40.5,-49.4 0,-30.4 15.6,-49.5 40.5,-49.5 24.8,0 40.5,19.1 40.5,49.5 -0.1,30.3 -15.7,49.4 -40.5,49.4 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path25"
|
||||
d="m 252.1,113.5 c 1,-1.2 2.1,-2.2 3.5,-2.9 1.4,-0.7 2.9,-1 4.6,-1 1.4,0 2.7,0.2 3.8,0.6 1.1,0.4 2.1,0.9 3,1.6 0.8,0.7 1.5,1.5 2,2.5 0.5,1 0.9,2 1.1,3.1 h 7.9 c -0.2,-2 -0.7,-3.9 -1.6,-5.7 -0.9,-1.8 -2.1,-3.3 -3.6,-4.7 -1.5,-1.3 -3.4,-2.4 -5.5,-3.2 -2.1,-0.8 -4.5,-1.2 -7.2,-1.2 -2.9,0 -5.6,0.5 -8,1.5 -2.4,1 -4.4,2.4 -6.1,4.3 -1.7,1.9 -3,4.1 -3.9,6.7 -0.9,2.6 -1.4,5.5 -1.4,8.8 0,3.3 0.5,6.3 1.4,8.9 0.9,2.6 2.3,4.9 4,6.7 1.7,1.8 3.8,3.2 6.2,4.2 2.4,1 5.1,1.5 8,1.5 2.5,0 4.8,-0.4 6.9,-1 2.1,-0.6 3.9,-1.7 5.5,-2.9 1.5,-1.3 2.8,-2.8 3.8,-4.6 1,-1.8 1.6,-3.8 1.8,-5.9 h -7.9 c -0.5,2.5 -1.6,4.3 -3.3,5.6 -1.7,1.3 -3.9,1.9 -6.6,1.9 -1.7,0 -3.2,-0.3 -4.6,-1 -1.4,-0.6 -2.6,-1.6 -3.5,-2.8 -1,-1.2 -1.7,-2.7 -2.3,-4.5 -0.5,-1.8 -0.8,-3.8 -0.8,-6 0,-2.2 0.3,-4.1 0.8,-5.9 0.3,-1.9 1,-3.4 2,-4.6 z"
|
||||
class="st1" />
|
||||
</g>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 407 407"
|
||||
style="enable-background:new 0 0 407 407;"
|
||||
xml:space="preserve"><metadata
|
||||
id="metadata36"><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></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs34"><linearGradient
|
||||
xlink:href="#SVGID_1_"
|
||||
id="linearGradient46"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
x1="203.7169"
|
||||
y1="7.7039"
|
||||
x2="203.7169"
|
||||
y2="402.0255" /><linearGradient
|
||||
xlink:href="#SVGID_1_"
|
||||
id="linearGradient48"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
x1="203.7169"
|
||||
y1="7.7039"
|
||||
x2="203.7169"
|
||||
y2="402.0255" />
|
||||
|
||||
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient120"><stop
|
||||
id="stop6-9"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" /><stop
|
||||
id="stop8-1"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" /><stop
|
||||
id="stop10-7"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" /></linearGradient><filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1002"
|
||||
x="-0.013201674"
|
||||
width="1.0264033"
|
||||
y="-0.013198327"
|
||||
height="1.0263967"><feGaussianBlur
|
||||
stdDeviation="2.168925"
|
||||
id="feGaussianBlur1004" /></filter></defs>
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:#515151;}
|
||||
</style>
|
||||
<g
|
||||
transform="matrix(1,0,0,0.98477354,0,6.0829719)"
|
||||
id="g15-0"
|
||||
style="fill:#4d4d4d;filter:url(#filter1002)"><linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient91"><stop
|
||||
id="stop85"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" /><stop
|
||||
id="stop87"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" /><stop
|
||||
id="stop89"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" /></linearGradient><path
|
||||
style="fill:#4d4d4d"
|
||||
id="path13-7"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
class="st0" /><path
|
||||
style="fill:#4d4d4d"
|
||||
class="st0"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
id="path40-7" /></g><g
|
||||
id="g15">
|
||||
|
||||
|
||||
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1,0,0,-1,0,407.2074)"
|
||||
y2="402.02551"
|
||||
x2="203.7169"
|
||||
y1="7.7038999"
|
||||
x1="203.7169"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="SVGID_1_">
|
||||
<stop
|
||||
id="stop6"
|
||||
style="stop-color:#F2F2F2"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop8"
|
||||
style="stop-color:#F7F7F7"
|
||||
offset="0.5963" />
|
||||
<stop
|
||||
id="stop10"
|
||||
style="stop-color:#FEFEFE"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="fill:url(#linearGradient46)"
|
||||
id="path13"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
class="st0" />
|
||||
<path
|
||||
style="fill:url(#linearGradient48)"
|
||||
class="st0"
|
||||
d="M 400.9,202.3 C 400.9,92.3 313.8,5.1 203.7,5.1 93.7,5.2 6.6,92.3 6.6,202.3 c 0,110 87.1,197.2 197.2,197.2 110.1,0 197.1,-87.1 197.1,-197.2 z"
|
||||
id="path40" /></g><g
|
||||
id="g27">
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path17"
|
||||
d="m 223.7,137.8 h 0.2 v 6.9 h 7.9 v -28.5 c 0,-2.1 -0.4,-3.9 -1.2,-5.6 -0.8,-1.7 -1.9,-3.1 -3.4,-4.3 -1.5,-1.2 -3.2,-2.1 -5.3,-2.7 -2.1,-0.6 -4.3,-1 -6.9,-1 -2.3,0 -4.5,0.3 -6.5,1 -2,0.6 -3.7,1.5 -5.2,2.7 -1.5,1.2 -2.6,2.5 -3.5,4.1 -0.9,1.6 -1.3,3.3 -1.4,5.1 h 7.8 c 0.2,-0.9 0.5,-1.7 1,-2.4 0.5,-0.7 1.1,-1.4 1.8,-1.9 0.7,-0.5 1.6,-0.9 2.6,-1.2 1,-0.3 2,-0.4 3.1,-0.4 2.8,0 4.9,0.6 6.5,1.9 1.5,1.2 2.3,3.1 2.3,5.5 v 3.2 l -11.2,0.6 c -5.2,0.3 -9.1,1.5 -11.8,3.6 -2.7,2.1 -4.1,4.9 -4.1,8.6 0,1.9 0.3,3.6 1,5.1 0.7,1.5 1.7,2.8 2.9,3.9 1.2,1.1 2.7,1.9 4.4,2.5 1.7,0.6 3.6,0.9 5.7,0.9 1.4,0 2.8,-0.2 4.1,-0.5 1.3,-0.3 2.6,-0.8 3.7,-1.5 1.1,-0.6 2.1,-1.4 3.1,-2.3 1,-1.2 1.8,-2.2 2.4,-3.3 z m -3.2,-2 c -1,0.8 -2.1,1.5 -3.4,2 -1.3,0.5 -2.8,0.7 -4.3,0.7 -2.4,0 -4.3,-0.5 -5.7,-1.6 -1.4,-1.1 -2.1,-2.5 -2.1,-4.3 0,-1.8 0.7,-3.3 2.2,-4.3 1.4,-1 3.6,-1.6 6.5,-1.8 l 10.1,-0.7 v 3.2 c 0,1.4 -0.3,2.6 -0.8,3.8 -0.8,1.2 -1.5,2.2 -2.5,3 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path19"
|
||||
d="m 278.5,228.7 -13.7,-3.4 c -16.7,-4.2 -23.6,-9.7 -23.6,-18.9 0,-11.7 10.9,-19.8 26.7,-19.8 15.8,0 26.5,8 27.7,21 h 17.9 c -0.7,-21.6 -19,-36.7 -45.2,-36.7 -26.8,0 -45.7,15 -45.7,36.5 0,17.5 10.6,28.2 34.1,34 l 16.3,4 c 16.7,4.2 23.9,10.4 23.9,20.6 0,11.8 -11.9,20.4 -28.4,20.4 -17.2,0 -29.8,-8.6 -31.2,-21.7 h -18 c 1.3,22.8 20.2,37.3 47.9,37.3 29.7,0 48.4,-14.7 48.4,-38.3 -0.3,-18.4 -11,-28.7 -37.1,-35 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path21"
|
||||
d="m 187.7,144.7 v -28.3 c 0,-2.1 -0.3,-4 -1,-5.6 -0.7,-1.6 -1.5,-3.1 -2.7,-4.3 -1.2,-1.2 -2.6,-2.1 -4.3,-2.8 -1.7,-0.7 -3.5,-1 -5.6,-1 -1.5,0 -2.9,0.2 -4.2,0.6 -1.3,0.4 -2.6,0.9 -3.7,1.6 -1.1,0.7 -2.1,1.6 -3,2.5 -0.9,0.9 -1.6,2.1 -2.1,3.4 h -0.2 c -0.8,-2.6 -2.3,-4.6 -4.3,-6 -2,-1.4 -4.5,-2.1 -7.4,-2.1 -1.3,0 -2.6,0.2 -3.9,0.5 -1.2,0.3 -2.3,0.8 -3.4,1.5 -1,0.7 -1.9,1.4 -2.7,2.4 -0.8,0.9 -1.4,2 -1.9,3.1 h -0.2 v -7 h -7.9 v 41.6 h 7.8 v -25.5 c 0,-1.3 0.7,-2.6 1.1,-3.7 0.4,-1.1 1,-2.1 1.8,-3 0.8,-0.8 1.7,-1.5 2.8,-2 1.1,-0.5 2.3,-0.7 3.5,-0.7 1.2,0 2.3,0.2 3.3,0.6 1,0.4 1.8,0.9 2.5,1.6 0.7,0.7 1.2,1.5 1.6,2.5 0.4,1 0.6,2.1 0.6,3.2 v 27 h 8.2 V 119 c 0,-1.3 0.2,-2.6 0.7,-3.7 0.4,-1.1 1,-2.1 1.8,-2.9 0.8,-0.8 1.7,-1.4 2.7,-1.9 1.1,-0.4 2.2,-0.7 3.5,-0.7 2.6,0 4.6,0.8 6,2.2 1.4,1.5 2.1,3.6 2.1,6.3 v 26.3 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path23"
|
||||
d="m 147.4,170.9 c -36.3,0 -59.1,25.3 -59.1,65.6 0,40.3 22.8,65.6 59.1,65.6 36.3,0 59.1,-25.3 59.1,-65.6 -0.1,-40.3 -22.8,-65.6 -59.1,-65.6 z m 0,115 c -24.9,0 -40.5,-19.1 -40.5,-49.4 0,-30.4 15.6,-49.5 40.5,-49.5 24.8,0 40.5,19.1 40.5,49.5 -0.1,30.3 -15.7,49.4 -40.5,49.4 z"
|
||||
class="st1" />
|
||||
<path
|
||||
style="fill:#515151"
|
||||
id="path25"
|
||||
d="m 252.1,113.5 c 1,-1.2 2.1,-2.2 3.5,-2.9 1.4,-0.7 2.9,-1 4.6,-1 1.4,0 2.7,0.2 3.8,0.6 1.1,0.4 2.1,0.9 3,1.6 0.8,0.7 1.5,1.5 2,2.5 0.5,1 0.9,2 1.1,3.1 h 7.9 c -0.2,-2 -0.7,-3.9 -1.6,-5.7 -0.9,-1.8 -2.1,-3.3 -3.6,-4.7 -1.5,-1.3 -3.4,-2.4 -5.5,-3.2 -2.1,-0.8 -4.5,-1.2 -7.2,-1.2 -2.9,0 -5.6,0.5 -8,1.5 -2.4,1 -4.4,2.4 -6.1,4.3 -1.7,1.9 -3,4.1 -3.9,6.7 -0.9,2.6 -1.4,5.5 -1.4,8.8 0,3.3 0.5,6.3 1.4,8.9 0.9,2.6 2.3,4.9 4,6.7 1.7,1.8 3.8,3.2 6.2,4.2 2.4,1 5.1,1.5 8,1.5 2.5,0 4.8,-0.4 6.9,-1 2.1,-0.6 3.9,-1.7 5.5,-2.9 1.5,-1.3 2.8,-2.8 3.8,-4.6 1,-1.8 1.6,-3.8 1.8,-5.9 h -7.9 c -0.5,2.5 -1.6,4.3 -3.3,5.6 -1.7,1.3 -3.9,1.9 -6.6,1.9 -1.7,0 -3.2,-0.3 -4.6,-1 -1.4,-0.6 -2.6,-1.6 -3.5,-2.8 -1,-1.2 -1.7,-2.7 -2.3,-4.5 -0.5,-1.8 -0.8,-3.8 -0.8,-6 0,-2.2 0.3,-4.1 0.8,-5.9 0.3,-1.9 1,-3.4 2,-4.6 z"
|
||||
class="st1" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.5 KiB |
|
@ -1,54 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 429 117.3" enable-background="new 0 0 429 117.3" xml:space="preserve">
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="58.666" y1="117.332" x2="58.666" y2="-9.094947e-13">
|
||||
<stop offset="0" style="stop-color:#0882C8"/>
|
||||
<stop offset="1" style="stop-color:#26B6DB"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_1_)" cx="58.7" cy="58.7" r="58.7"/>
|
||||
<g>
|
||||
<circle fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" cx="58.7" cy="58.5" r="43.7"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M94.7,47.8c4.7,1.6,9.8-0.9,11.4-5.6c1.6-4.7-0.9-9.8-5.6-11.4c-4.7-1.6-9.8,0.9-11.4,5.6
|
||||
C87.5,41.1,90,46.2,94.7,47.8z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="97.6" y1="39.4" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M77.6,91c-0.4,4.9,3.2,9.3,8.2,9.8c5,0.4,9.3-3.2,9.8-8.2c0.4-4.9-3.2-9.3-8.2-9.8
|
||||
C82.4,82.4,78,86,77.6,91z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="86.5" y1="91.8" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" d="M60,69.3c2.7,4.2,8.3,5.4,12.4,2.7c4.2-2.7,5.4-8.3,2.7-12.4c-2.7-4.2-8.3-5.4-12.4-2.7
|
||||
C58.5,59.5,57.3,65.1,60,69.3z"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M21.2,61.4c-4.3-2.5-9.8-1.1-12.3,3.1c-2.5,4.3-1.1,9.8,3.1,12.3c4.3,2.5,9.8,1.1,12.3-3.1
|
||||
C26.8,69.5,25.4,64,21.2,61.4z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="16.6" y1="69.1" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0891D1" d="M163.8,50.2c-0.6-0.7-6.3-4.1-11.4-4.1c-3.4,0-5.2,1.2-5.2,3.5c0,2.9,3.2,3.7,8.9,5.2
|
||||
c8.2,2.2,13.3,5,13.3,12.9c0,9.7-7.8,13-16,13c-6.2,0-13.1-2-18.2-5.3l4.3-8.6c0.8,0.8,7.5,5,14,5c3.5,0,5.2-1.1,5.2-3.2
|
||||
c0-3.2-4.4-4-10.3-5.8c-7.9-2.4-11.5-5.3-11.5-11.8c0-9,7.2-13.9,15.7-13.9c6.1,0,11.6,2.5,15.4,4.7L163.8,50.2z"/>
|
||||
<path fill="#0891D1" d="M175,85.1c1.7,0.5,3.3,0.8,4.4,0.8c2,0,3.3-1.5,4.2-5.5l-11.9-31.5h9.8l7.4,23.3l6.3-23.3h8.9l-12.1,36.6
|
||||
c-1.7,5.3-6.2,8.7-11.8,8.8c-1.7,0-3.5-0.2-5.3-0.9V85.1z"/>
|
||||
<path fill="#0891D1" d="M239.3,80.3h-9.6V62.6c0-4.1-1.7-5.9-4.3-5.9c-2.6,0-5.8,2.3-7,5.6v18.1h-9.6V48.8h8.6v5.3
|
||||
c2.3-3.7,6.8-5.9,12.2-5.9c8.2,0,9.5,6.7,9.5,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M261.6,48.2c7.2,0,12.3,3.4,14.8,8.3l-9.4,2.8c-1.2-1.9-3.1-3-5.5-3c-4,0-7,3.2-7,8.2c0,5,3.1,8.3,7,8.3
|
||||
c2.4,0,4.6-1.3,5.5-3.1l9.4,2.9c-2.3,4.9-7.6,8.3-14.8,8.3c-10.6,0-16.9-7.7-16.9-16.4S250.9,48.2,261.6,48.2z"/>
|
||||
<path fill="#0891D1" d="M302.1,78.7c-2.6,1.1-6.2,2.3-9.7,2.3c-4.7,0-8.8-2.3-8.8-8.4V56.1h-4v-7.3h4v-10h9.6v10h6.4v7.3h-6.4v13.1
|
||||
c0,2.1,1.2,2.9,2.8,2.9c1.4,0,3-0.6,4.2-1.1L302.1,78.7z"/>
|
||||
<path fill="#0891D1" d="M337.2,80.3h-9.6V62.6c0-4.1-1.8-5.9-4.6-5.9c-2.3,0-5.5,2.2-6.7,5.6v18.1h-9.6V36.5h9.6v17.6
|
||||
c2.3-3.7,6.3-5.9,10.9-5.9c8.5,0,9.9,6.5,9.9,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M343.4,45.2v-8.7h9.6v8.7H343.4z M343.4,80.3V48.8h9.6v31.5H343.4z"/>
|
||||
<path fill="#0891D1" d="M389.9,80.3h-9.6V62.6c0-4.1-1.7-5.9-4.3-5.9c-2.6,0-5.8,2.3-7,5.6v18.1h-9.6V48.8h8.6v5.3
|
||||
c2.3-3.7,6.8-5.9,12.2-5.9c8.2,0,9.5,6.7,9.5,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M395.5,64.6c0-9.2,6-16.3,14.6-16.3c4.7,0,8.4,2.2,10.6,5.8v-5.2h8.3v29.3c0,9.6-7.5,15.5-18.2,15.5
|
||||
c-6.8,0-11.5-2.3-15-6.3l5.1-5.2c2.3,2.6,6,4.3,9.9,4.3c4.6,0,8.6-2.4,8.6-8.3v-3.1c-1.9,3.5-5.9,5.3-10,5.3
|
||||
C401.1,80.5,395.5,73.3,395.5,64.6z M419.4,68.5v-6.6c-1.3-3.3-4.2-5.5-7.1-5.5c-4.1,0-7,4-7,8.4c0,4.6,3.2,8,7.5,8
|
||||
C415.7,72.8,418.1,71,419.4,68.5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 429 117.3" enable-background="new 0 0 429 117.3" xml:space="preserve">
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="58.666" y1="117.332" x2="58.666" y2="-9.094947e-13">
|
||||
<stop offset="0" style="stop-color:#0882C8"/>
|
||||
<stop offset="1" style="stop-color:#26B6DB"/>
|
||||
</linearGradient>
|
||||
<circle fill="url(#SVGID_1_)" cx="58.7" cy="58.7" r="58.7"/>
|
||||
<g>
|
||||
<circle fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" cx="58.7" cy="58.5" r="43.7"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M94.7,47.8c4.7,1.6,9.8-0.9,11.4-5.6c1.6-4.7-0.9-9.8-5.6-11.4c-4.7-1.6-9.8,0.9-11.4,5.6
|
||||
C87.5,41.1,90,46.2,94.7,47.8z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="97.6" y1="39.4" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M77.6,91c-0.4,4.9,3.2,9.3,8.2,9.8c5,0.4,9.3-3.2,9.8-8.2c0.4-4.9-3.2-9.3-8.2-9.8
|
||||
C82.4,82.4,78,86,77.6,91z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="86.5" y1="91.8" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" d="M60,69.3c2.7,4.2,8.3,5.4,12.4,2.7c4.2-2.7,5.4-8.3,2.7-12.4c-2.7-4.2-8.3-5.4-12.4-2.7
|
||||
C58.5,59.5,57.3,65.1,60,69.3z"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M21.2,61.4c-4.3-2.5-9.8-1.1-12.3,3.1c-2.5,4.3-1.1,9.8,3.1,12.3c4.3,2.5,9.8,1.1,12.3-3.1
|
||||
C26.8,69.5,25.4,64,21.2,61.4z"/>
|
||||
<line fill="none" stroke="#FFFFFF" stroke-width="6" stroke-miterlimit="10" x1="16.6" y1="69.1" x2="67.5" y2="64.4"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0891D1" d="M163.8,50.2c-0.6-0.7-6.3-4.1-11.4-4.1c-3.4,0-5.2,1.2-5.2,3.5c0,2.9,3.2,3.7,8.9,5.2
|
||||
c8.2,2.2,13.3,5,13.3,12.9c0,9.7-7.8,13-16,13c-6.2,0-13.1-2-18.2-5.3l4.3-8.6c0.8,0.8,7.5,5,14,5c3.5,0,5.2-1.1,5.2-3.2
|
||||
c0-3.2-4.4-4-10.3-5.8c-7.9-2.4-11.5-5.3-11.5-11.8c0-9,7.2-13.9,15.7-13.9c6.1,0,11.6,2.5,15.4,4.7L163.8,50.2z"/>
|
||||
<path fill="#0891D1" d="M175,85.1c1.7,0.5,3.3,0.8,4.4,0.8c2,0,3.3-1.5,4.2-5.5l-11.9-31.5h9.8l7.4,23.3l6.3-23.3h8.9l-12.1,36.6
|
||||
c-1.7,5.3-6.2,8.7-11.8,8.8c-1.7,0-3.5-0.2-5.3-0.9V85.1z"/>
|
||||
<path fill="#0891D1" d="M239.3,80.3h-9.6V62.6c0-4.1-1.7-5.9-4.3-5.9c-2.6,0-5.8,2.3-7,5.6v18.1h-9.6V48.8h8.6v5.3
|
||||
c2.3-3.7,6.8-5.9,12.2-5.9c8.2,0,9.5,6.7,9.5,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M261.6,48.2c7.2,0,12.3,3.4,14.8,8.3l-9.4,2.8c-1.2-1.9-3.1-3-5.5-3c-4,0-7,3.2-7,8.2c0,5,3.1,8.3,7,8.3
|
||||
c2.4,0,4.6-1.3,5.5-3.1l9.4,2.9c-2.3,4.9-7.6,8.3-14.8,8.3c-10.6,0-16.9-7.7-16.9-16.4S250.9,48.2,261.6,48.2z"/>
|
||||
<path fill="#0891D1" d="M302.1,78.7c-2.6,1.1-6.2,2.3-9.7,2.3c-4.7,0-8.8-2.3-8.8-8.4V56.1h-4v-7.3h4v-10h9.6v10h6.4v7.3h-6.4v13.1
|
||||
c0,2.1,1.2,2.9,2.8,2.9c1.4,0,3-0.6,4.2-1.1L302.1,78.7z"/>
|
||||
<path fill="#0891D1" d="M337.2,80.3h-9.6V62.6c0-4.1-1.8-5.9-4.6-5.9c-2.3,0-5.5,2.2-6.7,5.6v18.1h-9.6V36.5h9.6v17.6
|
||||
c2.3-3.7,6.3-5.9,10.9-5.9c8.5,0,9.9,6.5,9.9,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M343.4,45.2v-8.7h9.6v8.7H343.4z M343.4,80.3V48.8h9.6v31.5H343.4z"/>
|
||||
<path fill="#0891D1" d="M389.9,80.3h-9.6V62.6c0-4.1-1.7-5.9-4.3-5.9c-2.6,0-5.8,2.3-7,5.6v18.1h-9.6V48.8h8.6v5.3
|
||||
c2.3-3.7,6.8-5.9,12.2-5.9c8.2,0,9.5,6.7,9.5,11.9V80.3z"/>
|
||||
<path fill="#0891D1" d="M395.5,64.6c0-9.2,6-16.3,14.6-16.3c4.7,0,8.4,2.2,10.6,5.8v-5.2h8.3v29.3c0,9.6-7.5,15.5-18.2,15.5
|
||||
c-6.8,0-11.5-2.3-15-6.3l5.1-5.2c2.3,2.6,6,4.3,9.9,4.3c4.6,0,8.6-2.4,8.6-8.3v-3.1c-1.9,3.5-5.9,5.3-10,5.3
|
||||
C401.1,80.5,395.5,73.3,395.5,64.6z M419.4,68.5v-6.6c-1.3-3.3-4.2-5.5-7.1-5.5c-4.1,0-7,4-7,8.4c0,4.6,3.2,8,7.5,8
|
||||
C415.7,72.8,418.1,71,419.4,68.5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.7 KiB |
|
@ -1,34 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="robots" content="noindex">
|
||||
<script>
|
||||
if (document.URL.indexOf("ui") === -1) {
|
||||
window.location.replace("ui")
|
||||
}
|
||||
</script>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/ui/img/icon/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/ui/site.webmanifest">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<link rel="icon" href="/ui/favicon.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@mdi/font@6.5.95/css/materialdesignicons.min.css">
|
||||
<title>
|
||||
CasaOS
|
||||
</title>
|
||||
<link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/chunk-vendors.js" rel="preload" as="script"></head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but CasaOS doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="text/javascript" src="/ui/js/chunk-vendors.js"></script><script type="text/javascript" src="/ui/js/app.js"></script></body>
|
||||
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="robots" content="noindex">
|
||||
<script>
|
||||
if (document.URL.indexOf("ui") === -1) {
|
||||
window.location.replace("ui")
|
||||
}
|
||||
</script>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/ui/img/icon/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/ui/site.webmanifest">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<link rel="icon" href="/ui/favicon.svg" type="image/svg+xml">
|
||||
|
||||
<title>
|
||||
CasaOS
|
||||
</title>
|
||||
<link href="/ui/js/0.js" rel="prefetch"><link href="/ui/js/1.js" rel="prefetch"><link href="/ui/js/2.js" rel="prefetch"><link href="/ui/js/3.js" rel="prefetch"><link href="/ui/js/4.js" rel="prefetch"><link href="/ui/js/5.js" rel="prefetch"><link href="/ui/js/6.js" rel="prefetch"><link href="/ui/js/7.js" rel="prefetch"><link href="/ui/js/app.js" rel="preload" as="script"><link href="/ui/js/chunk-vendors.js" rel="preload" as="script"></head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but CasaOS doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="text/javascript" src="/ui/js/chunk-vendors.js"></script><script type="text/javascript" src="/ui/js/app.js"></script></body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -168,7 +168,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n/* harmony import */ var is_valid_hostname__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! is-valid-hostname */ \"./node_modules/is-valid-hostname/index.js\");\n/* harmony import */ var is_valid_hostname__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(is_valid_hostname__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var uuid_validate__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! uuid-validate */ \"./node_modules/uuid-validate/index.js\");\n/* harmony import */ var uuid_validate__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(uuid_validate__WEBPACK_IMPORTED_MODULE_4__);\n\n\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])('rfc1123', {\n validate: function validate(value) {\n return is_valid_hostname__WEBPACK_IMPORTED_MODULE_3___default()(value);\n },\n message: 'You entered an invalid RFC1123 hostname'\n});\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])('uuid', {\n validate: function validate(value) {\n return uuid_validate__WEBPACK_IMPORTED_MODULE_4___default()(value);\n },\n message: 'You entered an invalid share ID'\n});\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n/* harmony import */ var is_valid_hostname__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! is-valid-hostname */ \"./node_modules/is-valid-hostname/index.js\");\n/* harmony import */ var is_valid_hostname__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(is_valid_hostname__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var uuid_validate__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! uuid-validate */ \"./node_modules/uuid-validate/index.js\");\n/* harmony import */ var uuid_validate__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(uuid_validate__WEBPACK_IMPORTED_MODULE_4__);\n\n\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(E_Company_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])('rfc1123', {\n validate: function validate(value) {\n return is_valid_hostname__WEBPACK_IMPORTED_MODULE_3___default()(value);\n },\n message: 'You entered an invalid RFC1123 hostname'\n});\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])('uuid', {\n validate: function validate(value) {\n return uuid_validate__WEBPACK_IMPORTED_MODULE_4___default()(value);\n },\n message: 'You entered an invalid share ID'\n});\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
|
||||
|
||||
/***/ })
|
||||
|
||||
|
|
24
web/js/2.js
1024
web/js/3.js
7014
web/js/4.js
7727
web/js/5.js
10
web/js/6.js
10
web/js/7.js
103
web/js/app.js
|
@ -1,2 +1,2 @@
|
|||
User-agent: *
|
||||
User-agent: *
|
||||
Disallow: /
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/ui/img/icon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/ui/img/icon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package web
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed index.html favicon.svg img js browserconfig.xml site.webmanifest robots.txt
|
||||
var Static embed.FS
|
||||
package web
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed index.html favicon.svg browserconfig.xml site.webmanifest robots.txt img js fonts
|
||||
var Static embed.FS
|
||||
|
|