mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-13 11:53:41 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63210dce63 |
No files matched your search
@@ -1,27 +0,0 @@
|
|||||||
## Donate
|
|
||||||
|
|
||||||
Thank you for your support! 🙏
|
|
||||||
|
|
||||||
<div style="text-align: center;">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>微信</th>
|
|
||||||
<th>支付宝</th>
|
|
||||||
<th>PayPal</th>
|
|
||||||
<th>Ko-fi</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="/.donate/qr/wechatpay.jpg" alt="wechatpay" width="300" /></td>
|
|
||||||
<td><img src="/.donate/qr/alipay.jpg" alt="alipay" width="300" /></td>
|
|
||||||
<td><a href="https://paypal.me/monkeyWie" target="_blank">Click Me</a></td>
|
|
||||||
<td><a href="https://ko-fi.com/gopeed" target="_blank">Click Me</a></td>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
### Crypto
|
|
||||||
|
|
||||||
- **BTC**: 35jYkPN8bgkh7AWjt3B1VgMQHqtGYcvF6p
|
|
||||||
- **ETH:** 0x928a7fd2398c941Ac6713704e606Fa414595e3A0
|
|
||||||
- **Matic:** 0x928a7fd2398c941Ac6713704e606Fa414595e3A0
|
|
||||||
- **BNB:** 0x928a7fd2398c941Ac6713704e606Fa414595e3A0
|
|
||||||
- **USDT(ERC20)**: 0x928a7fd2398c941Ac6713704e606Fa414595e3A0
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 81 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB |
@@ -1,15 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
||||||
#patreon: # Replace with a single Patreon username
|
|
||||||
#open_collective: # Replace with a single Open Collective username
|
|
||||||
#ko_fi: # Replace with a single Ko-fi username
|
|
||||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
||||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
#liberapay: # Replace with a single Liberapay username
|
|
||||||
#issuehunt: # Replace with a single IssueHunt username
|
|
||||||
#otechie: # Replace with a single Otechie username
|
|
||||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
||||||
# github: monkeyWie
|
|
||||||
ko_fi: gopeed
|
|
||||||
custom: https://github.com/GopeedLab/gopeed/blob/main/.donate/index.md#donate
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<!--
|
|
||||||
Please use the following template to create an issue.
|
|
||||||
-->
|
|
||||||
### Description(required)
|
|
||||||
### App Version(required)
|
|
||||||
### OS Version(required)
|
|
||||||
### Snapshots
|
|
||||||
### Log
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
name-template: 'v$NEXT_PATCH_VERSION 🌈'
|
|
||||||
tag-template: 'v$NEXT_PATCH_VERSION'
|
|
||||||
categories:
|
|
||||||
- title: '🆕 Features'
|
|
||||||
labels:
|
|
||||||
- 'feat'
|
|
||||||
- 'feature'
|
|
||||||
- 'enhancement'
|
|
||||||
- title: '🐛 Bug Fixes'
|
|
||||||
labels:
|
|
||||||
- 'fix'
|
|
||||||
- 'bugfix'
|
|
||||||
- 'bug'
|
|
||||||
- title: '🧰 Maintenance'
|
|
||||||
label: 'chore'
|
|
||||||
- title: '📖 Document'
|
|
||||||
label: 'doc'
|
|
||||||
- title: '🚀 CI/CD'
|
|
||||||
label: 'ci'
|
|
||||||
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
|
||||||
version-resolver:
|
|
||||||
major:
|
|
||||||
labels:
|
|
||||||
- 'major'
|
|
||||||
minor:
|
|
||||||
labels:
|
|
||||||
- 'minor'
|
|
||||||
patch:
|
|
||||||
labels:
|
|
||||||
- 'patch'
|
|
||||||
default: patch
|
|
||||||
template: |
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
$CHANGES
|
|
||||||
@@ -1,362 +0,0 @@
|
|||||||
name: build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
get-release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
tag_name: ${{ steps.get-release.outputs.tag_name }}
|
|
||||||
upload_url: ${{ steps.get-release.outputs.upload_url }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: monkeyWie/get-latest-release@v1
|
|
||||||
id: get-release
|
|
||||||
with:
|
|
||||||
myToken: ${{ github.token }}
|
|
||||||
|
|
||||||
build-windows:
|
|
||||||
runs-on: windows-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
run: |
|
|
||||||
Invoke-WebRequest -Uri "https://github.com/jrsoftware/issrc/raw/main/Files/Languages/Unofficial/ChineseSimplified.isl" -OutFile "ChineseSimplified.isl"
|
|
||||||
mv ChineseSimplified.isl "C:\Program Files (x86)\Inno Setup 6\Languages\"
|
|
||||||
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build windows
|
|
||||||
$mingw = "C:\ProgramData\Chocolatey\lib\mingw\tools\install\mingw64\bin"
|
|
||||||
$system = "C:\Windows\System32"
|
|
||||||
$release = "build\windows\runner\Release\"
|
|
||||||
cp $mingw\libstdc++-6.dll $release
|
|
||||||
cp $mingw\libgcc_s_seh-1.dll $release
|
|
||||||
cp $mingw\libwinpthread-1.dll $release
|
|
||||||
cp $system\msvcp140.dll $release
|
|
||||||
cp $system\vcruntime140.dll $release
|
|
||||||
cp $system\vcruntime140_1.dll $release
|
|
||||||
|
|
||||||
New-Item -Path build\windows\Output -ItemType Directory
|
|
||||||
Compress-Archive -Path "$release*" -DestinationPath "build\windows\Output\Gopeed-$env:VERSION-windows-amd64-portable.zip"
|
|
||||||
|
|
||||||
cd build/windows
|
|
||||||
echo @"
|
|
||||||
; Script generated by the Inno Setup Script Wizard.
|
|
||||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
|
||||||
|
|
||||||
#define MyAppName "Gopeed"
|
|
||||||
#define MyAppVersion "$($env:VERSION.substring(1))"
|
|
||||||
#define MyAppPublisher "monkeyWie"
|
|
||||||
#define MyAppURL "https://gopeed.com"
|
|
||||||
#define MyAppExeName "gopeed.exe"
|
|
||||||
|
|
||||||
[Setup]
|
|
||||||
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
|
||||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
|
||||||
AppId={{5960F34D-1E42-402C-8C85-DE2FF24CBAE4}
|
|
||||||
AppName={#MyAppName}
|
|
||||||
AppVersion={#MyAppVersion}
|
|
||||||
;AppVerName={#MyAppName} {#MyAppVersion}
|
|
||||||
AppPublisher={#MyAppPublisher}
|
|
||||||
AppPublisherURL={#MyAppURL}
|
|
||||||
AppSupportURL={#MyAppURL}
|
|
||||||
AppUpdatesURL={#MyAppURL}
|
|
||||||
DefaultDirName={autopf}\gopeed
|
|
||||||
DisableProgramGroupPage=yes
|
|
||||||
LicenseFile=..\..\..\..\LICENSE
|
|
||||||
; Remove the following line to run in administrative install mode (install for all users.)
|
|
||||||
PrivilegesRequired=lowest
|
|
||||||
OutputBaseFilename=gopeed
|
|
||||||
SetupIconFile=..\..\assets\icon\icon.ico
|
|
||||||
Compression=lzma
|
|
||||||
SolidCompression=yes
|
|
||||||
WizardStyle=modern
|
|
||||||
LanguageDetectionMethod=uilanguage
|
|
||||||
ShowLanguageDialog=yes
|
|
||||||
|
|
||||||
[Languages]
|
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
||||||
Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
|
|
||||||
|
|
||||||
[Tasks]
|
|
||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
||||||
|
|
||||||
[Files]
|
|
||||||
Source: ".\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
|
||||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
|
||||||
|
|
||||||
[UninstallDelete]
|
|
||||||
Type: filesandordirs; Name: "{app}"
|
|
||||||
|
|
||||||
[Icons]
|
|
||||||
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
||||||
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
||||||
|
|
||||||
[Run]
|
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
|
||||||
"@ > setup.iss
|
|
||||||
iscc.exe setup.iss
|
|
||||||
mv "Output\gopeed.exe" "Output\Gopeed-$env:VERSION-windows-amd64.exe"
|
|
||||||
Compress-Archive -Path "Output\Gopeed-$env:VERSION-windows-amd64.exe" -DestinationPath "Output\Gopeed-$env:VERSION-windows-amd64.zip"
|
|
||||||
Remove-Item -Path "Output\Gopeed-$env:VERSION-windows-amd64.exe"
|
|
||||||
- name: Upload
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
|
||||||
asset_path: ui/flutter/build/windows/Output/*
|
|
||||||
overwrite: true
|
|
||||||
build-macos-arm64-lib:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
docker pull techknowlogick/xgo:go-1.19.x
|
|
||||||
go install src.techknowlogick.com/xgo@latest
|
|
||||||
xgo --targets=darwin/arm64 -tags="nosqlite" -ldflags="-w -s" -buildmode=c-shared -pkg=bind/desktop -out=libgopeed .
|
|
||||||
mv libgopeed-*.dylib libgopeed.dylib
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: macos-arm64-lib
|
|
||||||
path: libgopeed.dylib
|
|
||||||
build-macos:
|
|
||||||
runs-on: macos-latest
|
|
||||||
needs: [get-release, build-macos-arm64-lib]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 16
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- name: Install appdmg
|
|
||||||
run: npm install -g appdmg
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: macos-arm64-lib
|
|
||||||
path: ui/flutter/lib-arm64
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
run: |
|
|
||||||
PROJECT_DIR=$(pwd)
|
|
||||||
|
|
||||||
# amd64 lib
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/lib-amd64/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
# universal binary
|
|
||||||
mkdir -p ui/flutter/macos/Frameworks
|
|
||||||
cp ui/flutter/lib-amd64/libgopeed.dylib ui/flutter/macos/Frameworks/amd64-lib
|
|
||||||
cp ui/flutter/lib-arm64/libgopeed.dylib ui/flutter/macos/Frameworks/arm64-lib
|
|
||||||
cd ui/flutter/macos/Frameworks
|
|
||||||
lipo -create -output libgopeed.dylib amd64-lib arm64-lib
|
|
||||||
|
|
||||||
cd $PROJECT_DIR/ui/flutter
|
|
||||||
flutter build macos
|
|
||||||
cd build/macos/Build/Products/Release
|
|
||||||
cat>appdmg.json<<EOF
|
|
||||||
{
|
|
||||||
"title": "Gopeed",
|
|
||||||
"icon": "Gopeed.app/Contents/Resources/AppIcon.icns",
|
|
||||||
"contents": [
|
|
||||||
{ "x": 448, "y": 344, "type": "link", "path": "/Applications" },
|
|
||||||
{ "x": 192, "y": 344, "type": "file", "path": "Gopeed.app" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
mkdir dist
|
|
||||||
appdmg appdmg.json dist/Gopeed-$VERSION-macos.dmg
|
|
||||||
- name: Upload
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
|
||||||
asset_path: ui/flutter/build/macos/Build/Products/Release/dist/*
|
|
||||||
overwrite: true
|
|
||||||
build-linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- run: |
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get install -y ninja-build libgtk-3-dev
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
run: |
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build linux
|
|
||||||
mkdir -p debian/gui
|
|
||||||
cp assets/icon/icon_1024.png debian/gui/gopeed.png
|
|
||||||
cat>debian/debian.yaml<<EOF
|
|
||||||
flutter_app:
|
|
||||||
command: gopeed
|
|
||||||
arch: x64
|
|
||||||
parent: /usr/local/lib
|
|
||||||
control:
|
|
||||||
Package: gopeed
|
|
||||||
Version: ${VERSION:1}
|
|
||||||
Architecture: amd64
|
|
||||||
Essential: no
|
|
||||||
Priority: optional
|
|
||||||
Depends:
|
|
||||||
Maintainer: monkeyWie
|
|
||||||
Description: High speed downloader that supports all platforms.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat>debian/gui/gopeed.desktop<<EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Version=${VERSION:1}
|
|
||||||
Name=Gopeed
|
|
||||||
GenericName=Gopeed
|
|
||||||
Comment=High speed downloader that supports all platforms.
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Utility
|
|
||||||
Keywords=Flutter;Downloader;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
dart pub global activate flutter_to_debian
|
|
||||||
flutter_to_debian
|
|
||||||
mv debian/packages/gopeed*.deb debian/packages/Gopeed-$VERSION-linux-amd64.deb
|
|
||||||
- name: Upload
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
|
||||||
asset_path: ui/flutter/debian/packages/*
|
|
||||||
overwrite: true
|
|
||||||
build-android:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
distribution: "zulu"
|
|
||||||
java-version: "11"
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
APK_KEYSTORE : ${{ secrets.APK_KEYSTORE }}
|
|
||||||
APK_KEY_PASSWORD : ${{ secrets.APK_KEY_PASSWORD }}
|
|
||||||
APK_STORE_PASSWORD : ${{ secrets.APK_STORE_PASSWORD }}
|
|
||||||
run: |
|
|
||||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
|
||||||
go get golang.org/x/mobile/bind
|
|
||||||
gomobile init
|
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
|
||||||
cd ui/flutter
|
|
||||||
echo $APK_KEYSTORE | base64 -di > android/app/upload-keystore.jks
|
|
||||||
flutter build apk
|
|
||||||
mkdir dist
|
|
||||||
cp build/app/outputs/flutter-apk/app-release.apk dist/Gopeed-$VERSION-android.apk
|
|
||||||
- name: Upload
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
|
||||||
asset_path: ui/flutter/dist/*
|
|
||||||
overwrite: true
|
|
||||||
build-web:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
run: |
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build web
|
|
||||||
cd ../../
|
|
||||||
cp -r ui/flutter/build/web cmd/web/dist
|
|
||||||
mkdir -p dist/zip
|
|
||||||
goos_arr=(windows darwin linux)
|
|
||||||
goarch_arr=(386 amd64 arm64)
|
|
||||||
export CGO_ENABLED=0
|
|
||||||
for goos in "${goos_arr[@]}"; do
|
|
||||||
for goarch in "${goarch_arr[@]}"; do
|
|
||||||
goos_name=$goos
|
|
||||||
if [ $goos = "darwin" ]; then
|
|
||||||
goos_name="macos"
|
|
||||||
fi
|
|
||||||
name=gopeed-web-$VERSION-$goos_name-$goarch
|
|
||||||
dir="dist/$name/"
|
|
||||||
(GOOS=$goos GOARCH=$goarch go build -tags nosqlite,web -ldflags="-s -w" -o $dir github.com/GopeedLab/gopeed/cmd/web \
|
|
||||||
&& cd $dir \
|
|
||||||
&& file=$(ls -AU | head -1) \
|
|
||||||
&& mkdir $name \
|
|
||||||
&& mv $file $name/$(echo $file | sed -e "s/web/gopeed/g") \
|
|
||||||
&& zip -r ../zip/$name.zip * \
|
|
||||||
&& cd ../..) \
|
|
||||||
|| true
|
|
||||||
done
|
|
||||||
done
|
|
||||||
- name: Upload
|
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
|
||||||
with:
|
|
||||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
|
||||||
asset_path: dist/zip/*
|
|
||||||
overwrite: true
|
|
||||||
build-docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [get-release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: liwei2633
|
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
env:
|
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
|
||||||
with:
|
|
||||||
push: true
|
|
||||||
platforms: |
|
|
||||||
linux/386
|
|
||||||
linux/amd64
|
|
||||||
linux/arm64
|
|
||||||
tags: |
|
|
||||||
liwei2633/gopeed:latest
|
|
||||||
liwei2633/gopeed:${{ env.VERSION }}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
name: release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "bind/**"
|
|
||||||
- "cmd/**"
|
|
||||||
- "internal/**"
|
|
||||||
- "pkg/**"
|
|
||||||
- "ui/**"
|
|
||||||
- ".github/workflows/release.yml"
|
|
||||||
- ".github/release-drafter.yml"
|
|
||||||
- "go.mod"
|
|
||||||
- "go.sum"
|
|
||||||
- "Dockerfile"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
tag_name: ${{ steps.create_release.outputs.tag_name }}
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
- uses: release-drafter/release-drafter@v5
|
|
||||||
id: create_release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
name: test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "bind/**"
|
|
||||||
- "cmd/**"
|
|
||||||
- "internal/**"
|
|
||||||
- "pkg/**"
|
|
||||||
- "ui/**"
|
|
||||||
- ".github/workflows/test.yml"
|
|
||||||
- "go.mod"
|
|
||||||
- "go.sum"
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "bind/**"
|
|
||||||
- "cmd/**"
|
|
||||||
- "internal/**"
|
|
||||||
- "pkg/**"
|
|
||||||
- "ui/**"
|
|
||||||
- ".github/workflows/test.yml"
|
|
||||||
- "go.mod"
|
|
||||||
- "go.sum"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# lint:
|
|
||||||
# name: Lint
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/setup-go@v2
|
|
||||||
# with:
|
|
||||||
# go-version: '^1.19'
|
|
||||||
# - uses: actions/checkout@v2
|
|
||||||
# - name: Lint Go Code
|
|
||||||
# run: |
|
|
||||||
# export PATH=$PATH:$(go env GOPATH)/bin # temporary fix. See https://github.com/actions/setup-go/issues/14
|
|
||||||
# go get -u golang.org/x/lint/golint
|
|
||||||
# golint -set_exit_status ./...
|
|
||||||
test:
|
|
||||||
name: Test check
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- name: Run Unit tests.
|
|
||||||
run: go test $(go list ./... | grep -v /cmd/ | grep -v /bind/ ) -v -covermode=count -coverprofile=coverage.txt
|
|
||||||
- uses: codecov/codecov-action@v3
|
|
||||||
with:
|
|
||||||
files: ./coverage.txt
|
|
||||||
build:
|
|
||||||
name: Build check
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# needs: [lint, test]
|
|
||||||
needs: [test]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: "^1.19"
|
|
||||||
cache: true
|
|
||||||
- uses: subosito/flutter-action@v2
|
|
||||||
- run: |
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get install -y ninja-build libgtk-3-dev
|
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build linux
|
|
||||||
+2
-13
@@ -11,17 +11,6 @@
|
|||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
.idea/
|
debug
|
||||||
|
|
||||||
bin/
|
.idea/
|
||||||
|
|
||||||
.torrent.db
|
|
||||||
.torrent.db-shm
|
|
||||||
.torrent.db-wal
|
|
||||||
|
|
||||||
*.data
|
|
||||||
*.db
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
dist/
|
|
||||||
Vendored
+17
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${fileDirname}",
|
||||||
|
"env": {},
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"go.useLanguageServer": true,
|
||||||
|
"[go]": {
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Gopeed contributors guide
|
|
||||||
|
|
||||||
Firstly, thank you for your interest in contributing to Gopeed. This guide will help you better
|
|
||||||
participate in the development of Gopeed.
|
|
||||||
|
|
||||||
## Branch description
|
|
||||||
|
|
||||||
This project only has one main branch, namely the `main` branch. If you want to participate in the
|
|
||||||
development of Gopeed, please fork this project first, and then develop in your fork project. After
|
|
||||||
development is completed, submit a PR to this project and merge it into the `main` branch.
|
|
||||||
|
|
||||||
## Local development
|
|
||||||
|
|
||||||
It is recommended to develop and debug through the web. First, start the backend service, and start
|
|
||||||
it by the command line `go run cmd/api/main.go`, the default port of the service is `9999`, and then
|
|
||||||
start the front-end flutter project in `debug` mode to run.
|
|
||||||
|
|
||||||
## Translation
|
|
||||||
|
|
||||||
The internationalization files of Gopeed are located in the `ui/flutter/assets/locales` directory.
|
|
||||||
You only need to add the corresponding language file in this directory.
|
|
||||||
|
|
||||||
|
|
||||||
Generate locales after you edit locales:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
get generate locales
|
|
||||||
```
|
|
||||||
|
|
||||||
Please refer to `en_us.dart` for translation.
|
|
||||||
|
|
||||||
## flutter development
|
|
||||||
|
|
||||||
Don't forget to run`dart format ./ui/flutter`before you commit to keep your code in standard dart format
|
|
||||||
|
|
||||||
Turn on build_runner watcher if you want to edit api/models:
|
|
||||||
|
|
||||||
```
|
|
||||||
flutter pub run build_runner watch
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
get-cli commands usages:
|
|
||||||
|
|
||||||
```
|
|
||||||
create:
|
|
||||||
controller: Generate controller
|
|
||||||
page: Use to generate pages
|
|
||||||
view: Generate view
|
|
||||||
generate:
|
|
||||||
locales: Generate translation file from json files
|
|
||||||
model: generate Class model from json
|
|
||||||
```
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# Gopeed 贡献指南
|
|
||||||
|
|
||||||
首先感谢您对贡献代码感兴趣,这份指南将帮助您更好的参与到 Gopeed 的开发中来。
|
|
||||||
|
|
||||||
## 分支说明
|
|
||||||
|
|
||||||
本项目只有一个主分支,即 `main` 分支,如果您想要参与到 Gopeed 的开发中来,请先 fork 本项目,然后在您的 fork 项目中进行开发,开发完成后再向本项目提交
|
|
||||||
PR,合并到 `main` 分支。
|
|
||||||
|
|
||||||
## 本地开发
|
|
||||||
|
|
||||||
建议通过 web 端进行开发调试,首先启动后端服务,通过命令行 `go run cmd/api/main.go` 启动 ,服务启动默认端口为 `9999`,然后以 `debug` 模式启动前端
|
|
||||||
flutter 项目即可运行。
|
|
||||||
|
|
||||||
## 翻译
|
|
||||||
|
|
||||||
Gopeed 的国际化文件位于 `ui/flutter/assets/locales` 目录下,只需要在该目录下添加对应的语言文件即可。
|
|
||||||
|
|
||||||
编辑locales后请运行以下命令:
|
|
||||||
|
|
||||||
```
|
|
||||||
get generate locales
|
|
||||||
```
|
|
||||||
|
|
||||||
请注意以 `en_US.json` 为参照进行翻译。
|
|
||||||
|
|
||||||
## flutter开发
|
|
||||||
|
|
||||||
每次提交前请务必`dart format ./ui/flutter`
|
|
||||||
|
|
||||||
如果要编辑api/models,请打开build_runner watcher:
|
|
||||||
|
|
||||||
```
|
|
||||||
flutter pub run build_runner watch
|
|
||||||
```
|
|
||||||
|
|
||||||
适用get-cli 命令:
|
|
||||||
|
|
||||||
```
|
|
||||||
create:
|
|
||||||
controller: Generate controller
|
|
||||||
page: Use to generate pages
|
|
||||||
view: Generate view
|
|
||||||
generate:
|
|
||||||
locales: Generate translation file from json files
|
|
||||||
model: generate Class model from json
|
|
||||||
```
|
|
||||||
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
FROM cirrusci/flutter:3.7.7 AS flutter
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./ui/flutter/pubspec.yaml ./ui/flutter/pubspec.lock ./
|
|
||||||
RUN flutter pub get
|
|
||||||
COPY ./ui/flutter ./
|
|
||||||
RUN flutter build web
|
|
||||||
|
|
||||||
FROM golang:1.19.3 AS go
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./go.mod ./go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
COPY . .
|
|
||||||
COPY --from=flutter /app/build/web ./cmd/web/dist
|
|
||||||
RUN CGO_ENABLED=0 go build -tags nosqlite,web -ldflags="-s -w" -o dist/gopeed github.com/GopeedLab/gopeed/cmd/web
|
|
||||||
|
|
||||||
FROM alpine:3.14.2
|
|
||||||
LABEL maintainer="monkeyWie"
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=go /app/dist/gopeed ./
|
|
||||||
EXPOSE 9999
|
|
||||||
ENTRYPOINT ["./gopeed"]
|
|
||||||
@@ -1,158 +1,20 @@
|
|||||||
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
## gopeed
|
||||||
[](https://codecov.io/gh/GopeedLab/gopeed)
|
支持多协议(HTTP、BitTorrent)下载的客户端,提供命令行、RESTful API、WebSocket、Go类库方式来使用。
|
||||||
[](https://github.com/GopeedLab/gopeed/releases)
|
|
||||||
[](https://github.com/GopeedLab/gopeed/blob/main/.donate/index.md#donate)
|
|
||||||
[](https://discord.gg/ZUJqJrwCGB)
|
|
||||||
|
|
||||||

|
## TODO
|
||||||
|
- [x] HTTP下载实现
|
||||||
|
- [ ] BitTorrent下载实现
|
||||||
|
- [x] .torrent文件解析
|
||||||
|
- [x] tracker协议实现
|
||||||
|
- [x] peer wire protocol协议实现
|
||||||
|
- [ ] DHT协议实现
|
||||||
|
- [ ] 磁力链接支持
|
||||||
|
- [ ] uTP协议实现
|
||||||
|
- [ ] 下载接口抽象(不关心具体协议)
|
||||||
|
- [ ] 支持自定义配置
|
||||||
|
- [ ] 限速功能实现
|
||||||
|
- [ ] 命令行工具提供
|
||||||
|
- [ ] RESTful服务提供
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md)
|
## 参与
|
||||||
|
由于项目目前还未定型,代码可能随时有大的调整,所以暂不接受PR,当然如果有什么好的想法可以在issue区提出来。
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Gopeed (full name Go Speed), a high-speed downloader developed by `Golang` + `Flutter`, supports (HTTP, BitTorrent, Magnet) protocol, and supports all platforms.
|
|
||||||
|
|
||||||
Visit ✈ [Official Website](https://gopeed.com) | 📖 [Develop Docs](https://docs.gopeed.com)
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
**Supported platforms**
|
|
||||||
|
|
||||||
- [x] windows
|
|
||||||
- [x] macos
|
|
||||||
- [x] linux
|
|
||||||
- [x] android
|
|
||||||
- [ ] ios
|
|
||||||
- [x] web
|
|
||||||
- [x] docker
|
|
||||||
|
|
||||||
[Download](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> Tips: If the macos open failed, please execute the `xattr -d com.apple.quarantine /Applications/Gopeed.app` command in the terminal
|
|
||||||
|
|
||||||
### Command tool
|
|
||||||
|
|
||||||
use `go install`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
#### Start directly
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/download liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Using Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Access Gopeed
|
|
||||||
|
|
||||||
When the docker container is running, you can access the web page through `http://localhost:9999`.
|
|
||||||
|
|
||||||
> Tip: Modify the download path to `/download` on the setting page to access the downloaded files on the host.
|
|
||||||
|
|
||||||
## Donate
|
|
||||||
|
|
||||||
If you like this project, please consider [donating](/.donate/index.md#donate) to support the development of this project, thank you!
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
This project is divided into two parts, the front end uses `flutter`, the back end uses `Golang`, and the two sides communicate through the `http` protocol. On the unix system, `unix socket` is used, and on the windows system, `tcp` protocol is used.
|
|
||||||
|
|
||||||
> The front code is located in the `ui/flutter` directory.
|
|
||||||
|
|
||||||
### Environment
|
|
||||||
|
|
||||||
1. Golang 1.19+
|
|
||||||
2. Flutter 3.7+
|
|
||||||
|
|
||||||
### Clone
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone [email protected]:monkeyWie/gopeed.git
|
|
||||||
```
|
|
||||||
|
|
||||||
### Contributing
|
|
||||||
|
|
||||||
Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md)
|
|
||||||
|
|
||||||
### Build
|
|
||||||
|
|
||||||
#### Desktop
|
|
||||||
|
|
||||||
First, you need to configure the environment according to the [flutter desktop official website document](https://docs.flutter.dev/development/platform-integration/desktop), and then you need to prepare the `cgo` environment, which can be searched for yourself.
|
|
||||||
|
|
||||||
command:
|
|
||||||
|
|
||||||
- windows
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build windows
|
|
||||||
```
|
|
||||||
|
|
||||||
- macos
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/macos/Frameworks/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build macos
|
|
||||||
```
|
|
||||||
|
|
||||||
- linux
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build linux
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Mobile
|
|
||||||
|
|
||||||
Same as before, you also need to prepare the `cgo` environment, and then install `gomobile`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
|
||||||
go get golang.org/x/mobile/bind
|
|
||||||
gomobile init
|
|
||||||
```
|
|
||||||
|
|
||||||
command:
|
|
||||||
|
|
||||||
- android
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build apk
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Web
|
|
||||||
|
|
||||||
command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build web
|
|
||||||
cd ../../
|
|
||||||
rm -rf cmd/web/dist
|
|
||||||
cp -r ui/flutter/build/web cmd/web/dist
|
|
||||||
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
|
||||||
go run cmd/web/main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[GPLv3](LICENSE)
|
|
||||||
-157
@@ -1,157 +0,0 @@
|
|||||||
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
|
||||||
[](https://codecov.io/gh/GopeedLab/gopeed)
|
|
||||||
[](https://github.com/GopeedLab/gopeed/releases)
|
|
||||||
[](https://github.com/GopeedLab/gopeed/blob/main/.donate/index.md#donate)
|
|
||||||
[](https://discord.gg/ZUJqJrwCGB)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md)
|
|
||||||
|
|
||||||
## 介绍
|
|
||||||
|
|
||||||
Gopeed(全称 Go Speed),是一款由`Golang`+`Flutter`开发的高速下载器,支持(HTTP、BitTorrent、Magnet)协议下载,并且支持全平台使用。
|
|
||||||
|
|
||||||
访问 ✈ [官方网站](https://gopeed.com/zh-CN) | 📖 [开发文档](https://docs.gopeed.com/zh/)
|
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
**已支持平台**
|
|
||||||
|
|
||||||
- [x] windows
|
|
||||||
- [x] macos
|
|
||||||
- [x] linux
|
|
||||||
- [x] android
|
|
||||||
- [ ] ios
|
|
||||||
- [x] web
|
|
||||||
- [x] docker
|
|
||||||
|
|
||||||
[前往下载](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> 注:macos 版本运行如果提示损坏,请在终端执行 `xattr -d com.apple.quarantine /Applications/Gopeed.app` 命令
|
|
||||||
|
|
||||||
### 命令行工具
|
|
||||||
|
|
||||||
使用`go install`安装:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
#### 直接运行
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/download liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用 Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 访问服务
|
|
||||||
|
|
||||||
当 docker 容器运行时,可以通过 `http://localhost:9999` 访问 web 页面。
|
|
||||||
> 提示:在设置页面把下载路径修改为 `/download` 以便在宿主机访问下载完的文件。
|
|
||||||
|
|
||||||
## 打赏
|
|
||||||
|
|
||||||
如果觉得项目对你有帮助,请考虑[打赏](/.donate/index.md#donate)以支持这个项目的发展,非常感谢!
|
|
||||||
|
|
||||||
## 界面展示
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 开发
|
|
||||||
|
|
||||||
本项目分为前端和后端两个部分,前端使用`flutter`,后端使用`Golang`,两边通过`http`协议进行通讯,在 unix 系统下,使用的是`unix socket`,在 windows 系统下,使用的是`tcp`协议。
|
|
||||||
|
|
||||||
> 前端代码位于`ui/flutter`目录下。
|
|
||||||
|
|
||||||
### 环境要求
|
|
||||||
|
|
||||||
1. Golang 1.19+
|
|
||||||
2. Flutter 3.7+
|
|
||||||
|
|
||||||
### 克隆项目
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone [email protected]:monkeyWie/gopeed.git
|
|
||||||
```
|
|
||||||
|
|
||||||
### 贡献代码
|
|
||||||
|
|
||||||
请参考[贡献指南](CONTRIBUTING_zh-CN.md)
|
|
||||||
|
|
||||||
### 编译
|
|
||||||
|
|
||||||
#### 桌面端
|
|
||||||
|
|
||||||
首先需要按照[flutter desktop 官网文档](https://docs.flutter.dev/development/platform-integration/desktop)进行环境配置,然后需要准备好`cgo`环境,具体可以自行搜索。
|
|
||||||
|
|
||||||
构建命令:
|
|
||||||
|
|
||||||
- windows
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build windows
|
|
||||||
```
|
|
||||||
|
|
||||||
- macos
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/macos/Frameworks/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build macos
|
|
||||||
```
|
|
||||||
|
|
||||||
- linux
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build linux
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 移动端
|
|
||||||
|
|
||||||
同样的也是需要准备好`cgo`环境,接着安装`gomobile`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
|
||||||
go get golang.org/x/mobile/bind
|
|
||||||
gomobile init
|
|
||||||
```
|
|
||||||
|
|
||||||
构建命令:
|
|
||||||
|
|
||||||
- android
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build apk
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Web 端
|
|
||||||
|
|
||||||
构建命令:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ui/flutter
|
|
||||||
flutter build web
|
|
||||||
cd ../../
|
|
||||||
rm -rf cmd/web/dist
|
|
||||||
cp -r ui/flutter/build/web cmd/web/dist
|
|
||||||
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
|
||||||
go run cmd/web/main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
## 开源许可
|
|
||||||
|
|
||||||
基于 [GPLv3](LICENSE) 协议开源。
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB |
@@ -1,30 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/download"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
finallyCh := make(chan error)
|
|
||||||
_, err := download.Boot().
|
|
||||||
URL("https://www.baidu.com/index.html").
|
|
||||||
Listener(func(event *download.Event) {
|
|
||||||
if event.Key == download.EventKeyFinally {
|
|
||||||
finallyCh <- event.Err
|
|
||||||
}
|
|
||||||
}).
|
|
||||||
Create(&base.Options{
|
|
||||||
Connections: 8,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
err = <-finallyCh
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("download fail:%v\n", err)
|
|
||||||
} else {
|
|
||||||
fmt.Println("download success")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {}
|
|
||||||
|
|
||||||
//export Start
|
|
||||||
func Start(cfg *C.char) (int, *C.char) {
|
|
||||||
var config model.StartConfig
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(cfg)), &config); err != nil {
|
|
||||||
return 0, C.CString(err.Error())
|
|
||||||
}
|
|
||||||
realPort, err := rest.Start(&config)
|
|
||||||
if err != nil {
|
|
||||||
return 0, C.CString(err.Error())
|
|
||||||
}
|
|
||||||
return realPort, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//export Stop
|
|
||||||
func Stop() {
|
|
||||||
rest.Stop()
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package libgopeed
|
|
||||||
|
|
||||||
// #cgo LDFLAGS: -static-libstdc++
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Start(cfg string) (int, error) {
|
|
||||||
var config model.StartConfig
|
|
||||||
if err := json.Unmarshal([]byte(cfg), &config); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return rest.Start(&config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Stop() {
|
|
||||||
rest.Stop()
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"github.com/GopeedLab/gopeed/cmd"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cfg := &model.StartConfig{
|
|
||||||
Network: "tcp",
|
|
||||||
Address: "127.0.0.1:9999",
|
|
||||||
Storage: model.StorageBolt,
|
|
||||||
}
|
|
||||||
cmd.Start(cfg)
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
_______ ______ .______ _______ _______ _______
|
|
||||||
/ _____| / __ \ | _ \ | ____|| ____|| \
|
|
||||||
| | __ | | | | | |_) | | |__ | |__ | .--. |
|
|
||||||
| | |_ | | | | | | ___/ | __| | __| | | | |
|
|
||||||
| |__| | | `--' | | | | |____ | |____ | '--' |
|
|
||||||
\______| \______/ | _| |_______||_______||_______/
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
url string
|
|
||||||
connections *int
|
|
||||||
dir *string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse() *args {
|
|
||||||
dir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
var args args
|
|
||||||
args.connections = flag.Int("C", 16, "Concurrent connections.")
|
|
||||||
args.dir = flag.String("D", dir, "Store directory.")
|
|
||||||
flag.Parse()
|
|
||||||
t := flag.Args()
|
|
||||||
if len(t) > 0 {
|
|
||||||
args.url = t[0]
|
|
||||||
} else {
|
|
||||||
gPrintln("missing url parameter, for example: gopeed https://www.google.com or gopeed bt.torrent or gopeed magnet:?xt=urn:btih:...")
|
|
||||||
gPrintln("try 'gopeed -h' for more information")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return &args
|
|
||||||
}
|
|
||||||
|
|
||||||
func gPrint(msg string) {
|
|
||||||
fmt.Print("gopeed: " + msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gPrintln(msg string) {
|
|
||||||
gPrint(msg + "\n")
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/download"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const progressWidth = 20
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
args := parse()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
_, err := download.Boot().
|
|
||||||
URL(args.url).
|
|
||||||
Listener(func(event *download.Event) {
|
|
||||||
if event.Key == download.EventKeyProgress {
|
|
||||||
printProgress(event.Task, "downloading...")
|
|
||||||
}
|
|
||||||
if event.Key == download.EventKeyFinally {
|
|
||||||
var title string
|
|
||||||
if event.Err != nil {
|
|
||||||
title = "fail"
|
|
||||||
} else {
|
|
||||||
title = "complete"
|
|
||||||
}
|
|
||||||
printProgress(event.Task, title)
|
|
||||||
fmt.Println()
|
|
||||||
if event.Err != nil {
|
|
||||||
fmt.Printf("reason: %s", event.Err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Printf("saving path: %s", *args.dir)
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}
|
|
||||||
}).
|
|
||||||
Create(&base.Options{
|
|
||||||
Path: *args.dir,
|
|
||||||
Extra: http.OptsExtra{Connections: *args.connections},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
lastLineLen = 0
|
|
||||||
sb = new(strings.Builder)
|
|
||||||
)
|
|
||||||
|
|
||||||
func printProgress(task *download.Task, title string) {
|
|
||||||
rate := float64(task.Progress.Downloaded) / float64(task.Meta.Res.Size)
|
|
||||||
completeWidth := int(progressWidth * rate)
|
|
||||||
speed := util.ByteFmt(task.Progress.Speed)
|
|
||||||
totalSize := util.ByteFmt(task.Meta.Res.Size)
|
|
||||||
sb.WriteString(fmt.Sprintf("\r%s [", title))
|
|
||||||
for i := 0; i < progressWidth; i++ {
|
|
||||||
if i < completeWidth {
|
|
||||||
sb.WriteString("■")
|
|
||||||
} else {
|
|
||||||
sb.WriteString("□")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.WriteString(fmt.Sprintf("] %.1f%% %s/s %s", rate*100, speed, totalSize))
|
|
||||||
if lastLineLen != 0 {
|
|
||||||
paddingLen := lastLineLen - sb.Len()
|
|
||||||
if paddingLen > 0 {
|
|
||||||
sb.WriteString(strings.Repeat(" ", paddingLen))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastLineLen = sb.Len()
|
|
||||||
fmt.Print(sb.String())
|
|
||||||
sb.Reset()
|
|
||||||
}
|
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/monkeyWie/gopeed-core/download"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
downloader := buildDownloader()
|
||||||
|
res, err := downloader.Resolve(&common.Request{
|
||||||
|
URL: "http://192.168.200.163:8088/docker-compose",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = downloader.Create(res, &common.Options{
|
||||||
|
Path: "E:\\test\\gopeed\\http",
|
||||||
|
Connections: 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildDownloader() *download.Downloader {
|
||||||
|
return download.NewDownloader(&http.Fetcher{BaseFetcher: &common.BaseFetcher{}})
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"fmt"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/download"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed banner.txt
|
|
||||||
var banner string
|
|
||||||
|
|
||||||
func Start(cfg *model.StartConfig) {
|
|
||||||
fmt.Println(banner)
|
|
||||||
srv, listener, err := rest.BuildServer(cfg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
exist, _, err := rest.Downloader.GetConfig()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if !exist {
|
|
||||||
// Set default download dir to user download dir
|
|
||||||
userDir, err := os.UserHomeDir()
|
|
||||||
if err == nil {
|
|
||||||
downloadDir := filepath.Join(userDir, "Downloads")
|
|
||||||
rest.Downloader.PutConfig(&download.DownloaderStoreConfig{
|
|
||||||
DownloadDir: downloadDir,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
fmt.Printf("Server start success on http://%s\n", listener.Addr().String())
|
|
||||||
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
//go:build web
|
|
||||||
// +build web
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"github.com/GopeedLab/gopeed/cmd"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
|
||||||
"io/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed dist/*
|
|
||||||
var dist embed.FS
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
sub, err := fs.Sub(dist, "dist")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
cfg := &model.StartConfig{
|
|
||||||
Network: "tcp",
|
|
||||||
Address: "0.0.0.0:9999",
|
|
||||||
Storage: model.StorageBolt,
|
|
||||||
WebEnable: true,
|
|
||||||
WebFS: sub,
|
|
||||||
}
|
|
||||||
cmd.Start(cfg)
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
gopeed:
|
|
||||||
container_name: gopeed
|
|
||||||
ports:
|
|
||||||
- 9999:9999 # HTTP port (host:container)
|
|
||||||
image: liwei2633/gopeed
|
|
||||||
volumes:
|
|
||||||
- ~/Downloads:/download # replace with your prefer path
|
|
||||||
restart: unless-stopped
|
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
package base
|
package common
|
||||||
|
|
||||||
type Status string
|
import "errors"
|
||||||
|
|
||||||
|
type Status int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DownloadStatusReady Status = "ready"
|
DownloadStatusReady Status = iota
|
||||||
DownloadStatusRunning Status = "running"
|
DownloadStatusStart
|
||||||
DownloadStatusPause Status = "pause"
|
DownloadStatusPause
|
||||||
DownloadStatusError Status = "error"
|
DownloadStatusError
|
||||||
DownloadStatusDone Status = "done"
|
DownloadStatusDone
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -21,3 +23,8 @@ const (
|
|||||||
|
|
||||||
HttpHeaderRangeFormat = "bytes=%d-%d"
|
HttpHeaderRangeFormat = "bytes=%d-%d"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
PauseErr = errors.New("pause")
|
||||||
|
DeleteErr = errors.New("delete")
|
||||||
|
)
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 下载请求
|
||||||
|
type Request struct {
|
||||||
|
// 下载链接
|
||||||
|
URL string
|
||||||
|
// 附加信息
|
||||||
|
Extra interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 资源信息
|
||||||
|
type Resource struct {
|
||||||
|
Req *Request
|
||||||
|
// 资源总大小
|
||||||
|
Size int64
|
||||||
|
// 是否支持断点下载
|
||||||
|
Range bool
|
||||||
|
// 资源所包含的文件列表
|
||||||
|
Files []*FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
// 保存文件名
|
||||||
|
Name string
|
||||||
|
// 保存目录
|
||||||
|
Path string
|
||||||
|
// 并发连接数
|
||||||
|
Connections int
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileInfo struct {
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Process interface {
|
||||||
|
Start() error
|
||||||
|
Pause() error
|
||||||
|
Continue() error
|
||||||
|
Delete() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileCreator interface {
|
||||||
|
Create(name string, size int64) (file *os.File, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
Files map[string]*os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController() *Controller {
|
||||||
|
return &Controller{Files: make(map[string]*os.File)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Touch(name string, size int64) (file *os.File, err error) {
|
||||||
|
if size > 0 {
|
||||||
|
err := os.Truncate(name, size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
file, err = os.OpenFile(name, os.O_RDWR, 0666)
|
||||||
|
} else {
|
||||||
|
file, err = os.Create(name)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.Files[name] = file
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Open(name string) (file *os.File, err error) {
|
||||||
|
file, err = os.OpenFile(name, os.O_RDWR, 0666)
|
||||||
|
if err == nil {
|
||||||
|
c.Files[name] = file
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Write(name string, offset int64, buf []byte) (int, error) {
|
||||||
|
return c.Files[name].WriteAt(buf, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Close(name string) error {
|
||||||
|
err := c.Files[name].Close()
|
||||||
|
delete(c.Files, name)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) ContextDialer() (proxy.Dialer, error) {
|
||||||
|
// return proxy.SOCKS5("tpc", "127.0.0.1:9999", nil, nil)
|
||||||
|
var dialer proxy.Dialer
|
||||||
|
return &DialerWarp{dialer: dialer}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DialerWarp struct {
|
||||||
|
dialer proxy.Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnWarp struct {
|
||||||
|
conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) Read(b []byte) (n int, err error) {
|
||||||
|
return c.conn.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) Write(b []byte) (n int, err error) {
|
||||||
|
return c.conn.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) Close() error {
|
||||||
|
return c.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) LocalAddr() net.Addr {
|
||||||
|
return c.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) RemoteAddr() net.Addr {
|
||||||
|
return c.conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) SetDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) SetReadDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnWarp) SetWriteDeadline(t time.Time) error {
|
||||||
|
return c.conn.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialerWarp) Dial(network, addr string) (c net.Conn, err error) {
|
||||||
|
conn, err := d.dialer.Dial(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ConnWarp{conn: conn}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
// 对应协议的下载支持
|
||||||
|
type Fetcher interface {
|
||||||
|
BaseFetch
|
||||||
|
// 支持的协议列表
|
||||||
|
Protocols() []string
|
||||||
|
// 解析请求
|
||||||
|
Resolve(req *Request) (*Resource, error)
|
||||||
|
// 创建任务
|
||||||
|
Create(res *Resource, opts *Options) (Process, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseFetch interface {
|
||||||
|
InitCtl(ctl *Controller)
|
||||||
|
GetCtl() *Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseFetcher struct {
|
||||||
|
ctl *Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseFetcher) InitCtl(ctl *Controller) {
|
||||||
|
b.ctl = ctl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseFetcher) GetCtl() *Controller {
|
||||||
|
return b.ctl
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package download
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskInfo struct {
|
||||||
|
ID string
|
||||||
|
Res *common.Resource
|
||||||
|
Opts *common.Options
|
||||||
|
Status common.Status
|
||||||
|
Files map[string]*common.FileInfo
|
||||||
|
|
||||||
|
process common.Process
|
||||||
|
}
|
||||||
|
|
||||||
|
type Downloader struct {
|
||||||
|
fetches map[string]common.Fetcher
|
||||||
|
tasks map[string]*TaskInfo
|
||||||
|
*common.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDownloader(fetchers ...common.Fetcher) *Downloader {
|
||||||
|
d := &Downloader{Controller: common.NewController()}
|
||||||
|
d.fetches = make(map[string]common.Fetcher)
|
||||||
|
for _, f := range fetchers {
|
||||||
|
for _, p := range f.Protocols() {
|
||||||
|
d.fetches[strings.ToUpper(p)] = f
|
||||||
|
}
|
||||||
|
f.InitCtl(d.Controller)
|
||||||
|
}
|
||||||
|
d.tasks = make(map[string]*TaskInfo)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) getFetcher(URL string) (common.Fetcher, error) {
|
||||||
|
url, err := url.Parse(URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if fetch, ok := d.fetches[strings.ToUpper(url.Scheme)]; ok {
|
||||||
|
return fetch, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("unsupported protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) Resolve(req *common.Request) (*common.Resource, error) {
|
||||||
|
fetcher, err := d.getFetcher(req.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fetcher.Resolve(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) Create(res *common.Resource, opts *common.Options) error {
|
||||||
|
fetcher, err := d.getFetcher(res.Req.URL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
process, err := fetcher.Create(res, opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
id := uuid.New().String()
|
||||||
|
d.tasks[id] = &TaskInfo{
|
||||||
|
ID: id,
|
||||||
|
Res: res,
|
||||||
|
Opts: opts,
|
||||||
|
Status: common.DownloadStatusReady,
|
||||||
|
process: process,
|
||||||
|
}
|
||||||
|
return process.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) Pause(id string) {
|
||||||
|
d.tasks[id].process.Pause()
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package download
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDownloader_Resolve(t *testing.T) {
|
||||||
|
downloader := buildDownloader()
|
||||||
|
res, err := downloader.Resolve(&common.Request{
|
||||||
|
URL: "http://192.168.200.163:8088/docker-compose",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDownloader_Create(t *testing.T) {
|
||||||
|
downloader := buildDownloader()
|
||||||
|
res, err := downloader.Resolve(&common.Request{
|
||||||
|
URL: "http://192.168.200.163:8088/docker-compose",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = downloader.Create(res, &common.Options{
|
||||||
|
Path: "E:\\test\\gopeed\\http",
|
||||||
|
Connections: 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildDownloader() *Downloader {
|
||||||
|
return NewDownloader(&http.Fetcher{BaseFetcher: &common.BaseFetcher{}})
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package file_allocate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileAllocate interface {
|
||||||
|
Allocate(name string, size int64) (file *os.File, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultFileAllocator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DefaultFileAllocator) Allocate(name string, size int64) (file *os.File, err error) {
|
||||||
|
err = os.Truncate(name, size)
|
||||||
|
file, err = os.OpenFile(name, os.O_RDWR, 0644)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package file_allocate
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type PreFileAllocator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PreFileAllocator) Allocate(name string, size int64) (file *os.File, err error) {
|
||||||
|
err = os.Truncate(name, size)
|
||||||
|
file, err = os.OpenFile(name, os.O_RDWR, 0644)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/http/model"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestError struct {
|
||||||
|
Code int
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequestError(code int, msg string) *RequestError {
|
||||||
|
return &RequestError{Code: code, Msg: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (re *RequestError) Error() string {
|
||||||
|
return fmt.Sprintf("http request fail,code:%d", re.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Fetcher struct {
|
||||||
|
*common.BaseFetcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFetcher() *Fetcher {
|
||||||
|
return &Fetcher{BaseFetcher: &common.BaseFetcher{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Fetcher) Protocols() []string {
|
||||||
|
return []string{"HTTP", "HTTPS"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Fetcher) Resolve(req *common.Request) (*common.Resource, error) {
|
||||||
|
httpReq, err := BuildRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client := BuildClient()
|
||||||
|
// 只访问一个字节,测试资源是否支持Range请求
|
||||||
|
httpReq.Header.Set(common.HttpHeaderRange, fmt.Sprintf(common.HttpHeaderRangeFormat, 0, 0))
|
||||||
|
httpResp, err := client.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 拿到响应头就关闭,不用加defer
|
||||||
|
httpResp.Body.Close()
|
||||||
|
res := &common.Resource{
|
||||||
|
Req: req,
|
||||||
|
Range: false,
|
||||||
|
Files: []*common.FileInfo{},
|
||||||
|
}
|
||||||
|
if common.HttpCodePartialContent == httpResp.StatusCode {
|
||||||
|
// 返回206响应码表示支持断点下载
|
||||||
|
res.Range = true
|
||||||
|
// 解析资源大小: bytes 0-1000/1001 => 1001
|
||||||
|
contentTotal := subLastSlash(httpResp.Header.Get(common.HttpHeaderContentRange))
|
||||||
|
if contentTotal != "" {
|
||||||
|
parse, err := strconv.ParseInt(contentTotal, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.Size = parse
|
||||||
|
}
|
||||||
|
} else if common.HttpCodeOK == httpResp.StatusCode {
|
||||||
|
// 返回200响应码,不支持断点下载,通过Content-Length头获取文件大小,获取不到的话可能是chunked编码
|
||||||
|
contentLength := httpResp.Header.Get(common.HttpHeaderContentLength)
|
||||||
|
if contentLength != "" {
|
||||||
|
parse, err := strconv.ParseInt(contentLength, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.Size = parse
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, NewRequestError(httpResp.StatusCode, httpResp.Status)
|
||||||
|
}
|
||||||
|
file := &common.FileInfo{
|
||||||
|
Size: res.Size,
|
||||||
|
}
|
||||||
|
contentDisposition := httpResp.Header.Get(common.HttpHeaderContentDisposition)
|
||||||
|
if contentDisposition != "" {
|
||||||
|
_, params, _ := mime.ParseMediaType(contentDisposition)
|
||||||
|
filename := params["filename"]
|
||||||
|
if filename != "" {
|
||||||
|
file.Name = filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Get file name by URL
|
||||||
|
if file.Name == "" {
|
||||||
|
parse, err := url.Parse(req.URL)
|
||||||
|
if err == nil {
|
||||||
|
// e.g. /files/test.txt => test.txt
|
||||||
|
file.Name = subLastSlash(parse.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unknown file name
|
||||||
|
if file.Name == "" {
|
||||||
|
file.Name = "unknown"
|
||||||
|
}
|
||||||
|
res.Files = append(res.Files, file)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Fetcher) Create(res *common.Resource, opts *common.Options) (common.Process, error) {
|
||||||
|
if opts.Connections != 1 && !res.Range {
|
||||||
|
opts.Connections = 1
|
||||||
|
}
|
||||||
|
return NewProcess(h, res, opts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func subLastSlash(str string) string {
|
||||||
|
if str == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
index := strings.LastIndex(str, "/")
|
||||||
|
if index != -1 {
|
||||||
|
return str[index+1:]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildClient() *http.Client {
|
||||||
|
// Cookie handle
|
||||||
|
jar, _ := cookiejar.New(nil)
|
||||||
|
return &http.Client{
|
||||||
|
Jar: jar,
|
||||||
|
Timeout: time.Second * 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildRequest(req *common.Request) (*http.Request, error) {
|
||||||
|
url, err := url.Parse(req.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
httpReq := &http.Request{
|
||||||
|
URL: url,
|
||||||
|
Header: map[string][]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Extra != nil {
|
||||||
|
if extra, ok := req.Extra.(model.Extra); ok {
|
||||||
|
if extra.Method != "" {
|
||||||
|
httpReq.Method = extra.Method
|
||||||
|
} else {
|
||||||
|
httpReq.Method = http.MethodGet
|
||||||
|
}
|
||||||
|
if len(extra.Header) > 0 {
|
||||||
|
for k, v := range extra.Header {
|
||||||
|
httpReq.Header[k] = []string{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpReq.Body = ioutil.NopCloser(bytes.NewBufferString(extra.Body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpReq, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testDir = "./"
|
||||||
|
const buildSize = 200 * 1024 * 1024
|
||||||
|
const buildName = "build.data"
|
||||||
|
const buildFile = testDir + buildName
|
||||||
|
const downloadName = "download.data"
|
||||||
|
const downloadFile = testDir + downloadName
|
||||||
|
|
||||||
|
func TestFetcher_Resolve(t *testing.T) {
|
||||||
|
testResolve(startTestFileServer, &common.Resource{
|
||||||
|
Size: buildSize,
|
||||||
|
Range: true,
|
||||||
|
Files: []*common.FileInfo{
|
||||||
|
{
|
||||||
|
Name: buildName,
|
||||||
|
Size: buildSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
|
testResolve(startTestChunkedServer, &common.Resource{
|
||||||
|
Size: 0,
|
||||||
|
Range: false,
|
||||||
|
Files: []*common.FileInfo{
|
||||||
|
{
|
||||||
|
Name: buildName,
|
||||||
|
Size: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testResolve(startTestServer func() net.Listener, want *common.Resource, t *testing.T) {
|
||||||
|
listener := startTestServer()
|
||||||
|
defer listener.Close()
|
||||||
|
fetcher := NewFetcher()
|
||||||
|
res, err := fetcher.Resolve(&common.Request{
|
||||||
|
URL: "http://" + listener.Addr().String() + "/" + buildName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
res.Req = nil
|
||||||
|
if !reflect.DeepEqual(want, res) {
|
||||||
|
t.Errorf("Resolve error = %v, want %v", res, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadNormal(t *testing.T) {
|
||||||
|
listener := startTestFileServer()
|
||||||
|
defer listener.Close()
|
||||||
|
// 正常下载
|
||||||
|
downloadNormal(listener, 1, t)
|
||||||
|
downloadNormal(listener, 5, t)
|
||||||
|
downloadNormal(listener, 8, t)
|
||||||
|
downloadNormal(listener, 16, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadContinue(t *testing.T) {
|
||||||
|
listener := startTestFileServer()
|
||||||
|
defer listener.Close()
|
||||||
|
// 暂停继续
|
||||||
|
downloadContinue(listener, 1, t)
|
||||||
|
fmt.Println("d1")
|
||||||
|
downloadContinue(listener, 5, t)
|
||||||
|
fmt.Println("d5")
|
||||||
|
downloadContinue(listener, 8, t)
|
||||||
|
fmt.Println("d8")
|
||||||
|
downloadContinue(listener, 16, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadChunked(t *testing.T) {
|
||||||
|
listener := startTestChunkedServer()
|
||||||
|
defer listener.Close()
|
||||||
|
// chunked编码下载
|
||||||
|
//downloadNormal(listener, 1, t)
|
||||||
|
downloadContinue(listener, 1, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadRetry(t *testing.T) {
|
||||||
|
listener := startTestRetryServer()
|
||||||
|
defer listener.Close()
|
||||||
|
// chunked编码下载
|
||||||
|
downloadNormal(listener, 1, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadError(t *testing.T) {
|
||||||
|
listener := startTestErrorServer()
|
||||||
|
defer listener.Close()
|
||||||
|
// chunked编码下载
|
||||||
|
downloadError(listener, 1, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestFileServer() net.Listener {
|
||||||
|
return startTestServer(func() http.Handler {
|
||||||
|
return http.FileServer(http.Dir(testDir))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestChunkedServer() net.Listener {
|
||||||
|
return startTestServer(func() http.Handler {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/"+buildName, func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
file, err := os.Open(buildFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
io.Copy(writer, file)
|
||||||
|
})
|
||||||
|
return mux
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestRetryServer() net.Listener {
|
||||||
|
counter := 0
|
||||||
|
return startTestServer(func() http.Handler {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/"+buildName, func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
counter++
|
||||||
|
if counter != 1 && counter < 5 {
|
||||||
|
writer.WriteHeader(500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.Open(buildFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
io.Copy(writer, file)
|
||||||
|
})
|
||||||
|
return mux
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestErrorServer() net.Listener {
|
||||||
|
counter := 0
|
||||||
|
return startTestServer(func() http.Handler {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/"+buildName, func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
counter++
|
||||||
|
if counter != 1 {
|
||||||
|
writer.WriteHeader(500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return mux
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestServer(serverHandle func() http.Handler) net.Listener {
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
file, err := os.Create(buildFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// 随机生成一个文件
|
||||||
|
l := int64(8192)
|
||||||
|
buf := make([]byte, l)
|
||||||
|
size := int64(0)
|
||||||
|
for {
|
||||||
|
_, err := rand.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if size+l >= buildSize {
|
||||||
|
file.WriteAt(buf[0:buildSize-size], size)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
file.WriteAt(buf, size)
|
||||||
|
size += l
|
||||||
|
}
|
||||||
|
server := &http.Server{}
|
||||||
|
server.Handler = serverHandle()
|
||||||
|
go server.Serve(listener)
|
||||||
|
|
||||||
|
return &delFileListener{
|
||||||
|
File: file,
|
||||||
|
Listener: listener,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type delFileListener struct {
|
||||||
|
*os.File
|
||||||
|
net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *delFileListener) Close() error {
|
||||||
|
defer func() {
|
||||||
|
c.File.Close()
|
||||||
|
if err := ifExistAndRemove(c.File.Name()); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
if err := ifExistAndRemove(downloadFile); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return c.Listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifExistAndRemove(name string) error {
|
||||||
|
if _, err := os.Stat(name); !os.IsNotExist(err) {
|
||||||
|
return os.Remove(name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadReady(listener net.Listener, connections int, t *testing.T) common.Process {
|
||||||
|
fetcher := NewFetcher()
|
||||||
|
fetcher.InitCtl(common.NewController())
|
||||||
|
res, err := fetcher.Resolve(&common.Request{
|
||||||
|
URL: "http://" + listener.Addr().String() + "/" + buildName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
process, err := fetcher.Create(res, &common.Options{
|
||||||
|
Name: downloadName,
|
||||||
|
Path: testDir,
|
||||||
|
Connections: connections,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return process
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadNormal(listener net.Listener, connections int, t *testing.T) {
|
||||||
|
process := downloadReady(listener, connections, t)
|
||||||
|
err := process.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
want := fileMd5(buildFile)
|
||||||
|
got := fileMd5(downloadFile)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Download error = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadContinue(listener net.Listener, connections int, t *testing.T) {
|
||||||
|
process := downloadReady(listener, connections, t)
|
||||||
|
go func() {
|
||||||
|
err := process.Start()
|
||||||
|
if err != nil && err != common.PauseErr {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Millisecond * 200)
|
||||||
|
if err := process.Pause(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 200)
|
||||||
|
if err := process.Continue(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
want := fileMd5(buildFile)
|
||||||
|
got := fileMd5(downloadFile)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Download error = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadError(listener net.Listener, connections int, t *testing.T) {
|
||||||
|
process := downloadReady(listener, connections, t)
|
||||||
|
err := process.Start()
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Download error = %v, want %v", err, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileMd5(filePath string) string {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Tell the program to call the following function when the current function returns
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Open a new hash interface to write to
|
||||||
|
hash := md5.New()
|
||||||
|
|
||||||
|
// Copy the file in the hash interface and check for any error
|
||||||
|
if _, err := io.Copy(hash, file); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(hash.Sum(nil))
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Chunk struct {
|
||||||
|
Status common.Status
|
||||||
|
Begin int64
|
||||||
|
End int64
|
||||||
|
Downloaded int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewChunk(begin int64, end int64) *Chunk {
|
||||||
|
return &Chunk{
|
||||||
|
Status: common.DownloadStatusReady,
|
||||||
|
Begin: begin,
|
||||||
|
End: end,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Extra struct {
|
||||||
|
Method string
|
||||||
|
Header map[string]string
|
||||||
|
Body string
|
||||||
|
}
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/common"
|
||||||
|
"github.com/monkeyWie/gopeed-core/download/http/model"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Process struct {
|
||||||
|
fetcher *Fetcher
|
||||||
|
|
||||||
|
res *common.Resource
|
||||||
|
opts *common.Options
|
||||||
|
status common.Status
|
||||||
|
clients []*http.Response
|
||||||
|
chunks []*model.Chunk
|
||||||
|
|
||||||
|
pauseCond *sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProcess(fetcher *Fetcher, res *common.Resource, opts *common.Options) *Process {
|
||||||
|
return &Process{
|
||||||
|
fetcher: fetcher,
|
||||||
|
res: res,
|
||||||
|
opts: opts,
|
||||||
|
status: common.DownloadStatusReady,
|
||||||
|
|
||||||
|
pauseCond: sync.NewCond(&sync.Mutex{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) Start() error {
|
||||||
|
ctl := p.fetcher.GetCtl()
|
||||||
|
// 创建文件
|
||||||
|
name := p.name()
|
||||||
|
_, err := ctl.Touch(name, p.res.Size)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer p.close()
|
||||||
|
p.status = common.DownloadStatusStart
|
||||||
|
if p.res.Range {
|
||||||
|
// 每个连接平均需要下载的分块大小
|
||||||
|
chunkSize := p.res.Size / int64(p.opts.Connections)
|
||||||
|
p.chunks = make([]*model.Chunk, p.opts.Connections)
|
||||||
|
p.clients = make([]*http.Response, p.opts.Connections)
|
||||||
|
for i := 0; i < p.opts.Connections; i++ {
|
||||||
|
var (
|
||||||
|
begin = chunkSize * int64(i)
|
||||||
|
end int64
|
||||||
|
)
|
||||||
|
if i == p.opts.Connections-1 {
|
||||||
|
// 最后一个分块需要保证把文件下载完
|
||||||
|
end = p.res.Size
|
||||||
|
} else {
|
||||||
|
end = begin + chunkSize
|
||||||
|
}
|
||||||
|
chunk := model.NewChunk(begin, end)
|
||||||
|
p.chunks[i] = chunk
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 只支持单连接下载
|
||||||
|
p.chunks = make([]*model.Chunk, 1)
|
||||||
|
p.clients = make([]*http.Response, 1)
|
||||||
|
p.chunks[0] = model.NewChunk(0, 0)
|
||||||
|
}
|
||||||
|
return p.fetch()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) Pause() error {
|
||||||
|
p.pauseCond.L.Lock()
|
||||||
|
defer p.pauseCond.L.Unlock()
|
||||||
|
if common.DownloadStatusStart != p.status {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.status = common.DownloadStatusPause
|
||||||
|
p.stop()
|
||||||
|
// 释放锁,并等待下载结束
|
||||||
|
p.pauseCond.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) Continue() error {
|
||||||
|
if func() bool {
|
||||||
|
p.pauseCond.L.Lock()
|
||||||
|
defer p.pauseCond.L.Unlock()
|
||||||
|
if common.DownloadStatusPause != p.status && common.DownloadStatusError != p.status {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.status = common.DownloadStatusStart
|
||||||
|
return false
|
||||||
|
}() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctl = p.fetcher.GetCtl()
|
||||||
|
name = p.name()
|
||||||
|
)
|
||||||
|
_, err := ctl.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer ctl.Close(name)
|
||||||
|
return p.fetch()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) Delete() error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) close() error {
|
||||||
|
return p.fetcher.GetCtl().Close(p.name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) name() string {
|
||||||
|
// 创建文件
|
||||||
|
var filename = p.opts.Name
|
||||||
|
if filename == "" {
|
||||||
|
filename = p.res.Files[0].Name
|
||||||
|
}
|
||||||
|
return filepath.Join(p.opts.Path, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) fetch() error {
|
||||||
|
errCh := make(chan error, p.opts.Connections)
|
||||||
|
defer close(errCh)
|
||||||
|
|
||||||
|
for i := 0; i < p.opts.Connections; i++ {
|
||||||
|
go func(i int) {
|
||||||
|
errCh <- p.fetchChunk(i, p.name(), p.chunks[i])
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
var retErr error
|
||||||
|
for i := 0; i < p.opts.Connections; i++ {
|
||||||
|
err := <-errCh
|
||||||
|
if err != nil && retErr == nil {
|
||||||
|
retErr = err
|
||||||
|
// 有一个连接失败就立即终止下载
|
||||||
|
if retErr != common.PauseErr {
|
||||||
|
func() {
|
||||||
|
p.pauseCond.L.Lock()
|
||||||
|
defer p.pauseCond.L.Unlock()
|
||||||
|
p.stop()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.pauseCond.Signal()
|
||||||
|
return retErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) stop() {
|
||||||
|
if len(p.clients) > 0 {
|
||||||
|
for _, client := range p.clients {
|
||||||
|
fmt.Println("client close")
|
||||||
|
if client != nil {
|
||||||
|
client.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Process) fetchChunk(index int, name string, chunk *model.Chunk) (err error) {
|
||||||
|
httpReq, err := BuildRequest(p.res.Req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
client = BuildClient()
|
||||||
|
buf = make([]byte, 8192)
|
||||||
|
)
|
||||||
|
// 重试5次
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
var (
|
||||||
|
resp *http.Response
|
||||||
|
retry bool
|
||||||
|
)
|
||||||
|
if p.res.Range {
|
||||||
|
httpReq.Header.Set(common.HttpHeaderRange,
|
||||||
|
fmt.Sprintf(common.HttpHeaderRangeFormat, chunk.Begin+chunk.Downloaded, chunk.End))
|
||||||
|
} else {
|
||||||
|
chunk.Downloaded = 0
|
||||||
|
}
|
||||||
|
err = func() error {
|
||||||
|
p.pauseCond.L.Lock()
|
||||||
|
defer p.pauseCond.L.Unlock()
|
||||||
|
if p.status == common.DownloadStatusPause {
|
||||||
|
return common.PauseErr
|
||||||
|
}
|
||||||
|
resp, err = client.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.clients[index] = resp
|
||||||
|
if resp.StatusCode != common.HttpCodeOK && resp.StatusCode != common.HttpCodePartialContent {
|
||||||
|
err = NewRequestError(resp.StatusCode, resp.Status)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
if err == common.PauseErr {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 请求失败重试
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
retry, err = func() (bool, error) {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
for {
|
||||||
|
n, err := resp.Body.Read(buf)
|
||||||
|
if n > 0 {
|
||||||
|
_, err := p.fetcher.GetCtl().Write(name, chunk.Begin+chunk.Downloaded, buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
chunk.Downloaded += int64(n)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}()
|
||||||
|
if err == nil || !retry {
|
||||||
|
// 下载成功,跳出重试
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
p.chunks[index].Status = common.DownloadStatusError
|
||||||
|
} else {
|
||||||
|
p.chunks[index].Status = common.DownloadStatusDone
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,73 +1,12 @@
|
|||||||
module github.com/GopeedLab/gopeed
|
module github.com/monkeyWie/gopeed-core
|
||||||
|
|
||||||
go 1.19
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/anacrolix/torrent v1.46.0
|
github.com/RoaringBitmap/roaring v0.4.21
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/google/uuid v1.1.1
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
|
||||||
go.etcd.io/bbolt v1.3.6
|
github.com/sirupsen/logrus v1.4.2
|
||||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
|
||||||
crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508 // indirect
|
|
||||||
github.com/RoaringBitmap/roaring v1.0.1-0.20220510143707-3f418c4f42a4 // indirect
|
|
||||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
|
||||||
github.com/anacrolix/chansync v0.3.0 // indirect
|
|
||||||
github.com/anacrolix/dht/v2 v2.16.2-0.20220311024416-dd658f18fd51 // indirect
|
|
||||||
github.com/anacrolix/envpprof v1.2.1 // indirect
|
|
||||||
github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60 // indirect
|
|
||||||
github.com/anacrolix/go-libutp v1.2.0 // indirect
|
|
||||||
github.com/anacrolix/log v0.13.1 // indirect
|
|
||||||
github.com/anacrolix/missinggo v1.3.0 // indirect
|
|
||||||
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.0 // indirect
|
|
||||||
github.com/anacrolix/mmsg v1.0.0 // indirect
|
|
||||||
github.com/anacrolix/multiless v0.2.1-0.20211218050420-533661eef5dc // indirect
|
|
||||||
github.com/anacrolix/stm v0.3.0 // indirect
|
|
||||||
github.com/anacrolix/sync v0.4.0 // indirect
|
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect
|
|
||||||
github.com/anacrolix/utp v0.1.0 // indirect
|
|
||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
|
||||||
github.com/benbjohnson/immutable v0.3.0 // indirect
|
|
||||||
github.com/bits-and-blooms/bitset v1.2.0 // indirect
|
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
|
||||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
|
||||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
|
||||||
github.com/google/btree v1.0.1 // indirect
|
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
|
||||||
github.com/lispad/go-generics-tools v1.0.0 // indirect
|
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
|
||||||
github.com/pion/datachannel v1.5.2 // indirect
|
|
||||||
github.com/pion/dtls/v2 v2.1.2 // indirect
|
|
||||||
github.com/pion/ice/v2 v2.1.20 // indirect
|
|
||||||
github.com/pion/interceptor v0.1.7 // indirect
|
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
|
||||||
github.com/pion/mdns v0.0.5 // indirect
|
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
|
||||||
github.com/pion/rtcp v1.2.9 // indirect
|
|
||||||
github.com/pion/rtp v1.7.4 // indirect
|
|
||||||
github.com/pion/sctp v1.8.2 // indirect
|
|
||||||
github.com/pion/sdp/v3 v3.0.4 // indirect
|
|
||||||
github.com/pion/srtp/v2 v2.0.5 // indirect
|
|
||||||
github.com/pion/stun v0.3.5 // indirect
|
|
||||||
github.com/pion/transport v0.13.0 // indirect
|
|
||||||
github.com/pion/turn/v2 v2.0.6 // indirect
|
|
||||||
github.com/pion/udp v0.1.1 // indirect
|
|
||||||
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 // indirect
|
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686 // indirect
|
|
||||||
github.com/tidwall/btree v1.3.1 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect
|
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 // indirect
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
)
|
)
|
||||||
@@ -1,470 +1,57 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797 h1:yDf7ARQc637HoxDho7xjqdvO5ZA2Yb+xzv/fOnnvZzw=
|
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972 h1:FvAasVrPm/VUO8M0odLDqA9Y7VbALYq3PRAwmWGPw78=
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972/go.mod h1:wGf99xKTJ8f/a8cC1inMqFz9cGEzISLLid5F6i5fI/g=
|
||||||
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508 h1:fILCBBFnjnrQ0whVJlGhfv1E/QiaFDNtGFBObEVRnYg=
|
|
||||||
crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
|
||||||
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
|
||||||
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/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
|
||||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
|
||||||
github.com/RoaringBitmap/roaring v1.0.1-0.20220510143707-3f418c4f42a4 h1:LxR70Si8X8IlYTeKiPReOBt9pla6wEJDlkawfwDdrB0=
|
|
||||||
github.com/RoaringBitmap/roaring v1.0.1-0.20220510143707-3f418c4f42a4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
|
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
|
||||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0=
|
|
||||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
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/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
|
|
||||||
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
|
||||||
github.com/anacrolix/dht/v2 v2.16.2-0.20220311024416-dd658f18fd51 h1:issCwqC43gQ7n0gg9rn0EeVYXnQMI7vlnWub4oidtlU=
|
|
||||||
github.com/anacrolix/dht/v2 v2.16.2-0.20220311024416-dd658f18fd51/go.mod h1:osiyaNrMLG9dw7wUtVMaII/NdCjlXeHjUcYzXnmop68=
|
|
||||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
|
||||||
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
|
||||||
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
|
||||||
github.com/anacrolix/envpprof v1.2.1 h1:25TJe6t/i0AfzzldiGFKCpD+s+dk8lONBcacJZB2rdE=
|
|
||||||
github.com/anacrolix/envpprof v1.2.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
|
||||||
github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60 h1:k4/h2B1gGF+PJGyGHxs8nmHHt1pzWXZWBj6jn4OBlRc=
|
|
||||||
github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
|
||||||
github.com/anacrolix/go-libutp v1.2.0 h1:sjxoB+/ARiKUR7IK/6wLWyADIBqGmu1fm0xo+8Yy7u0=
|
|
||||||
github.com/anacrolix/go-libutp v1.2.0/go.mod h1:RrJ3KcaDcf9Jqp33YL5V/5CBEc6xMc7aJL8wXfuWL50=
|
|
||||||
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
|
||||||
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
|
||||||
github.com/anacrolix/log v0.10.0/go.mod h1:s5yBP/j046fm9odtUTbHOfDUq/zh1W8OkPpJtnX0oQI=
|
|
||||||
github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8/go.mod h1:GmnE2c0nvz8pOIPUSC9Rawgefy1sDXqposC2wgtBZE4=
|
|
||||||
github.com/anacrolix/log v0.13.1 h1:BmVwTdxHd5VcNrLylgKwph4P4wf+5VvPgOK4yi91fTY=
|
|
||||||
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
|
||||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
|
|
||||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
|
||||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
|
||||||
github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
|
||||||
github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
|
||||||
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
|
|
||||||
github.com/anacrolix/missinggo v1.3.0 h1:06HlMsudotL7BAELRZs0yDZ4yVXsHXGi323QBjAVASw=
|
|
||||||
github.com/anacrolix/missinggo v1.3.0/go.mod h1:bqHm8cE8xr+15uVfMG3BFui/TxyB6//H5fwlq/TeqMc=
|
|
||||||
github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw=
|
|
||||||
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY=
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.5.2/go.mod h1:yNvsLrtZYRYCOI+KRH/JM8TodHjtIE/bjOGhQaLOWIE=
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.0 h1:4fzOAAn/VCvfWGviLmh64MPMttrlYew81JdPO7nSHvI=
|
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.0/go.mod h1:2IZIvmRTizALNYFYXsPR7ofXPzJgyBpKZ4kMqMEICkI=
|
|
||||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
|
|
||||||
github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg=
|
|
||||||
github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
|
|
||||||
github.com/anacrolix/multiless v0.2.1-0.20211218050420-533661eef5dc h1:K047jUtd0Xv4SEpv/5DoBgDvj4ZNpT1SOVtMlFpRrh0=
|
|
||||||
github.com/anacrolix/multiless v0.2.1-0.20211218050420-533661eef5dc/go.mod h1:TrCLEZfIDbMVfLoQt5tOoiBS/uq4y8+ojuEVVvTNPX4=
|
|
||||||
github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg=
|
|
||||||
github.com/anacrolix/stm v0.3.0 h1:peQncJSNJtk1YBrFbW0DLKYqll+sa0kOk8EvXRcO+wA=
|
|
||||||
github.com/anacrolix/stm v0.3.0/go.mod h1:spImf/rXwiAUoYYJK1YCZeWkpaHZ3kzjGFjwK5OStfU=
|
|
||||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
|
||||||
github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
|
||||||
github.com/anacrolix/sync v0.4.0 h1:T+MdO/u87ir/ijWsTFsPYw5jVm0SMm4kVpg8t4KF38o=
|
|
||||||
github.com/anacrolix/sync v0.4.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
|
||||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
|
||||||
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
|
||||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
|
||||||
github.com/anacrolix/torrent v1.46.0 h1:m5SGlW4p0dJkqrIh4bCqzcKbKFFmfJorf9LSpSM5dEc=
|
|
||||||
github.com/anacrolix/torrent v1.46.0/go.mod h1:3DE+VA4AgyfKDPjZcIo70D3VFZRo3bfdEBn70CGjca4=
|
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 h1:QAVZ3pN/J4/UziniAhJR2OZ9Ox5kOY2053tBbbqUPYA=
|
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96/go.mod h1:Wa6n8cYIdaG35x15aH3Zy6d03f7P728QfdcDeD/IEOs=
|
|
||||||
github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
|
|
||||||
github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
|
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
|
||||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
|
||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
|
||||||
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
|
||||||
github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw=
|
|
||||||
github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
||||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
|
||||||
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
|
|
||||||
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
|
|
||||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
|
||||||
github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
|
||||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
|
||||||
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
|
||||||
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
|
||||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
|
||||||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
|
||||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e h1:KMs6SK8iDSR1+ZzOK10L5wGPpWDByyvOe5nrqk51g2U=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e/go.mod h1:+AHfJo5+69p+fjvMJTmYajNP9rFBHQcaTDFmuXRRATI=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/lispad/go-generics-tools v1.0.0 h1:pPtt9QERE5sGQfwvLakKe2sjhcNKKsDSnr3939ofj1E=
|
|
||||||
github.com/lispad/go-generics-tools v1.0.0/go.mod h1:stn7X24ZIyFvaSyttafq3VlJzGJJJkUtLYdbgi/gopM=
|
|
||||||
github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0=
|
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
|
||||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
|
||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
||||||
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
|
|
||||||
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
|
|
||||||
github.com/pion/dtls/v2 v2.1.1/go.mod h1:qG3gA7ZPZemBqpEFqRKyURYdKEwFZQCGb7gv9T3ON3Y=
|
|
||||||
github.com/pion/dtls/v2 v2.1.2 h1:22Q1Jk9L++Yo7BIf9130MonNPfPVb+YgdYLeyQotuAA=
|
|
||||||
github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
|
|
||||||
github.com/pion/ice/v2 v2.1.20 h1:xpxXyX5b4WjCh/D905gzBeW/hbJxMEPx2ptVfrhVE6M=
|
|
||||||
github.com/pion/ice/v2 v2.1.20/go.mod h1:hEAldRzBhTtAfvlU1V/2/nLCMvveQWFKPNCop+63/Iw=
|
|
||||||
github.com/pion/interceptor v0.1.7 h1:HThW0tIIKT9RRoDWGURe8rlZVOx0fJHxBHpA0ej0+bo=
|
|
||||||
github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
|
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
|
||||||
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
|
|
||||||
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
|
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
|
||||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
|
||||||
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
|
||||||
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
|
|
||||||
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
|
|
||||||
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
|
||||||
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
|
|
||||||
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
|
||||||
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
|
||||||
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
|
|
||||||
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
|
||||||
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
|
|
||||||
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
|
||||||
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
|
|
||||||
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
|
|
||||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
|
||||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
|
||||||
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
|
||||||
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
|
|
||||||
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
|
|
||||||
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
|
|
||||||
github.com/pion/turn/v2 v2.0.6 h1:AsXjSPR6Im15DMTB39NlfdTY9BQfieANPBjdg/aVNwY=
|
|
||||||
github.com/pion/turn/v2 v2.0.6/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
|
|
||||||
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
|
|
||||||
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
|
|
||||||
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38 h1:+IEql+S+YAj3S5e7Ftl/u4xPcZGG0WwLFsyFj6NRTz4=
|
|
||||||
github.com/pion/webrtc/v3 v3.1.24-0.20220208053747-94262c1b2b38/go.mod h1:L5S/oAhL0Fzt/rnftVQRrP80/j5jygY7XRZzWwFx6P4=
|
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
|
||||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
|
||||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
|
||||||
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686 h1:IJ6Df0uxPDtNoByV0KkzVKNseWvZFCNM/S9UoyOMCSI=
|
|
||||||
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
|
||||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
|
||||||
github.com/tidwall/btree v1.3.1 h1:636+tdVDs8Hjcf35Di260W2xCW4KuoXOKyk9QWOvCpA=
|
|
||||||
github.com/tidwall/btree v1.3.1/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE=
|
|
||||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
|
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
|
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20220928052126-fa6bcb076835 h1:v6yt1xSu+4xV0fPEmB8s2BHdOaoU0SSZrVQzj6pRvqk=
|
|
||||||
golang.org/x/mobile v0.0.0-20220928052126-fa6bcb076835/go.mod h1:M32cGdzp91A8Ex9qQtyZinr19EYxzkFqDjW2oyHzTDQ=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
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.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
|
||||||
golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/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=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
|
|
||||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
|
||||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=
|
|
||||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
GetConfig func(v any) (bool, error)
|
|
||||||
FileController
|
|
||||||
//ContextDialer() (proxy.Dialer, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileController interface {
|
|
||||||
Touch(name string, size int64) (file *os.File, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultFileController struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController() *Controller {
|
|
||||||
return &Controller{
|
|
||||||
FileController: &DefaultFileController{},
|
|
||||||
GetConfig: func(v any) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *DefaultFileController) Touch(name string, size int64) (file *os.File, err error) {
|
|
||||||
dir := filepath.Dir(name)
|
|
||||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file, err = os.Create(name)
|
|
||||||
if err != nil && !errors.Is(err, os.ErrExist) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if size > 0 {
|
|
||||||
err = os.Truncate(name, size)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func (c *DefaultController) ContextDialer() (proxy.Dialer, error) {
|
|
||||||
// return proxy.SOCKS5("tpc", "127.0.0.1:9999", nil, nil)
|
|
||||||
var dialer proxy.Dialer
|
|
||||||
return &DialerWarp{dialer: dialer}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DialerWarp struct {
|
|
||||||
dialer proxy.Dialer
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnWarp struct {
|
|
||||||
conn net.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) Read(b []byte) (n int, err error) {
|
|
||||||
return c.conn.Read(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) Write(b []byte) (n int, err error) {
|
|
||||||
return c.conn.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) Close() error {
|
|
||||||
return c.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) LocalAddr() net.Addr {
|
|
||||||
return c.conn.LocalAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) RemoteAddr() net.Addr {
|
|
||||||
return c.conn.RemoteAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) SetDeadline(t time.Time) error {
|
|
||||||
return c.conn.SetDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) SetReadDeadline(t time.Time) error {
|
|
||||||
return c.conn.SetReadDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnWarp) SetWriteDeadline(t time.Time) error {
|
|
||||||
return c.conn.SetWriteDeadline(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DialerWarp) Dial(network, addr string) (c net.Conn, err error) {
|
|
||||||
conn, err := d.dialer.Dial(network, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &ConnWarp{conn: conn}, nil
|
|
||||||
}*/
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package fetcher
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fetcher defines the interface for a download protocol.
|
|
||||||
// One fetcher for each download task
|
|
||||||
type Fetcher interface {
|
|
||||||
// Name return the name of the protocol.
|
|
||||||
Name() string
|
|
||||||
|
|
||||||
Setup(ctl *controller.Controller) error
|
|
||||||
// Resolve resource info from request
|
|
||||||
Resolve(req *base.Request) error
|
|
||||||
// Create ready to download, but not started
|
|
||||||
Create(opts *base.Options) error
|
|
||||||
Start() error
|
|
||||||
Pause() error
|
|
||||||
Continue() error
|
|
||||||
Close() error
|
|
||||||
|
|
||||||
// Meta returns the meta information of the download.
|
|
||||||
Meta() *FetcherMeta
|
|
||||||
// Progress returns the progress of the download.
|
|
||||||
Progress() Progress
|
|
||||||
// Wait for the download to complete, this method will block until the download is done.
|
|
||||||
Wait() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetcherMeta defines the meta information of a fetcher.
|
|
||||||
type FetcherMeta struct {
|
|
||||||
Req *base.Request `json:"req"`
|
|
||||||
Res *base.Resource `json:"res"`
|
|
||||||
Opts *base.Options `json:"opts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FetcherMeta) Filepath(file *base.FileInfo) string {
|
|
||||||
finalName := m.Opts.Name
|
|
||||||
if finalName == "" {
|
|
||||||
finalName = file.Name
|
|
||||||
}
|
|
||||||
return path.Join(m.Opts.Path, m.Res.RootDir, finalName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetcherBuilder defines the interface for a fetcher builder.
|
|
||||||
type FetcherBuilder interface {
|
|
||||||
// Schemes returns the schemes supported by the fetcher.
|
|
||||||
Schemes() []string
|
|
||||||
// Build returns a new fetcher.
|
|
||||||
Build() Fetcher
|
|
||||||
|
|
||||||
// Store fetcher
|
|
||||||
Store(fetcher Fetcher) (any, error)
|
|
||||||
// Restore fetcher
|
|
||||||
Restore() (v any, f func(meta *FetcherMeta, v any) Fetcher)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultFetcher struct {
|
|
||||||
Ctl *controller.Controller
|
|
||||||
Meta *FetcherMeta
|
|
||||||
DoneCh chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *DefaultFetcher) Setup(ctl *controller.Controller) (err error) {
|
|
||||||
f.Ctl = ctl
|
|
||||||
f.DoneCh = make(chan error, 1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *DefaultFetcher) Wait() (err error) {
|
|
||||||
return <-f.DoneCh
|
|
||||||
}
|
|
||||||
|
|
||||||
// Progress is a map of the progress of each file in the torrent.
|
|
||||||
type Progress []int64
|
|
||||||
|
|
||||||
// TotalDownloaded returns the total downloaded bytes.
|
|
||||||
func (p Progress) TotalDownloaded() int64 {
|
|
||||||
total := int64(0)
|
|
||||||
for _, d := range p {
|
|
||||||
total += d
|
|
||||||
}
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package bt
|
|
||||||
|
|
||||||
type config struct {
|
|
||||||
Trackers []string `json:"trackers"`
|
|
||||||
}
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
package bt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
|
||||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
"github.com/anacrolix/torrent"
|
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
|
||||||
"github.com/anacrolix/torrent/storage"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var client *torrent.Client
|
|
||||||
|
|
||||||
type Fetcher struct {
|
|
||||||
ctl *controller.Controller
|
|
||||||
|
|
||||||
torrent *torrent.Torrent
|
|
||||||
meta *fetcher.FetcherMeta
|
|
||||||
|
|
||||||
ready atomic.Bool
|
|
||||||
progress fetcher.Progress
|
|
||||||
|
|
||||||
torrentPaths map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Name() string {
|
|
||||||
return "bt"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Setup(ctl *controller.Controller) (err error) {
|
|
||||||
f.ctl = ctl
|
|
||||||
if f.meta == nil {
|
|
||||||
f.meta = &fetcher.FetcherMeta{}
|
|
||||||
}
|
|
||||||
var once sync.Once
|
|
||||||
once.Do(func() {
|
|
||||||
cfg := torrent.NewDefaultClientConfig()
|
|
||||||
cfg.ListenPort = 0
|
|
||||||
|
|
||||||
// Support custom download path for each torrent
|
|
||||||
pieceCompletion, err := storage.NewDefaultPieceCompletionForDir(cfg.DataDir)
|
|
||||||
if err != nil {
|
|
||||||
pieceCompletion = storage.NewMapPieceCompletion()
|
|
||||||
}
|
|
||||||
clientImplCloser := storage.NewFileOpts(storage.NewFileClientOpts{
|
|
||||||
ClientBaseDir: cfg.DataDir,
|
|
||||||
TorrentDirMaker: func(baseDir string, info *metainfo.Info, infoHash metainfo.Hash) string {
|
|
||||||
if dir, ok := f.torrentPaths[infoHash.String()]; ok {
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
return baseDir
|
|
||||||
},
|
|
||||||
PieceCompletion: pieceCompletion,
|
|
||||||
})
|
|
||||||
cfg.DefaultStorage = clientImplCloser
|
|
||||||
client, err = torrent.NewClient(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.torrentPaths = make(map[string]string)
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Resolve(req *base.Request) error {
|
|
||||||
if err := f.addTorrent(req.URL); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.torrent.Drop()
|
|
||||||
res := &base.Resource{
|
|
||||||
Name: f.torrent.Name(),
|
|
||||||
Range: true,
|
|
||||||
RootDir: f.torrent.Name(),
|
|
||||||
Files: make([]*base.FileInfo, len(f.torrent.Files())),
|
|
||||||
Hash: f.torrent.InfoHash().String(),
|
|
||||||
}
|
|
||||||
for i, file := range f.torrent.Files() {
|
|
||||||
res.Files[i] = &base.FileInfo{
|
|
||||||
Name: filepath.Base(file.DisplayPath()),
|
|
||||||
Path: util.Dir(file.Path()),
|
|
||||||
Size: file.Length(),
|
|
||||||
}
|
|
||||||
res.Size += file.Length()
|
|
||||||
}
|
|
||||||
f.meta.Req = req
|
|
||||||
f.meta.Res = res
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Create(opts *base.Options) (err error) {
|
|
||||||
f.meta.Opts = opts
|
|
||||||
if len(opts.SelectFiles) == 0 {
|
|
||||||
opts.SelectFiles = make([]int, 0)
|
|
||||||
for i := range f.torrent.Files() {
|
|
||||||
opts.SelectFiles = append(opts.SelectFiles, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if opts.Path != "" {
|
|
||||||
f.torrentPaths[f.meta.Res.Hash] = path.Join(f.meta.Opts.Path, f.meta.Res.RootDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.progress = make(fetcher.Progress, len(f.meta.Opts.SelectFiles))
|
|
||||||
f.ready.Store(false)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Start() (err error) {
|
|
||||||
if !f.ready.Load() {
|
|
||||||
if err = f.addTorrent(f.meta.Req.URL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
files := f.torrent.Files()
|
|
||||||
if len(f.meta.Opts.SelectFiles) == len(files) {
|
|
||||||
f.torrent.DownloadAll()
|
|
||||||
} else {
|
|
||||||
for _, selectIndex := range f.meta.Opts.SelectFiles {
|
|
||||||
file := files[selectIndex]
|
|
||||||
file.Download()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Pause() (err error) {
|
|
||||||
f.ready.Store(false)
|
|
||||||
f.torrent.Drop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Continue() (err error) {
|
|
||||||
return f.Start()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Close() (err error) {
|
|
||||||
f.torrent.Drop()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Wait() (err error) {
|
|
||||||
for {
|
|
||||||
if f.ready.Load() {
|
|
||||||
done := true
|
|
||||||
for _, selectIndex := range f.meta.Opts.SelectFiles {
|
|
||||||
file := f.torrent.Files()[selectIndex]
|
|
||||||
if file.BytesCompleted() < file.Length() {
|
|
||||||
done = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if done {
|
|
||||||
// remove unselected files
|
|
||||||
for i, file := range f.torrent.Files() {
|
|
||||||
selected := false
|
|
||||||
for _, selectIndex := range f.meta.Opts.SelectFiles {
|
|
||||||
if i == selectIndex {
|
|
||||||
selected = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !selected {
|
|
||||||
util.SafeRemove(filepath.Join(f.meta.Opts.Path, file.Path()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(time.Millisecond * 500)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Meta() *fetcher.FetcherMeta {
|
|
||||||
return f.meta
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) Progress() fetcher.Progress {
|
|
||||||
if !f.ready.Load() {
|
|
||||||
return f.progress
|
|
||||||
}
|
|
||||||
for i := range f.progress {
|
|
||||||
selectIndex := f.meta.Opts.SelectFiles[i]
|
|
||||||
file := f.torrent.Files()[selectIndex]
|
|
||||||
f.progress[i] = file.BytesCompleted()
|
|
||||||
}
|
|
||||||
return f.progress
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fetcher) addTorrent(url string) (err error) {
|
|
||||||
schema := util.ParseSchema(url)
|
|
||||||
if schema == "MAGNET" {
|
|
||||||
f.torrent, err = client.AddMagnet(url)
|
|
||||||
} else {
|
|
||||||
f.torrent, err = client.AddTorrentFromFile(url)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var cfg config
|
|
||||||
exist, err := f.ctl.GetConfig(&cfg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if exist && len(cfg.Trackers) > 0 {
|
|
||||||
announceList := make([][]string, 0)
|
|
||||||
for _, tracker := range cfg.Trackers {
|
|
||||||
announceList = append(announceList, []string{tracker})
|
|
||||||
}
|
|
||||||
f.torrent.AddTrackers(announceList)
|
|
||||||
}
|
|
||||||
<-f.torrent.GotInfo()
|
|
||||||
f.ready.Store(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type FetcherBuilder struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
var schemes = []string{"FILE", "MAGNET"}
|
|
||||||
|
|
||||||
func (fb *FetcherBuilder) Schemes() []string {
|
|
||||||
return schemes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *FetcherBuilder) Build() fetcher.Fetcher {
|
|
||||||
return &Fetcher{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *FetcherBuilder) Store(f fetcher.Fetcher) (data any, err error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *FetcherBuilder) Restore() (v any, f func(meta *fetcher.FetcherMeta, v any) fetcher.Fetcher) {
|
|
||||||
return nil, func(meta *fetcher.FetcherMeta, v any) fetcher.Fetcher {
|
|
||||||
return &Fetcher{
|
|
||||||
meta: meta,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loaded 50 of 319 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user