├── .codebeatsettings ├── .github └── workflows │ ├── ci-test.yml │ ├── codeql-analysis.yml │ ├── generate-docs.yml │ └── version-check.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── code-gen ├── go.mod ├── src │ ├── api_desc.go │ ├── apidesc │ │ ├── api.go │ │ ├── body_json.go │ │ ├── consts.go │ │ ├── header.go │ │ ├── request.go │ │ ├── request_body_form.go │ │ ├── request_body_multipart.go │ │ ├── request_query.go │ │ ├── response.go │ │ └── response_body.go │ ├── generator │ │ ├── config.go │ │ ├── consts.go │ │ ├── generator.go │ │ ├── internal │ │ │ └── data │ │ │ │ ├── api.go │ │ │ │ ├── field.go │ │ │ │ ├── request.go │ │ │ │ └── response.go │ │ └── lang │ │ │ ├── java │ │ │ ├── java.go │ │ │ └── java_test.go │ │ │ └── lang.go │ ├── main.go │ ├── parser │ │ └── parser.go │ └── utils │ │ ├── file.go │ │ ├── math.go │ │ ├── string.go │ │ └── temp.go └── templates │ └── java │ ├── api.java │ ├── api_create_class.java │ ├── api_request.java │ └── api_response.java ├── codecov.yml ├── config └── checkstyle │ └── checkstyle.xml ├── examples ├── BatchDemo.java ├── CdnRefreshDirsDemo.java ├── CdnRefreshUrlsDemo.java ├── DomainListDemo.java ├── FetchApiDemo.java ├── FetchDemo.java ├── FusionRefreshDemo.java ├── GetBucketInfo.java ├── LinkingDemo.java ├── ListDemo.java ├── QNMetaDemo.java ├── QvmUploadDemo.java ├── ResourcesCensor.java ├── SendMessageDemo.java ├── UploadBySelfDefiningDomain.java ├── UploadBySelfDefiningParam.java ├── copy.java ├── delete.java ├── download.java ├── fops.java ├── move.java ├── pfop_vframe.java ├── pfop_watermark.java ├── stat.java ├── upload.java ├── upload_ recorder.java ├── upload_callback.java ├── upload_overwrite.java ├── upload_pfops.java ├── upload_v1_api.java ├── upload_v2_api.java ├── 关于回调流程.md └── 关于设置notifyURL没有收到回调.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mvn_push.gradle ├── settings.gradle └── src ├── main └── java │ └── com │ └── qiniu │ ├── audit │ └── apis │ │ └── ApiQueryLog.java │ ├── cdn │ ├── CdnManager.java │ └── CdnResult.java │ ├── common │ ├── AutoZone.java │ ├── Constants.java │ ├── QiniuException.java │ ├── Zone.java │ └── ZoneReqInfo.java │ ├── http │ ├── AsyncCallback.java │ ├── Client.java │ ├── Dns.java │ ├── Error.java │ ├── Headers.java │ ├── MethodType.java │ ├── ProxyConfiguration.java │ ├── RequestStreamBody.java │ └── Response.java │ ├── iam │ └── apis │ │ ├── ApiCreateGroup.java │ │ ├── ApiCreatePolicy.java │ │ ├── ApiCreateUser.java │ │ ├── ApiCreateUserKeypairs.java │ │ ├── ApiDeleteGroup.java │ │ ├── ApiDeleteGroupPolicies.java │ │ ├── ApiDeleteGroupUsers.java │ │ ├── ApiDeletePolicy.java │ │ ├── ApiDeleteUser.java │ │ ├── ApiDeleteUserKeypair.java │ │ ├── ApiDeleteUserPolicy.java │ │ ├── ApiDisableUserKeypair.java │ │ ├── ApiEnableUserKeypair.java │ │ ├── ApiGetActions.java │ │ ├── ApiGetAudits.java │ │ ├── ApiGetGroup.java │ │ ├── ApiGetGroupPolicies.java │ │ ├── ApiGetGroupServiceActionResources.java │ │ ├── ApiGetGroupUsers.java │ │ ├── ApiGetGroups.java │ │ ├── ApiGetPolicies.java │ │ ├── ApiGetPolicy.java │ │ ├── ApiGetPolicyGroups.java │ │ ├── ApiGetPolicyUsers.java │ │ ├── ApiGetServices.java │ │ ├── ApiGetUser.java │ │ ├── ApiGetUserAvailableServices.java │ │ ├── ApiGetUserGroups.java │ │ ├── ApiGetUserKeypairs.java │ │ ├── ApiGetUserPolicies.java │ │ ├── ApiGetUserServiceActionResources.java │ │ ├── ApiGetUsers.java │ │ ├── ApiModifyGroup.java │ │ ├── ApiModifyGroupPolicies.java │ │ ├── ApiModifyGroupUsers.java │ │ ├── ApiModifyPolicy.java │ │ ├── ApiModifyUser.java │ │ ├── ApiModifyUserPolicies.java │ │ ├── ApiUpdateGroupPolicies.java │ │ ├── ApiUpdateGroupUsers.java │ │ ├── ApiUpdatePolicyGroups.java │ │ ├── ApiUpdatePolicyUsers.java │ │ ├── ApiUpdateUserGroups.java │ │ └── ApiUpdateUserPolicies.java │ ├── linking │ ├── LinkingDeviceManager.java │ ├── LinkingVodManager.java │ ├── README.md │ └── model │ │ ├── Channel.java │ │ ├── Device.java │ │ ├── DeviceHistoryItem.java │ │ ├── DeviceHistoryListing.java │ │ ├── DeviceKey.java │ │ ├── DeviceListing.java │ │ ├── PatchOperation.java │ │ ├── SaveasReply.java │ │ ├── Segment.java │ │ └── SegmentListing.java │ ├── media │ └── apis │ │ ├── ApiPfop.java │ │ └── ApiPrefop.java │ ├── processing │ ├── OperationManager.java │ └── OperationStatus.java │ ├── qvs │ ├── DeviceManager.java │ ├── NameSpaceManager.java │ ├── PTZManager.java │ ├── QvsMap.java │ ├── QvsResponse.java │ ├── README.md │ ├── RecordManager.java │ ├── StatsManager.java │ ├── StreamManager.java │ ├── TemplateManager.java │ └── model │ │ ├── ChannelInfo.java │ │ ├── Device.java │ │ ├── DynamicLiveRoute.java │ │ ├── NameSpace.java │ │ ├── PatchOperation.java │ │ ├── PlayContral.java │ │ ├── StaticLiveRoute.java │ │ ├── Stream.java │ │ ├── Template.java │ │ └── VoiceChat.java │ ├── rtc │ ├── QRTC.java │ ├── QRTCClient.java │ ├── RtcAppManager.java │ ├── RtcRoomManager.java │ ├── ServiceCallFunc.java │ ├── model │ │ ├── AppParam.java │ │ ├── AppResult.java │ │ ├── CallbackParam.java │ │ ├── ForwardParam.java │ │ ├── ForwardResult.java │ │ ├── MediaConfig.java │ │ ├── MediaInput.java │ │ ├── MediaOutput.java │ │ ├── MediaPosition.java │ │ ├── MergeJob.java │ │ ├── MergeParam.java │ │ ├── MergeResult.java │ │ ├── MergeTrackParam.java │ │ ├── QRTCResult.java │ │ ├── RoomAccess.java │ │ ├── RoomParam.java │ │ ├── RoomResult.java │ │ ├── StretchModeEnum.java │ │ ├── UrlParam.java │ │ └── WatermarksParam.java │ └── service │ │ ├── AbstractService.java │ │ ├── AppService.java │ │ ├── CallbackService.java │ │ ├── ForwardService.java │ │ ├── MergeService.java │ │ ├── MergeServiceV4.java │ │ └── RoomService.java │ ├── sms │ ├── Configuration.java │ ├── SmsManager.java │ └── model │ │ ├── SignatureInfo.java │ │ └── TemplateInfo.java │ ├── storage │ ├── Api.java │ ├── ApiInterceptorAuth.java │ ├── ApiInterceptorDebug.java │ ├── ApiInterceptorDefaultHeader.java │ ├── ApiInterceptorRetryHosts.java │ ├── ApiInterceptorRetrySimple.java │ ├── ApiQueryRegion.java │ ├── ApiUpload.java │ ├── ApiUploadV1MakeBlock.java │ ├── ApiUploadV1MakeFile.java │ ├── ApiUploadV1PutChunk.java │ ├── ApiUploadV2AbortUpload.java │ ├── ApiUploadV2CompleteUpload.java │ ├── ApiUploadV2InitUpload.java │ ├── ApiUploadV2ListParts.java │ ├── ApiUploadV2UploadPart.java │ ├── ApiUtils.java │ ├── AutoRegion.java │ ├── BaseUploader.java │ ├── BucketManager.java │ ├── ConcurrentResumeUploader.java │ ├── ConfigHelper.java │ ├── Configuration.java │ ├── DownloadPrivateCloudUrl.java │ ├── DownloadUrl.java │ ├── FixBlockUploader.java │ ├── FormUploader.java │ ├── HostProvider.java │ ├── Recorder.java │ ├── Region.java │ ├── RegionGroup.java │ ├── RegionReqInfo.java │ ├── ResumeUploadPerformer.java │ ├── ResumeUploadPerformerV1.java │ ├── ResumeUploadPerformerV2.java │ ├── ResumeUploadSource.java │ ├── ResumeUploadSourceFile.java │ ├── ResumeUploadSourceStream.java │ ├── ResumeUploader.java │ ├── Retry.java │ ├── StreamUploader.java │ ├── UpCompletionHandler.java │ ├── UpHostHelper.java │ ├── UploadManager.java │ ├── UploadOptions.java │ ├── UploadToken.java │ ├── model │ │ ├── AccessStyleMode.java │ │ ├── AclType.java │ │ ├── BatchOpData.java │ │ ├── BatchStatus.java │ │ ├── BucketEventRule.java │ │ ├── BucketInfo.java │ │ ├── BucketLifeCycleRule.java │ │ ├── BucketQuota.java │ │ ├── BucketReferAntiLeech.java │ │ ├── CorsRule.java │ │ ├── DefaultPutRet.java │ │ ├── FetchRet.java │ │ ├── FileInfo.java │ │ ├── FileListing.java │ │ ├── IndexPageType.java │ │ ├── ResumeBlockInfo.java │ │ ├── StorageType.java │ │ └── UploadPolicy.java │ └── persistent │ │ └── FileRecorder.java │ ├── streaming │ ├── StreamingManager.java │ ├── UrlFactory.java │ └── model │ │ ├── ActivityRecords.java │ │ ├── StreamAttribute.java │ │ ├── StreamListing.java │ │ └── StreamStatus.java │ └── util │ ├── Auth.java │ ├── Base64.java │ ├── Cache.java │ ├── Crc32.java │ ├── DefaultHeader.java │ ├── Etag.java │ ├── EtagV2.java │ ├── Hex.java │ ├── IOUtils.java │ ├── Json.java │ ├── Md5.java │ ├── StringMap.java │ ├── StringUtils.java │ ├── Timestamp.java │ ├── UrlSafeBase64.java │ └── UrlUtils.java └── test └── java ├── com └── qiniu │ ├── audit │ └── apis │ │ └── ApiQueryLogTest.java │ ├── common │ └── AutoZoneTest.java │ ├── iam │ └── apis │ │ ├── ApiTestConfig.java │ │ ├── GroupPolicyApiTest.java │ │ ├── GroupsApiTest.java │ │ ├── PolicyApiTest.java │ │ ├── SystemApiTest.java │ │ └── UserApiTest.java │ └── storage │ ├── ApiQueryRegionTest.java │ ├── BatchTest.java │ ├── FixBlockUploaderWithRecorderTest.java │ └── RegionTest.java └── test └── com └── qiniu ├── CdnTest.java ├── DnsTest.java ├── HttpTest.java ├── ResCode.java ├── TempFile.java ├── TestConfig.java ├── cdn └── CdnManagerTest.java ├── linking └── DeviceTest.java ├── processing └── PfopTest.java ├── qvs ├── DeviceManagerTest.java ├── NameSpaceTest.java ├── PTZTest.java ├── RecordTest.java ├── StatsTest.java ├── StreamTest.java └── TemplateTest.java ├── rtc ├── MergeServiceV4Test.java └── RtcTest.java ├── sms └── SmsTest.java ├── storage ├── ApiUploadV1Test.java ├── ApiUploadV2Test.java ├── BucketManagerTest.java ├── BucketTest.java ├── BucketTest2.java ├── DownloadUrlTest.java ├── FixBlockUploaderTest.java ├── FormUploadTest.java ├── RecordUploadTest.java ├── RegionGroupTest.java ├── RegionTest.java ├── ResumeUploadTest.java ├── StreamUploadTest.java ├── SwitchRegionTest.java └── ZoneTest.java ├── streaming ├── StreamingTest.java └── UrlTest.java └── util ├── AuthTest.java ├── Base64Test.java ├── CacheTest.java ├── CrcTest.java ├── EtagTest.java ├── JsonTest.java ├── Md5Test.java └── UrlComposerTest.java /.codebeatsettings: -------------------------------------------------------------------------------- 1 | { 2 | "JAVA": { 3 | "ABC": [15, 25, 50, 70], 4 | "TOO_MANY_IVARS": [8, 15, 20, 25], 5 | "ARITY": [5, 10, 15, 20] 6 | } 7 | } -------------------------------------------------------------------------------- /.github/workflows/ci-test.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Gradle 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | permissions: 7 | actions: read 8 | contents: read 9 | security-events: write 10 | strategy: 11 | fail-fast: false 12 | max-parallel: 1 13 | matrix: 14 | java_version: ['8', '11'] 15 | steps: 16 | - name: checkout 17 | uses: actions/checkout@v2 18 | - name: Set up JDK 19 | uses: actions/setup-java@v2 20 | with: 21 | distribution: 'zulu' 22 | java-version: ${{ matrix.java_version }} 23 | - name: Grant execute permission for gradlew 24 | run: chmod +x gradlew 25 | - name: Unit Test 26 | run: | 27 | ./gradlew unitTest -d 28 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | 21 | jobs: 22 | analyze: 23 | name: Analyze 24 | runs-on: ubuntu-latest 25 | permissions: 26 | actions: read 27 | contents: read 28 | security-events: write 29 | 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | language: [ 'java' ] 34 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 35 | # Learn more: 36 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 37 | 38 | steps: 39 | - name: Checkout repository 40 | uses: actions/checkout@v2 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | - name: Autobuild 46 | uses: github/codeql-action/autobuild@v1 47 | - name: Perform CodeQL Analysis 48 | uses: github/codeql-action/analyze@v1 49 | -------------------------------------------------------------------------------- /.github/workflows/generate-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy static content to Pages 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | # Allow one concurrent deployment 18 | concurrency: 19 | group: "pages" 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | # Single deploy job since we're just deploying 24 | deploy: 25 | environment: 26 | name: github-pages 27 | url: ${{ steps.deployment.outputs.page_url }} 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v3 32 | with: 33 | submodules: 'recursive' 34 | - name: Set up JDK 35 | uses: actions/setup-java@v2 36 | with: 37 | distribution: 'zulu' 38 | java-version: '11' 39 | - name: Grant execute permission for gradlew 40 | run: chmod +x gradlew 41 | - name: Generate Docs 42 | run: | 43 | rm -rf build/docs 44 | mkdir -p build/docs 45 | ./gradlew apiJavadocs -d 46 | - name: Setup Pages 47 | uses: actions/configure-pages@v2 48 | - name: Upload artifact 49 | uses: actions/upload-pages-artifact@v1 50 | with: 51 | path: build/docs/javadoc 52 | - name: Deploy to GitHub Pages 53 | id: deployment 54 | uses: actions/deploy-pages@v1 55 | -------------------------------------------------------------------------------- /.github/workflows/version-check.yml: -------------------------------------------------------------------------------- 1 | name: Java SDK Version Check 2 | on: 3 | push: 4 | tags: 5 | - "v[0-9]+.[0-9]+.[0-9]+" 6 | jobs: 7 | linux: 8 | name: Version Check 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v2 13 | - name: Set env 14 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV 15 | - name: Check 16 | run: | 17 | set -e 18 | grep -qF "## ${RELEASE_VERSION}" CHANGELOG.md 19 | grep -qF "public static final String VERSION = \"${RELEASE_VERSION}\";" src/main/java/com/qiniu/common/Constants.java 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Play! working directory # 2 | bin/ 3 | /db 4 | .eclipse 5 | .classpath 6 | .project 7 | .settings/ 8 | /lib/ 9 | /logs/ 10 | /modules 11 | /project/project 12 | /project/target 13 | /target 14 | tmp/ 15 | test-result 16 | server.pid 17 | *.iml 18 | *.eml 19 | /dist/ 20 | .cache 21 | .gradle/ 22 | build/ 23 | out/ 24 | 25 | #src.zip 26 | 27 | .idea 28 | .gradle 29 | # For MacOS: 30 | .DS_Store 31 | 32 | # For vim: 33 | *.swp -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献代码指南 2 | 3 | 我们非常欢迎大家来贡献代码,我们会向贡献者致以最诚挚的敬意。 4 | 5 | 一般可以通过在Github上提交[Pull Request](https://github.com/qiniu/java-sdk)来贡献代码。 6 | 7 | ## Pull Request要求 8 | 9 | - **代码风格标准** 。要通过项目中的checkstyle检查。 10 | 11 | - **代码格式** 提交前请按项目风格进行格式化。 12 | 13 | - **必须添加测试!** - 如果没有测试(单元测试、集成测试都可以),那么提交的补丁是不会通过的。 14 | 15 | - **记得更新文档** - 保证`README.md`以及其他相关文档及时更新,和代码的变更保持一致性。 16 | 17 | - **考虑我们的发布周期** - 我们的版本号会服从[SemVer v2.0.0](http://semver.org/),我们绝对不会随意变更对外的API。 18 | 19 | - **创建feature分支** - 最好不要从你的master分支提交 pull request。 20 | 21 | - **一个feature提交一个pull请求** - 如果你的代码变更了多个操作,那就提交多个pull请求吧。 22 | 23 | - **清晰的commit历史** - 保证你的pull请求的每次commit操作都是有意义的。如果你开发中需要执行多次的即时commit操作,那么请把它们放到一起再提交pull请求。 24 | 25 | ## 运行测试 26 | 27 | ``` bash 28 | ./gradlew build 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Qiniu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import java.util.regex.Matcher 2 | 3 | apply plugin: 'java' 4 | apply plugin: 'jacoco' 5 | 6 | sourceCompatibility = 1.7 7 | targetCompatibility = 1.7 8 | version = '1.0' 9 | [compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | jacocoTestReport { 16 | reports { 17 | xml.enabled true 18 | html.enabled false 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.14.4' 24 | implementation 'com.google.code.gson:gson:2.8.9' 25 | implementation 'org.projectlombok:lombok:1.18.22' 26 | testImplementation group: 'com.qiniu', name: 'happy-dns-java', version: '0.1.6' 27 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' 28 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' 29 | compileOnly 'org.projectlombok:lombok:1.18.22' 30 | annotationProcessor 'org.projectlombok:lombok:1.18.22' 31 | testCompileOnly 'org.projectlombok:lombok:1.18.22' 32 | testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' 33 | } 34 | 35 | test { 36 | useJUnitPlatform() 37 | } 38 | 39 | task unitTest(type: Test) { 40 | useJUnitPlatform { 41 | includeTags 'UnitTest' 42 | } 43 | } 44 | 45 | task getHomeDir { 46 | doLast { 47 | println gradle.gradleHomeDir 48 | } 49 | } 50 | 51 | apply plugin: 'checkstyle' 52 | 53 | task apiJavadocs(type: Javadoc) { 54 | source = sourceSets.main.allJava 55 | classpath = sourceSets.main.runtimeClasspath 56 | title = "七牛 Java SDK API 文档" 57 | options { 58 | memberLevel = JavadocMemberLevel.PUBLIC 59 | setEncoding 'UTF-8' 60 | setWindowTitle "七牛 Java SDK API 文档" 61 | } 62 | } 63 | 64 | def versionName() { 65 | String config = getProjectDir().getPath() + '/src/main/java/com/qiniu/common/Constants.java' 66 | String fileContents = new File(config).text 67 | Matcher myMatcher = fileContents =~ /VERSION = "(.+)";/ 68 | String version = myMatcher[0][1] 69 | println(version) 70 | return version 71 | } 72 | 73 | static def versionNameToCode(String version) { 74 | String v = version.replaceAll(/\./, '') 75 | return v.toLong() 76 | } 77 | 78 | String version = versionName() 79 | int code = versionNameToCode(version) 80 | 81 | setProperty('VERSION_NAME', version) 82 | setProperty('VERSION_CODE', code) 83 | 84 | apply from: 'mvn_push.gradle' 85 | 86 | apply plugin: 'eclipse' 87 | 88 | task gen_eclipse(dependsOn: [ 89 | 'cleanEclipseProject', 'cleanEclipseClasspath', 90 | 'eclipseProject', 'eclipseClasspath']) 91 | eclipseProject.mustRunAfter cleanEclipseProject 92 | eclipseClasspath.mustRunAfter cleanEclipseClasspath 93 | -------------------------------------------------------------------------------- /code-gen/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/YangSen-qn/code-gen 2 | 3 | require ( 4 | github.com/getkin/kin-openapi v0.124.0 5 | github.com/iancoleman/strcase v0.3.0 6 | gopkg.in/yaml.v3 v3.0.1 7 | ) 8 | 9 | require ( 10 | github.com/go-openapi/jsonpointer v0.20.2 // indirect 11 | github.com/go-openapi/swag v0.22.8 // indirect 12 | github.com/invopop/yaml v0.2.0 // indirect 13 | github.com/josharian/intern v1.0.0 // indirect 14 | github.com/mailru/easyjson v0.7.7 // indirect 15 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 16 | github.com/perimeterx/marshmallow v1.1.5 // indirect 17 | ) 18 | 19 | go 1.21.8 20 | -------------------------------------------------------------------------------- /code-gen/src/api_desc.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/api.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type ApiDetailedDescription struct { 4 | Documentation string `yaml:"documentation,omitempty"` // API 文档 5 | PackageName string `yaml:"package_name,omitempty"` // 包名,文件路径中提取 6 | Name string `yaml:"name,omitempty"` // API 名称,文件名 7 | CamelCaseName string `yaml:"camel_case_name,omitempty"` // 驼峰命名 8 | SnakeCaseName string `yaml:"snake_case_name,omitempty"` // 蛇形命名:特指下划线命名 9 | Method MethodName `yaml:"method,omitempty"` // HTTP 方法 10 | ServiceNames []ServiceName `yaml:"service_names,omitempty"` // 七牛服务名称 11 | Command string `yaml:"command,omitempty"` // URL 查询命令 12 | BasePath string `yaml:"base_path,omitempty"` // URL 基础路径 13 | PathSuffix string `yaml:"path_suffix,omitempty"` // URL 路径后缀 14 | Request ApiRequestDescription `yaml:"request,omitempty"` // 请求参数 15 | Response ApiResponseDescription `yaml:"response,omitempty"` // 响应参数 16 | } 17 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/header.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type HeaderName struct { 4 | HeaderName string `yaml:"header_name,omitempty"` // HTTP 头名称 5 | Documentation string `yaml:"documentation,omitempty"` // HTTP 头参数文档 6 | FieldName string `yaml:"field_name,omitempty"` // HTTP 头参数名称 7 | FieldCamelCaseName string `yaml:"field_camel_case_name,omitempty"` // HTTP 头参数驼峰命名 8 | FieldSnakeCaseName string `yaml:"field_snake_case_name,omitempty"` // HTTP 头参数下划线命名 9 | Optional *OptionalType `yaml:"optional,omitempty"` // HTTP 头参数是否可选,如果为空,则表示必填 10 | } 11 | 12 | type HeaderNames []HeaderName 13 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/request_body_form.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type FormUrlencodedRequestStruct struct { 4 | Fields []FormUrlencodedRequestField `yaml:"fields,omitempty"` // URL 编码表单字段列表 5 | } 6 | 7 | type FormUrlencodedRequestField struct { 8 | FieldName string `yaml:"field_name,omitempty"` // URL 编码表单字段名称 9 | FieldCamelCaseName string `yaml:"field_camel_case_name,omitempty"` // URL 编码表单字段驼峰命名 10 | FieldSnakeCaseName string `yaml:"field_snake_case_name,omitempty"` // URL 编码表单字段下划线命名 11 | Key string `yaml:"key,omitempty"` // URL 编码表单参数名称 12 | Documentation string `yaml:"documentation,omitempty"` // URL 编码表单参数文档 13 | Type *StringLikeType `yaml:"type,omitempty"` // URL 编码表单参数类型 14 | Multiple bool `yaml:"multiple,omitempty"` // URL 编码表单参数是否可以有多个值 15 | Optional *OptionalType `yaml:"optional,omitempty"` // URL 编码表单参数是否可选,如果为空,则表示必填 16 | ServiceBucket *ServiceBucketType `yaml:"service_bucket,omitempty"` // URL 编码表单参数是否是空间名称,如果为空,则表示不是,如果不为空,则填写格式 17 | ServiceObject *ServiceObjectType `yaml:"service_object,omitempty"` // URL 编码表单参数是否是对象名称,如果为空,则表示不是,如果不为空,则填写格式 18 | } 19 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/request_body_multipart.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type MultipartFormFields struct { 4 | Named []NamedMultipartFormField `yaml:"named_fields,omitempty"` 5 | Free *FreeMultipartFormFields `yaml:"free_fields,omitempty"` 6 | } 7 | 8 | type NamedMultipartFormField struct { 9 | FieldName string `yaml:"field_name,omitempty"` 10 | FieldCamelCaseName string `yaml:"field_camel_case_name,omitempty"` 11 | FieldSnakeCaseName string `yaml:"field_snake_case_name,omitempty"` 12 | Key string `yaml:"key,omitempty"` 13 | Type *MultipartFormDataType `yaml:"type,omitempty"` 14 | Documentation string `yaml:"documentation,omitempty"` 15 | ServiceBucket *ServiceBucketType `yaml:"service_bucket,omitempty"` 16 | ServiceObject *ServiceObjectType `yaml:"service_object,omitempty"` 17 | Optional *OptionalType `yaml:"optional,omitempty"` 18 | } 19 | 20 | type FreeMultipartFormFields struct { 21 | FieldName string `yaml:"field_name,omitempty"` 22 | FieldCamelCaseName string `yaml:"field_camel_case_name,omitempty"` 23 | FieldSnakeCaseName string `yaml:"field_snake_case_name,omitempty"` 24 | Documentation string `yaml:"documentation,omitempty"` 25 | } 26 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/request_query.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type QueryName struct { 4 | FieldName string `yaml:"field_name,omitempty"` // 参数名称 5 | FieldCamelCaseName string `yaml:"field_camel_case_name,omitempty"` // URL 路径参数驼峰命名 6 | FieldSnakeCaseName string `yaml:"field_snake_case_name,omitempty"` // URL 路径参数下划线命名 7 | QueryName string `yaml:"query_name,omitempty"` // URL 查询参数名称 8 | Documentation string `yaml:"documentation,omitempty"` // URL 查询参数文档 9 | Multiple bool `yaml:"multiple,omitempty"` // URL 查询参数是否可以有多个值 10 | QueryType *StringLikeType `yaml:"query_type,omitempty"` // URL 查询参数类型 11 | ServiceBucket *ServiceBucketType `yaml:"service_bucket,omitempty"` // URL 查询参数是否是空间名称,如果为空,则表示不是,如果不为空,则填写格式 12 | ServiceObject *ServiceObjectType `yaml:"service_object,omitempty"` // URL 查询参数是否是对象名称,如果为空,则表示不是,如果不为空,则填写格式 13 | Optional *OptionalType `yaml:"optional,omitempty"` // URL 查询参数是否可选,如果为空,则表示必填 14 | } 15 | 16 | type QueryNames []QueryName 17 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/response.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | type ApiResponseDescription struct { 4 | HeaderNames HeaderNames `yaml:"header_names,omitempty"` // HTTP 头参数列表 5 | Body *ResponseBody `yaml:"body,omitempty"` // 响应体 6 | } 7 | -------------------------------------------------------------------------------- /code-gen/src/apidesc/response_body.go: -------------------------------------------------------------------------------- 1 | package apidesc 2 | 3 | import ( 4 | "fmt" 5 | 6 | "gopkg.in/yaml.v3" 7 | ) 8 | 9 | type ResponseBody struct { 10 | Json *JsonType `yaml:"json,omitempty"` // JSON 类型 11 | BinaryDataStream bool `yaml:"binaryDataStream,omitempty"` // 二进制数据 12 | } 13 | 14 | func (body *ResponseBody) UnmarshalYAML(value *yaml.Node) error { 15 | switch value.ShortTag() { 16 | case "!!str": 17 | switch value.Value { 18 | case "binary_data_stream": 19 | body.BinaryDataStream = true 20 | return nil 21 | default: 22 | return fmt.Errorf("unknown response body type: %s", value.Value) 23 | } 24 | case "!!map": 25 | switch value.Content[0].Value { 26 | case "json": 27 | return value.Content[1].Decode(&body.Json) 28 | default: 29 | return fmt.Errorf("unknown response body type: %s", value.Content[0].Value) 30 | } 31 | default: 32 | return fmt.Errorf("unknown response body type: %s", value.ShortTag()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code-gen/src/generator/config.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "path/filepath" 5 | 6 | "github.com/YangSen-qn/code-gen/src/generator/lang" 7 | ) 8 | 9 | type Config struct { 10 | Language lang.Language // 11 | TemplateDir string // 模版路径 12 | OutputDir string // 输出路径 13 | PackagePrefix string // 包名前缀 14 | } 15 | 16 | func (c Config) apiTemplatePath() string { 17 | return c.templatePath(TemplateFileNameApi) 18 | } 19 | 20 | func (c Config) apiClassTemplatePath() []string { 21 | templateNames := []string{ 22 | TemplateFileNameCreateClass, 23 | } 24 | paths := make([]string, 0) 25 | for _, name := range templateNames { 26 | paths = append(paths, c.templatePath(name)) 27 | } 28 | return paths 29 | } 30 | 31 | func (c Config) apiRequestTemplatePath() []string { 32 | templateNames := []string{ 33 | TemplateFileNameRequest, 34 | TemplateFileNameCreateClass, 35 | } 36 | paths := make([]string, 0) 37 | for _, name := range templateNames { 38 | paths = append(paths, c.templatePath(name)) 39 | } 40 | return paths 41 | } 42 | 43 | func (c Config) apiResponseTemplatePath() []string { 44 | templateNames := []string{ 45 | TemplateFileNameResponse, 46 | } 47 | paths := make([]string, 0) 48 | for _, name := range templateNames { 49 | paths = append(paths, c.templatePath(name)) 50 | } 51 | return paths 52 | } 53 | 54 | func (c Config) templatePath(name string) string { 55 | path := name 56 | 57 | if len(c.TemplateDir) > 0 { 58 | path = filepath.Join(c.TemplateDir, path) 59 | } 60 | 61 | return path 62 | } 63 | -------------------------------------------------------------------------------- /code-gen/src/generator/consts.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | const ( 4 | TemplateFileNameApi = "api.java" 5 | TemplateFileNameCreateClass = "api_create_class.java" 6 | TemplateFileNameRequest = "api_request.java" 7 | TemplateFileNameResponse = "api_response.java" 8 | ) 9 | -------------------------------------------------------------------------------- /code-gen/src/generator/internal/data/api.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "github.com/YangSen-qn/code-gen/src/generator/lang" 5 | "github.com/YangSen-qn/code-gen/src/utils" 6 | ) 7 | 8 | type Api struct { 9 | PackageName string 10 | Document string 11 | ClassName string 12 | RequestCode string 13 | ResponseCode string 14 | UseEncode bool 15 | Request *Request 16 | Response *Response 17 | Language lang.Language 18 | } 19 | 20 | func (a *Api) HasOtherClasses() bool { 21 | return len(a.Request.Classes) > 0 || len(a.Response.Classes) > 0 22 | } 23 | 24 | func (a *Api) HasMapFields() bool { 25 | for _, f := range a.Request.RequireFields { 26 | if f.IsMap() { 27 | return true 28 | } 29 | } 30 | 31 | for _, f := range a.Request.OptionsFields { 32 | if f.IsMap() { 33 | return true 34 | } 35 | } 36 | 37 | for _, class := range a.Request.Classes { 38 | for _, field := range class.Fields { 39 | if field.IsMap() { 40 | return true 41 | } 42 | 43 | } 44 | } 45 | 46 | for _, class := range a.Response.Classes { 47 | for _, field := range class.Fields { 48 | if field.IsMap() { 49 | return true 50 | } 51 | } 52 | } 53 | 54 | return false 55 | } 56 | 57 | func (a *Api) IsFromRequestBody() bool { 58 | return a.Request.IsBodyForm || a.Request.IsBodyMultiPartFrom 59 | } 60 | 61 | func (a *Api) IsJsonRequestBody() bool { 62 | return a.Request.IsBodyJson 63 | } 64 | 65 | func (a *Api) IsJsonResponseBody() bool { 66 | return a.Response.IsBodyJson 67 | } 68 | 69 | func (a *Api) AddIndentation(info string) string { 70 | if newInfo, err := utils.TextLineMapper(info, func(line string, lineNumber int, totalLine int) (t string, stop bool) { 71 | return a.Language.Indentation() + line, false 72 | }); err != nil { 73 | return info 74 | } else { 75 | return newInfo 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /code-gen/src/generator/internal/data/response.go: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import ( 4 | "github.com/YangSen-qn/code-gen/src/apidesc" 5 | "github.com/YangSen-qn/code-gen/src/generator/lang" 6 | ) 7 | 8 | type Response struct { 9 | Document string `json:"document"` 10 | PackageName string `json:"package_name"` 11 | ClassName string `json:"class_name"` 12 | Desc apidesc.ApiResponseDescription `json:"desc"` 13 | Language lang.Language `json:"-"` 14 | HeadFields []Field `json:"-"` 15 | BodyField Field `json:"-"` 16 | IsStreamBody bool `json:"-"` 17 | IsBodyJson bool `json:"-"` 18 | Classes []Class `json:"-"` 19 | } 20 | 21 | func (r *Response) Setup() *Response { 22 | r.getFieldsFromHeader() 23 | r.getFieldsFromBody() 24 | 25 | for _, class := range r.Classes { 26 | if class.ClassName == "" { 27 | class.ClassName = "ResponseData" 28 | } 29 | 30 | for _, field := range class.Fields { 31 | field.PublicGetFunc = true 32 | } 33 | } 34 | return r 35 | } 36 | 37 | func (r *Response) getFieldsFromHeader() { 38 | if headers := r.Desc.HeaderNames; headers != nil { 39 | for _, f := range headers { 40 | fieldType := lang.FieldType{ 41 | FieldType: FieldTypeString, 42 | } 43 | kOptional, vOptional := parseOptional(nil, f.Optional) 44 | field := Field{ 45 | Document: f.Documentation, 46 | Name: r.Language.FieldName(f.FieldName, true), 47 | GetFuncName: r.Language.FieldGetFunctionName(f.FieldName, true), 48 | SetFuncName: r.Language.FieldSetFunctionName(f.FieldName, !vOptional), 49 | Key: f.HeaderName, 50 | Type: r.Language.FieldTypeDesc(fieldType), 51 | Default: r.Language.FieldDefaultValue(fieldType, vOptional), 52 | KeyOptional: kOptional, 53 | ValueOptional: vOptional, 54 | Deprecated: false, 55 | } 56 | 57 | r.HeadFields = append(r.HeadFields, field) 58 | } 59 | } 60 | } 61 | 62 | func (r *Response) getFieldsFromBody() { 63 | body := r.Desc.Body 64 | if body == nil { 65 | return 66 | } 67 | 68 | if body.BinaryDataStream { 69 | r.IsStreamBody = true 70 | return 71 | } 72 | 73 | if data := body.Json; data != nil { 74 | field, classes := parseJsonTypeToField(r.Language, data) 75 | r.BodyField = field 76 | r.BodyField.PublicGetFunc = true 77 | r.BodyField.GetFuncName = r.Language.FieldGetFunctionName(field.Name, false) 78 | 79 | r.Classes = classes 80 | r.IsBodyJson = true 81 | return 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /code-gen/src/generator/lang/java/java_test.go: -------------------------------------------------------------------------------- 1 | package java 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFunctionName(t *testing.T) { 8 | 9 | j := java{} 10 | name := j.FieldName("Domain", false) 11 | if name != "domain" { 12 | t.Errorf("Expected domain, got %s", name) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code-gen/src/generator/lang/lang.go: -------------------------------------------------------------------------------- 1 | package lang 2 | 3 | type FieldType struct { 4 | FieldType string 5 | ClassName string // for class 6 | ContentKeyType string // for map,转化后的 7 | ContentValueType string // for map and array,转化后的 8 | } 9 | 10 | type Language interface { 11 | PackageName(name string) string 12 | Indentation() string 13 | Annotation(info string) string 14 | ApiFileName(name string) string 15 | ClassName(name string, isPrivate bool) string 16 | FieldName(name string, isPrivate bool) string 17 | FieldTypeDesc(fieldType FieldType) string 18 | FieldDefaultValue(fieldType FieldType, isOptional bool) string 19 | FieldGetFunctionName(name string, isPrivate bool) string 20 | FieldSetFunctionName(name string, isPrivate bool) string 21 | FunctionName(name string, isPrivate bool) string 22 | } 23 | -------------------------------------------------------------------------------- /code-gen/src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/YangSen-qn/code-gen/src/apidesc" 7 | "github.com/YangSen-qn/code-gen/src/generator" 8 | "github.com/YangSen-qn/code-gen/src/generator/lang/java" 9 | "github.com/YangSen-qn/code-gen/src/parser" 10 | ) 11 | 12 | func main() { 13 | 14 | apiDescDir := "api-specs" 15 | 16 | gen := generator.New(generator.Config{ 17 | Language: java.Java(), 18 | TemplateDir: "temp/java", 19 | OutputDir: "../src/main/java/com/qiniu", 20 | PackagePrefix: "com.qiniu.", 21 | }) 22 | 23 | if e := parser.Parser(apiDescDir, func(desc *apidesc.ApiDetailedDescription) error { 24 | fmt.Println(desc) 25 | return gen.Generate(desc) 26 | }); e != nil { 27 | fmt.Printf("error: %s", e) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code-gen/src/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "io/fs" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | "gopkg.in/yaml.v3" 11 | 12 | "github.com/YangSen-qn/code-gen/src/apidesc" 13 | "github.com/YangSen-qn/code-gen/src/utils" 14 | ) 15 | 16 | func isApiSpecFile(path string) bool { 17 | return strings.HasSuffix(path, ".yml") 18 | } 19 | 20 | type ApiDescHandler func(desc *apidesc.ApiDetailedDescription) error 21 | 22 | func Parser(apiDir string, handler ApiDescHandler) error { 23 | if handler == nil { 24 | return nil 25 | } 26 | 27 | return filepath.WalkDir(apiDir, func(path string, d fs.DirEntry, err error) error { 28 | if err != nil { 29 | return err 30 | } 31 | 32 | // 检查 33 | apiPath := path 34 | if exist, e := utils.ExistFile(apiPath); e != nil { 35 | return e 36 | } else if !exist { 37 | return nil 38 | } 39 | 40 | if !isApiSpecFile(apiPath) { 41 | return nil 42 | } 43 | 44 | descFile, err := os.Open(apiPath) 45 | if err != nil { 46 | return err 47 | } 48 | defer descFile.Close() 49 | 50 | pkgName := strings.TrimPrefix(path, apiDir) 51 | pkgName = strings.TrimPrefix(pkgName, "/") 52 | pkgName = strings.TrimSuffix(pkgName, d.Name()) 53 | pkgName = strings.TrimSuffix(pkgName, "/") 54 | 55 | desc := apidesc.ApiDetailedDescription{ 56 | PackageName: pkgName, 57 | Name: strings.TrimSuffix(d.Name(), ".yml"), 58 | } 59 | decoder := yaml.NewDecoder(descFile) 60 | decoder.KnownFields(true) 61 | if err = decoder.Decode(&desc); err != nil { 62 | return fmt.Errorf("parse api:%s error:%s", apiPath, err) 63 | } 64 | 65 | return handler(&desc) 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /code-gen/src/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | func ExistDir(dir string) (bool, error) { 8 | stat, err := os.Stat(dir) 9 | if err != nil { 10 | if os.IsNotExist(err) { 11 | return false, nil 12 | } 13 | 14 | return false, err 15 | } 16 | return stat.IsDir(), nil 17 | } 18 | 19 | func ExistFile(dir string) (bool, error) { 20 | stat, err := os.Stat(dir) 21 | if err != nil { 22 | if os.IsNotExist(err) { 23 | return false, nil 24 | } 25 | 26 | return false, err 27 | } 28 | return !stat.IsDir(), nil 29 | } 30 | -------------------------------------------------------------------------------- /code-gen/src/utils/math.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func Add(a, b int) int { 4 | return a + b 5 | } 6 | 7 | func Sub(a, b int) int { 8 | return a - b 9 | } 10 | 11 | func Mul(a, b int) int { 12 | return a * b 13 | } 14 | 15 | func Div(a, b int) int { 16 | if b == 0 { 17 | return 0 18 | } 19 | return a / b 20 | } 21 | -------------------------------------------------------------------------------- /code-gen/src/utils/string.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "strings" 7 | ) 8 | 9 | func TextLineMapper(text string, mapper func(line string, lineNumber int, totalLine int) (t string, stop bool)) (string, error) { 10 | if mapper == nil { 11 | return text, nil 12 | } 13 | 14 | totalLine := CountLines(text) 15 | 16 | stop := false 17 | line := "" 18 | index := 0 19 | newText := strings.Builder{} 20 | s := bufio.NewScanner(bytes.NewReader([]byte(text))) 21 | for s.Scan() { 22 | line, stop = mapper(s.Text(), index, totalLine) 23 | if index > 0 { 24 | line = "\n" + line 25 | } 26 | 27 | if _, err := newText.WriteString(line); err != nil { 28 | return "", err 29 | } 30 | 31 | if stop { 32 | break 33 | } 34 | 35 | index++ 36 | } 37 | 38 | return newText.String(), nil 39 | } 40 | 41 | func CountLines(text string) int { 42 | lines := 0 43 | for _, char := range text { 44 | if char == '\n' { 45 | lines++ 46 | } 47 | } 48 | 49 | // 如果字符串不以换行符结尾,则需要额外加一 50 | if lines > 0 && text[len(text)-1] != '\n' { 51 | lines++ 52 | } 53 | return lines 54 | } 55 | -------------------------------------------------------------------------------- /code-gen/src/utils/temp.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "text/template" 5 | ) 6 | 7 | func TemplateFunctions() template.FuncMap { 8 | return template.FuncMap{ 9 | "add": Add, 10 | "sub": Sub, 11 | "mul": Mul, 12 | "div": Div, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code-gen/templates/java/api.java: -------------------------------------------------------------------------------- 1 | package {{ .PackageName }}; 2 | {{ if .HasOtherClasses}} 3 | import com.google.gson.annotations.SerializedName; 4 | {{- end}} 5 | {{- if .IsJsonRequestBody }} 6 | import com.qiniu.common.Constants; 7 | {{- end}} 8 | import com.qiniu.common.QiniuException; 9 | import com.qiniu.http.Client; 10 | import com.qiniu.http.MethodType; 11 | {{- if .UseEncode}} 12 | import com.qiniu.util.UrlSafeBase64; 13 | {{- end}} 14 | import com.qiniu.storage.Api; 15 | {{- if or .IsJsonRequestBody .IsJsonResponseBody }} 16 | import com.qiniu.util.Json; 17 | {{- end}} 18 | {{- if .IsFromRequestBody }} 19 | import com.qiniu.util.StringMap; 20 | {{- end}} 21 | {{ if .HasMapFields }} 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | {{- end}} 25 | {{ .Document }} 26 | public class {{ .ClassName }} extends Api { 27 | 28 | /** 29 | * api 构建函数 30 | * 31 | * @param client 请求 Client 32 | */ 33 | public {{ .ClassName }}(Client client) { 34 | super(client); 35 | } 36 | 37 | /** 38 | * api 构建函数 39 | * 40 | * @param client 请求 Client 41 | * @param config 请求流程的配置信息 42 | **/ 43 | public {{ .ClassName }}(Client client, Config config) { 44 | super(client, config); 45 | } 46 | 47 | /** 48 | * 发起请求 49 | * 50 | * @param request 请求对象【必须】 51 | * @return 响应对象 52 | * @throws QiniuException 请求异常 53 | */ 54 | public Response request(Request request) throws QiniuException { 55 | return new Response(requestWithInterceptor(request)); 56 | } 57 | 58 | {{ .AddIndentation .RequestCode }} 59 | 60 | {{ .AddIndentation .ResponseCode }} 61 | } 62 | -------------------------------------------------------------------------------- /code-gen/templates/java/api_create_class.java: -------------------------------------------------------------------------------- 1 | {{- $classInfo := .}} 2 | /** 3 | * {{.Document}} 4 | */ 5 | public{{if .IsInner}} static{{end}} final class {{ .ClassName }} { 6 | {{- $fieldList := .Fields}}{{if $fieldList}} 7 | {{- range $i, $field := $fieldList}} 8 | 9 | /** 10 | * {{$field.Document}} 11 | */ 12 | @SerializedName("{{$field.Key}}") 13 | private {{$field.Type}} {{$field.Name}}; 14 | {{- end}} 15 | {{- end}} 16 | 17 | {{- $fieldList := .Fields}}{{if $fieldList}} 18 | {{- range $i, $field := $fieldList}} 19 | {{- if $field.PublicGetFunc}} 20 | 21 | /** 22 | * 获取变量值 23 | * {{$field.Document}} 24 | * 25 | * @return {{$field.Name}} 26 | */ 27 | public {{$field.Type}} {{$field.GetFuncName}}() { 28 | return this.{{$field.Name}}; 29 | } 30 | {{- end}} 31 | {{- if $field.PublicSetFunc}} 32 | 33 | /** 34 | * 设置变量值 35 | * 36 | * @param {{$field.Name}} {{$field.Document}} 37 | * @return Request 38 | */ 39 | public {{ $classInfo.ClassName }} {{$field.SetFuncName}}({{$field.Type}} {{$field.Name}}) { 40 | this.{{$field.Name}} = {{$field.Name}}; 41 | return this; 42 | } 43 | {{- end}} 44 | {{- end}} 45 | {{- end}} 46 | } -------------------------------------------------------------------------------- /code-gen/templates/java/api_response.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 响应信息 3 | */ 4 | public static class Response extends Api.Response { 5 | {{- if .IsBodyJson}} 6 | 7 | /** 8 | * {{.BodyField.Document}} 9 | */ 10 | private {{.BodyField.Type}} {{.BodyField.Name}}; 11 | {{- end}} 12 | 13 | protected Response(com.qiniu.http.Response response) throws QiniuException { 14 | super(response); 15 | 16 | {{- if .IsBodyJson}} 17 | 18 | this.{{.BodyField.Name}} = Json.decode(response.bodyString(), {{.BodyField.Type}}.class); 19 | {{- end}} 20 | } 21 | 22 | {{- if .IsBodyJson}} 23 | 24 | /** 25 | * 响应信息 26 | * 27 | * @return {{.BodyField.Type}} 28 | */ 29 | public {{.BodyField.Type}} {{.BodyField.GetFuncName}}() { 30 | return this.{{.BodyField.Name}}; 31 | } 32 | {{- end}} 33 | {{/* 创建 class */}} 34 | {{- $classList := .Classes}}{{if $classList}} 35 | {{- range $i, $classInfo := $classList}} 36 | {{- $classCode := generateClassCode $classInfo }}{{ addIndentation $classCode }} 37 | {{- end}} 38 | {{- end}} 39 | } -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | ci: 3 | - prow.qiniu.io # prow 里面运行需添加,其他 CI 不要 4 | require_ci_to_pass: no # 改为 no,否则 codecov 会等待其他 GitHub 上所有 CI 通过才会留言。 5 | 6 | github_checks: #关闭github checks 7 | annotations: false 8 | 9 | comment: 10 | layout: "reach, diff, flags, files" 11 | behavior: new # 默认是更新旧留言,改为 new,删除旧的,增加新的。 12 | require_changes: false # if true: only post the comment if coverage changes 13 | require_base: no # [yes :: must have a base report to post] 14 | require_head: yes # [yes :: must have a head report to post] 15 | branches: # branch names that can post comment 16 | - "master" 17 | 18 | coverage: 19 | status: # 评判 pr 通过的标准 20 | patch: off 21 | project: # project 统计所有代码x 22 | default: 23 | # basic 24 | target: 60% # 总体通过标准 25 | threshold: 3% # 允许单次下降的幅度 26 | base: auto 27 | if_not_found: success 28 | if_ci_failed: error -------------------------------------------------------------------------------- /examples/BatchDemo.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.common.Zone; 3 | import com.qiniu.http.Response; 4 | import com.qiniu.storage.BucketManager; 5 | import com.qiniu.storage.Configuration; 6 | import com.qiniu.util.Auth; 7 | 8 | 9 | public class BatchDemo { 10 | 11 | public static void main(String args[]) { 12 | //设置需要操作的账号的AK和SK 13 | String ACCESS_KEY = "Access_Key"; 14 | String SECRET_KEY = "Secret_Key"; 15 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 16 | 17 | Zone z = Zone.zone0(); 18 | Configuration c = new Configuration(z); 19 | 20 | //实例化一个BucketManager对象 21 | BucketManager bucketManager = new BucketManager(auth, c); 22 | 23 | //创建 BatchOperations 类型的 operations 对象 24 | BucketManager.BatchOperations operations = new BucketManager.BatchOperations(); 25 | 26 | //第一组源空间名、原文件名,目的空间名、目的文件名 27 | String bucketFrom1 = "yourbucket"; 28 | String keyFrom1 = "srckey1"; 29 | String bucketTo1 = "yourbucket"; 30 | String keyTo1 = "destkey1"; 31 | 32 | //第二组源空间名、原文件名,目的空间名、目的文件名 33 | String bucketFrom2 = "yourbucket"; 34 | String keyFrom2 = "srckey2"; 35 | String bucketTo2 = "yourbucket"; 36 | String keyTo2 = "destkey2"; 37 | 38 | 39 | try { 40 | //调用批量操作的batch方法 41 | Response res = bucketManager.batch(operations.move(bucketFrom1, keyFrom1, bucketTo1, keyTo1) 42 | .move(bucketFrom2, keyFrom2, bucketTo2, keyTo2)); 43 | 44 | System.out.println(res.toString()); 45 | 46 | } catch (QiniuException e) { 47 | //捕获异常信息 48 | Response r = e.response; 49 | System.out.println(r.toString()); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/CdnRefreshDirsDemo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu; 2 | 3 | import com.qiniu.cdn.CdnManager; 4 | import com.qiniu.cdn.CdnResult; 5 | import com.qiniu.common.QiniuException; 6 | import com.qiniu.util.Auth; 7 | 8 | //https://developer.qiniu.com/kodo/sdk/java#fusion-refresh-urls 9 | 10 | public class CdnRefreshDirsDemo { 11 | public static void main(String args[]) { 12 | String accessKey = "your access key"; 13 | String secretKey = "your secret key"; 14 | Auth auth = Auth.create(accessKey, secretKey); 15 | CdnManager c = new CdnManager(auth); 16 | //待刷新的目录列表,目录必须以 / 结尾 17 | String[] dirs = new String[]{ 18 | "http://javasdk.qiniudn.com/gopher1/", 19 | "http://javasdk.qiniudn.com/gopher2/", 20 | //.... 21 | }; 22 | try { 23 | //单次方法调用刷新的目录不可以超过10个,另外刷新目录权限需要联系技术支持开通 24 | CdnResult.RefreshResult result = c.refreshDirs(dirs); 25 | System.out.println(result.code); 26 | //获取其他的回复内容 27 | } catch (QiniuException e) { 28 | System.err.println(e.response.toString()); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /examples/CdnRefreshUrlsDemo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu; 2 | 3 | import com.qiniu.cdn.CdnManager; 4 | import com.qiniu.cdn.CdnResult; 5 | import com.qiniu.common.QiniuException; 6 | import com.qiniu.util.Auth; 7 | 8 | //https://developer.qiniu.com/kodo/sdk/java#fusion-refresh-urls 9 | public class CdnRefreshDemo { 10 | public static void main(String args[]) { 11 | String accessKey = "your access key"; 12 | String secretKey = "your secret key"; 13 | Auth auth = Auth.create(accessKey, secretKey); 14 | CdnManager c = new CdnManager(auth); 15 | //待刷新的链接列表 16 | String[] urls = new String[]{ 17 | "http://javasdk.qiniudn.com/gopher1.jpg", 18 | "http://javasdk.qiniudn.com/gopher2.jpg", 19 | //.... 20 | }; 21 | try { 22 | //单次方法调用刷新的链接不可以超过100个 23 | CdnResult.RefreshResult result = c.refreshUrls(urls); 24 | System.out.println(result.code); 25 | //获取其他的回复内容 26 | } catch (QiniuException e) { 27 | System.err.println(e.response.toString()); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/DomainListDemo.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.common.Zone; 3 | import com.qiniu.http.Response; 4 | import com.qiniu.util.Auth; 5 | 6 | public class DomainListDemo { 7 | public static void main(String args[]) { 8 | //设置需要操作的账号的AK和SK 9 | String ACCESS_KEY = "DWQOcrnPp1ogwgAHBdIK1mI-"; 10 | String SECRET_KEY = "cJFhYuaq7Vo35e1pmXO0aGkJG"; 11 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 12 | 13 | Zone z = Zone.zone0(); 14 | Configuration c = new Configuration(z); 15 | 16 | //实例化一个BucketManager对象 17 | BucketManager bucketManager = new BucketManager(auth, c); 18 | 19 | //要列举文件的空间名 20 | String bucket = "dorst1"; 21 | 22 | try { 23 | String[] domainLists = bucketManager.domainList(bucket); 24 | for (String domain : domainLists) 25 | System.out.print(domain); 26 | 27 | } catch (QiniuException e) { 28 | 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/FetchApiDemo.java: -------------------------------------------------------------------------------- 1 | package com.examples; 2 | 3 | import com.google.gson.Gson; 4 | import com.qiniu.http.Client; 5 | import com.qiniu.util.Auth; 6 | import com.qiniu.util.StringMap; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class FetchApiDemo { 12 | 13 | public static void main(String[] args) throws Exception { 14 | //参考api文档 https://developer.qiniu.com/kodo/api/4097/asynch-fetch 15 | //设置好账号的ACCESS_KEY和SECRET_KEY 16 | String ACCESS_KEY = "Access_Key"; 17 | String SECRET_KEY = "Secret_Key"; 18 | //要上传的空间 19 | String bucketname = "Bucket_Name"; 20 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 21 | // 构造post请求body 22 | Gson gson = new Gson(); 23 | Map m = new HashMap(); 24 | m.put("url", "http://chentaodb.qiniuts.com/1.jpg"); 25 | m.put("bucket", bucketname); 26 | String paraR = gson.toJson(m); 27 | byte[] bodyByte = paraR.getBytes(); 28 | // 获取签名 29 | String url = "http://api-z2.qiniu.com/sisyphus/fetch"; 30 | String accessToken = (String) auth.authorizationV2(url, "POST", bodyByte, "application/json") 31 | .get("Authorization"); 32 | Client client = new Client(); 33 | StringMap headers = new StringMap(); 34 | headers.put("Authorization", accessToken); 35 | try { 36 | com.qiniu.http.Response resp = client.post(url, bodyByte, headers, Client.JsonMime); 37 | } catch (Exception e) { 38 | throw new Exception(e.getMessage()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/FetchDemo.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.common.Zone; 6 | import com.qiniu.storage.Configuration; 7 | 8 | public class FetchDemo { 9 | 10 | public static void main(String args[]) { 11 | //设置需要操作的账号的AK和SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | 16 | Zone z = Zone.zone0(); 17 | Configuration c = new Configuration(z); 18 | 19 | //实例化一个BucketManager对象 20 | BucketManager bucketManager = new BucketManager(auth, c); 21 | 22 | //文件保存的空间名和文件名 23 | String bucket = "yourbucket"; 24 | String key = "yourkey"; 25 | 26 | //要fetch的url 27 | String url = "url"; 28 | 29 | try { 30 | //调用fetch方法抓取文件 31 | bucketManager.fetch(url, bucket, key); 32 | } catch (QiniuException e) { 33 | //捕获异常信息 34 | Response r = e.response; 35 | System.out.println(r.toString()); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /examples/FusionRefreshDemo.java: -------------------------------------------------------------------------------- 1 | package com.examples; 2 | 3 | import com.google.gson.Gson; 4 | import com.qiniu.http.Client; 5 | import com.qiniu.util.Auth; 6 | import com.qiniu.util.StringMap; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class FusionRefreshDemo { 12 | 13 | public static void main(String[] args) throws Exception { 14 | String ACCESS_KEY = "Access_Key"; 15 | String SECRET_KEY = "Secret_Key"; 16 | //要上传的空间 17 | String bucketname = "Bucket_Name"; 18 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 19 | // 构造post请求body 20 | Gson gson = new Gson(); 21 | Map m = new HashMap(); 22 | String[] urls = {"http://neko.chentao.qiniuts.com/1.MP4", 23 | "http://neko.chentao.qiniuts.com/1.mp4"}; 24 | m.put("urls", urls); 25 | String paraR = gson.toJson(m); 26 | byte[] bodyByte = paraR.getBytes(); 27 | // 获取签名 28 | String url = "http://fusion.qiniuapi.com/v2/tune/refresh"; 29 | String accessToken = (String) auth.authorizationV2(url, "POST", bodyByte, "application/json") 30 | .get("Authorization"); 31 | Client client = new Client(); 32 | StringMap headers = new StringMap(); 33 | headers.put("Authorization", accessToken); 34 | try { 35 | com.qiniu.http.Response resp = client.post(url, bodyByte, headers, Client.JsonMime); 36 | } catch (Exception e) { 37 | throw new Exception(e.getMessage()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/GetBucketInfo.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.Zone; 2 | import com.qiniu.storage.BucketManager; 3 | import com.qiniu.storage.Configuration; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.storage.model.BucketInfo; 6 | 7 | public class GetBucketInfo { 8 | 9 | //设置需要操作的账号的AK和SK 10 | String ACCESS_KEY = "Access_Key"; 11 | String SECRET_KEY = "Secret_Key"; 12 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 13 | 14 | //指定区域,可以用 Zone.autoZone() 自动获取 15 | Zone z = Zone.zone0(); 16 | Configuration c = new Configuration(z); 17 | 18 | //实例化一个BucketManager对象 19 | BucketManager bucketManager = new BucketManager(auth, c); 20 | 21 | // 空间名 22 | String bucket = "BUCKET"; 23 | 24 | public static void main(String[] args) { 25 | new GetBucketInfo().getBucketInfo(); 26 | } 27 | 28 | public void getBucketInfo() { 29 | try { 30 | BucketInfo bucketInfo = bucketManager.getBucketInfo(bucket); 31 | // 输出空间私有性 32 | System.out.println(bucketInfo.getPrivate()); 33 | // 输出空间所述区域 34 | System.out.println(bucketInfo.getZone()); 35 | 36 | // 其他参数详见 https://github.com/qiniu/java-sdk/blob/master/src/main/java/com/qiniu/storage/model/BucketInfo.java 37 | 38 | } catch (Exception e) { 39 | // 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/ListDemo.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.storage.model.FileInfo; 5 | import com.qiniu.storage.model.FileListing; 6 | import com.qiniu.util.Auth; 7 | import com.qiniu.common.Zone; 8 | import com.qiniu.storage.Configuration; 9 | 10 | 11 | public class ListDemo { 12 | 13 | public static void main(String args[]) { 14 | //设置需要操作的账号的AK和SK 15 | String ACCESS_KEY = "Access_Key"; 16 | String SECRET_KEY = "Secret_Key"; 17 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 18 | 19 | Zone z = Zone.zone0(); 20 | Configuration c = new Configuration(z); 21 | 22 | //实例化一个BucketManager对象 23 | BucketManager bucketManager = new BucketManager(auth, c); 24 | 25 | //要列举文件的空间名 26 | String bucket = "yourbucket"; 27 | 28 | try { 29 | //调用listFiles方法列举指定空间的指定文件 30 | //参数一:bucket 空间名 31 | //参数二:prefix 文件名前缀 32 | //参数三:marker 上一次获取文件列表时返回的 marker 33 | //参数四:limit 每次迭代的长度限制,最大1000,推荐值 100 34 | //参数五:delimiter 指定目录分隔符,列出所有公共前缀(模拟列出目录效果)。缺省值为空字符串 35 | FileListing fileListing = bucketManager.listFiles(bucket, null, null, 10, null); 36 | FileInfo[] items = fileListing.items; 37 | for (FileInfo fileInfo : items) { 38 | System.out.println(fileInfo.key); 39 | } 40 | } catch (QiniuException e) { 41 | //捕获异常信息 42 | Response r = e.response; 43 | System.out.println(r.toString()); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/QvmUploadDemo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.Zone; 4 | import com.qiniu.http.Response; 5 | import com.qiniu.storage.Configuration; 6 | import com.qiniu.storage.UploadManager; 7 | import com.qiniu.util.Auth; 8 | 9 | /** 10 | * 华东 1 区域(杭州)和华北 2 区域(北京)的云主机 通过内网上传资源到七牛同区域的对象存储空间, 11 | * 并且避免绕行公网带来的网络质量不稳定问题,也可以免去数据在传输过程中被窃取的风险, 12 | * 参考文档:https://developer.qiniu.com/qvm/manual/4269/qvm-kodo 13 | */ 14 | public class QvmUploadDemo { 15 | // 获取凭证 16 | public static void main(String[] args) { 17 | //设置账号的AK,SK 18 | String ACCESS_KEY = "Access_Key"; 19 | String SECRET_KEY = "Secret_Key"; 20 | //要上传的空间 21 | String bucketname = "Bucket_Name"; 22 | //上传到七牛后保存的文件名 23 | String key = "my-java.png"; 24 | //上传文件的路径 25 | String FilePath = "/.../..."; 26 | // 构造一个带指定的zone对象的配置类,华东1区域的云主机可以选择Zone.qvmZone0(),华北2区域(北京)的云主机可以选择Zone.qvmZone1(),目前其他存储区域是不支持 27 | Configuration configuration = new Configuration(Zone.qvmZone0()); 28 | //创建上传对象 29 | UploadManager uploadManager = new UploadManager(configuration); 30 | //秘钥鉴权 31 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 32 | //简单上传,使用默认策略,只需要设置上传的空间名就可以了 33 | String upToken = auth.uploadToken(bucketname); 34 | Response res = null; 35 | try { 36 | //调用上传方法 37 | res = uploadManager.put(FilePath, key, upToken); 38 | } catch (QiniuException e) { 39 | e.printStackTrace(); 40 | } 41 | //打印返回的信息 42 | System.out.println(res.statusCode); 43 | System.out.println(res.toString()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/SendMessageDemo.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.Map; 3 | 4 | import com.qiniu.common.QiniuException; 5 | import com.qiniu.http.Response; 6 | import com.qiniu.sms.SmsManager; 7 | import com.qiniu.util.Auth; 8 | 9 | public class SendMessageDemo { 10 | public static void main(String args[]) { 11 | // 设置需要操作的账号的AK和SK 12 | String ACCESS_KEY = ""; 13 | String SECRET_KEY = ""; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | 16 | // 实例化一个SmsManager对象 17 | SmsManager smsManager = new SmsManager(auth); 18 | 19 | try { 20 | Map map = new HashMap(); 21 | Response resp = smsManager.sendMessage("templateId", new String[]{"10086"}, map); 22 | // Response resp = smsManager.describeSignature("passed", 0, 0); 23 | // Response resp = smsManager.createSignature("signature", "app", 24 | // new String[] { "data:image/gif;base64,xxxxxxxxxx" }); 25 | // Response resp = smsManager.describeTemplate("passed", 0, 0); 26 | // Response resp = smsManager.createTemplate("name", "template", "notification", "test", "signatureId"); 27 | // Response resp = smsManager.modifyTemplate("templateId", "name", "template", "test", "signatureId"); 28 | // Response resp = smsManager.modifySignature("SignatureId", "signature"); 29 | // Response resp = smsManager.deleteSignature("signatureId"); 30 | // Response resp = smsManager.deleteTemplate("templateId"); 31 | System.out.println(resp.bodyString()); 32 | 33 | // SignatureInfo sinfo = smsManager.describeSignatureItems("", 0, 0); 34 | // System.out.println(sinfo.getItems().get(0).getAuditStatus()); 35 | // TemplateInfo tinfo = smsManager.describeTemplateItems("", 0, 0); 36 | // System.out.println(tinfo.getItems().get(0).getAuditStatus()); 37 | 38 | 39 | } catch (QiniuException e) { 40 | System.out.println(e); 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/UploadBySelfDefiningDomain.java: -------------------------------------------------------------------------------- 1 | import com.google.gson.Gson; 2 | import com.qiniu.common.QiniuException; 3 | import com.qiniu.http.Response; 4 | import com.qiniu.storage.Configuration; 5 | import com.qiniu.storage.Region; 6 | import com.qiniu.storage.UploadManager; 7 | import com.qiniu.storage.model.DefaultPutRet; 8 | import com.qiniu.util.Auth; 9 | import com.qiniu.util.StringMap; 10 | 11 | 12 | public class UploadBySelfDefiningDomain { 13 | 14 | private static final String ACCESS_KEY = "填写你们的AK"; 15 | private static final String SECRET_KEY = "填写你们的SK"; 16 | private static final String BUCKET = "存储空间"; 17 | private static final Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 18 | 19 | //自定义上传域名,华东z0,华北z1,华南z2 20 | //上传主要修改 srcup 和 accup 21 | public static Region regionHD() { 22 | return (new Region.Builder()). 23 | srcUpHost("upload-z0.qiniup.com"). 24 | accUpHost("upload-z0.qiniup.com"). 25 | iovipHost("iovip-z0.qbox.me"). 26 | rsHost("rs-z0.qbox.me"). 27 | rsfHost("rsf-z0.qbox.me"). 28 | apiHost("api-z0.qiniu.com").build(); 29 | } 30 | 31 | public static void main(String args[]) throws Exception { 32 | upload(); 33 | } 34 | 35 | public static void upload() throws QiniuException { 36 | Configuration cfg = new Configuration(regionHD()); 37 | //是否指定https上传,默认true 38 | //cfg.useHttpsDomains=false; 39 | UploadManager uploadManager = new UploadManager(cfg); 40 | StringMap policy = new StringMap(); 41 | String upToken = auth.uploadToken(BUCKET, null, 3600, policy); 42 | String localFilePath = "/Users/mini/Downloads/qiniu_test.jpg"; 43 | Response response = uploadManager.put(localFilePath, "qiniu_test.jpg", upToken); 44 | //解析上传成功的结果 45 | DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); 46 | System.out.println(putRet.key); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /examples/UploadBySelfDefiningParam.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.Configuration; 4 | import com.qiniu.storage.Region; 5 | import com.qiniu.storage.UploadManager; 6 | import com.qiniu.util.Auth; 7 | import com.qiniu.util.StringMap; 8 | 9 | /** 10 | * 设置自定义变量上传并接收自定义变量 demo 11 | *

12 | * 自定义变量需要以 x: 开头, 携带自定义变量上传参考文档 13 | * https://developer.qiniu.com/kodo/manual/1235/vars#2 14 | *

15 | * 接收自定义变量参考上传策略文档 -- returnBody 16 | * https://developer.qiniu.com/kodo/manual/1206/put-policy 17 | *

18 | * 服务端具体用法实例参考 UploadBySelfDefiningParam.upload() 19 | */ 20 | public class UploadBySelfDefiningParam { 21 | 22 | private static final String ACCESS_KEY = "设置好你们自己的AK"; 23 | private static final String SECRET_KEY = "设置好你们自己的SK"; 24 | private static final Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 25 | 26 | private Configuration cfg; 27 | private UploadManager uploadManager; 28 | private Region region; 29 | private String bucket; 30 | 31 | { 32 | bucket = "设置你们自己的上传空间名称"; 33 | //指定存储空间所在区域,华北region1,华南region2 ,华东 region0 34 | region = Region.region1(); 35 | //初始化cfg实例,可以指定上传区域,也可以创建无参实例 , cfg = new Configuration(); 36 | cfg = new Configuration(region); 37 | //是否指定https上传,默认true 38 | //cfg.useHttpsDomains=false; 39 | //构建 uploadManager 实例 40 | uploadManager = new UploadManager(cfg); 41 | } 42 | 43 | public static void main(String args[]) throws Exception { 44 | UploadBySelfDefiningParam up = new UploadBySelfDefiningParam(); 45 | up.upload(); 46 | } 47 | 48 | public void upload() throws QiniuException { 49 | //设置上传后的文件名称 50 | String key = "qiniu_test.jpg"; 51 | //上传策略 52 | StringMap policy = new StringMap(); 53 | //自定义上传后返回内容,返回自定义参数,需要设置 x:参数名称 54 | policy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"fname\":\"$(x:fname)\",\"age\",$(x:age)}"); 55 | //生成上传token 56 | String upToken = auth.uploadToken(bucket, key, 3600, policy); 57 | 58 | //上传自定义参数,自定义参数名称需要以 x:开头 59 | StringMap params = new StringMap(); 60 | params.put("x:fname", "123.jpg"); 61 | params.put("x:age", 20); 62 | String localFilePath = "/Users/mini/Downloads/qiniu_test.jpg"; 63 | 64 | Response response = uploadManager.put(localFilePath, key, upToken, params, null, false); 65 | //输出返回结果 66 | System.out.println(response.bodyString()); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /examples/copy.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.common.Zone; 6 | import com.qiniu.storage.Configuration; 7 | 8 | public class BucketManagerDemo { 9 | 10 | public static void main(String args[]) { 11 | //设置需要操作的账号的AK和SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | 16 | Zone z = Zone.zone0(); 17 | Configuration c = new Configuration(z); 18 | 19 | //实例化一个BucketManager对象 20 | BucketManager bucketManager = new BucketManager(auth, c); 21 | //要测试的空间和key,并且这个key在你空间中存在 22 | String bucket = "Bucket_Name"; 23 | String key = "Bucket_key"; 24 | //将文件从文件key 复制到文件key2。 可以在不同bucket复制 25 | String key2 = "yourjavakey"; 26 | try { 27 | //调用copy方法移动文件 28 | bucketManager.copy(bucket, key, bucket, key2); 29 | } catch (QiniuException e) { 30 | //捕获异常信息 31 | Response r = e.response; 32 | System.out.println(r.toString()); 33 | } 34 | } -------------------------------------------------------------------------------- /examples/delete.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.common.Zone; 6 | import com.qiniu.storage.Configuration; 7 | 8 | public class BucketManagerDemo { 9 | 10 | public static void main(String args[]) { 11 | //设置需要操作的账号的AK和SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | 16 | Zone z = Zone.zone0(); 17 | Configuration c = new Configuration(z); 18 | 19 | //实例化一个BucketManager对象 20 | BucketManager bucketManager = new BucketManager(auth, c); 21 | //要测试的空间和key,并且这个key在你空间中存在 22 | String bucket = "Bucket_Name"; 23 | String key = "Bucket_key"; 24 | try { 25 | //调用delete方法移动文件 26 | bucketManager.delete(bucket, key); 27 | } catch (QiniuException e) { 28 | //捕获异常信息 29 | Response r = e.response; 30 | System.out.println(r.toString()); 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /examples/download.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.util.Auth; 2 | 3 | public class DownloadDemo { 4 | //设置好账号的ACCESS_KEY和SECRET_KEY 5 | String ACCESS_KEY = "Access_Key"; 6 | String SECRET_KEY = "Secret_Key"; 7 | //密钥配置 8 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 9 | //构造私有空间的需要生成的下载的链接 10 | String URL = "http://bucketdomain/key"; 11 | 12 | public static void main(String args[]) { 13 | new DownloadDemo().download(); 14 | } 15 | 16 | public void download() { 17 | //调用privateDownloadUrl方法生成下载链接,第二个参数可以设置Token的过期时间 18 | String downloadRUL = auth.privateDownloadUrl(URL, 3600); 19 | System.out.println(downloadRUL); 20 | } 21 | } -------------------------------------------------------------------------------- /examples/fops.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.processing.OperationManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | import com.qiniu.util.UrlSafeBase64; 7 | import com.qiniu.common.Zone; 8 | import com.qiniu.storage.Configuration; 9 | 10 | public class OperateDemo { 11 | 12 | public static void main(String[] args) throws QiniuException { 13 | //设置账号的AK,SK 14 | String ACCESS_KEY = "Access_Key"; 15 | String SECRET_KEY = "Secret_Key"; 16 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 17 | 18 | Zone z = Zone.zone0(); 19 | Configuration c = new Configuration(z); 20 | 21 | //新建一个OperationManager对象 22 | OperationManager operater = new OperationManager(auth, c); 23 | //设置要转码的空间和key,并且这个key在你空间中存在 24 | String bucket = "Bucket_Name"; 25 | String key = "Bucket_key"; 26 | //设置转码操作参数 27 | String fops = "avthumb/mp4/s/640x360/vb/1.25m"; 28 | //设置转码的队列 29 | String pipeline = "yourpipelinename"; 30 | //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。 31 | String urlbase64 = UrlSafeBase64.encodeToString("目标Bucket_Name:自定义文件key"); 32 | String pfops = fops + "|saveas/" + urlbase64; 33 | //设置pipeline参数 34 | StringMap params = new StringMap().putWhen("force", 1, true).putNotEmpty("pipeline", pipeline); 35 | try { 36 | String persistid = operater.pfop(bucket, key, pfops, params); 37 | //打印返回的persistid 38 | System.out.println(persistid); 39 | } catch (QiniuException e) { 40 | //捕获异常信息 41 | Response r = e.response; 42 | // 请求失败时简单状态信息 43 | System.out.println(r.toString()); 44 | try { 45 | // 响应的文本信息 46 | System.out.println(r.bodyString()); 47 | } catch (QiniuException e1) { 48 | //ignore 49 | } 50 | } 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /examples/move.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.common.Zone; 6 | import com.qiniu.storage.Configuration; 7 | 8 | public class BucketManagerDemo { 9 | 10 | public static void main(String args[]) { 11 | //设置需要操作的账号的AK和SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | 16 | Zone z = Zone.zone0(); 17 | Configuration c = new Configuration(z); 18 | 19 | //实例化一个BucketManager对象 20 | BucketManager bucketManager = new BucketManager(auth, c); 21 | //要测试的空间和key,并且这个key在你空间中存在 22 | String bucket = "Bucket_Name"; 23 | String key = "Bucket_key"; 24 | //将文件从文件key移动到文件key2, 可以在不同bucket移动,同空间移动相当于重命名 25 | String key2 = "yourjavakey"; 26 | try { 27 | //调用move方法移动文件 28 | bucketManager.move(bucket, key, bucket, key2); 29 | } catch (QiniuException e) { 30 | //捕获异常信息 31 | Response r = e.response; 32 | System.out.println(r.toString()); 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /examples/pfop_vframe.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.processing.OperationManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | import com.qiniu.util.UrlSafeBase64; 7 | 8 | public class OperateDemo { 9 | 10 | public static void main(String[] args) throws QiniuException { 11 | //设置账号的AK,SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | //新建一个OperationManager对象 16 | OperationManager operater = new OperationManager(auth); 17 | //设置要转码的空间和key,并且这个key在你空间中存在 18 | String bucket = "Bucket_Name"; 19 | String key = "Bucket_key"; 20 | //设置转码操作参数 21 | String fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90"; 22 | //设置转码的队列 23 | String pipeline = "yourpipelinename"; 24 | //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。 25 | String urlbase64 = UrlSafeBase64.encodeToString("目标Bucket_Name:自定义文件key"); 26 | String pfops = fops + "|saveas/" + urlbase64; 27 | //设置pipeline参数 28 | StringMap params = new StringMap().putWhen("force", 1, true).putNotEmpty("pipeline", pipeline); 29 | try { 30 | String persistid = operater.pfop(bucket, key, pfops, params); 31 | //打印返回的persistid 32 | System.out.println(persistid); 33 | } catch (QiniuException e) { 34 | //捕获异常信息 35 | Response r = e.response; 36 | // 请求失败时简单状态信息 37 | System.out.println(r.toString()); 38 | try { 39 | // 响应的文本信息 40 | System.out.println(r.bodyString()); 41 | } catch (QiniuException e1) { 42 | //ignore 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /examples/pfop_watermark.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.processing.OperationManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | import com.qiniu.util.UrlSafeBase64; 7 | 8 | public class OperateDemo { 9 | 10 | public static void main(String[] args) throws QiniuException { 11 | //设置账号的AK,SK 12 | String ACCESS_KEY = "Access_Key"; 13 | String SECRET_KEY = "Secret_Key"; 14 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 15 | //新建一个OperationManager对象 16 | OperationManager operater = new OperationManager(auth); 17 | //设置要转码的空间和key,并且这个key在你空间中存在 18 | String bucket = "Bucket_Name"; 19 | String key = "Bucket_key"; 20 | //需要添加水印的图片UrlSafeBase64,可以参考http://developer.qiniu.com/code/v6/api/dora-api/av/video-watermark.html 21 | String pictureurl = UrlSafeBase64.encodeToString("http://developer.qiniu.com/resource/logo-2.jpg"); 22 | //设置转码操作参数 23 | String fops = "avthumb/mp4/s/640x360/vb/1.25m/wmImage/" + pictureurl; 24 | //设置转码的队列 25 | String pipeline = "yourpipelinename"; 26 | //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。 27 | String urlbase64 = UrlSafeBase64.encodeToString("目标Bucket_Name:自定义文件key"); 28 | String pfops = fops + "|saveas/" + urlbase64; 29 | //设置pipeline参数 30 | StringMap params = new StringMap().putWhen("force", 1, true).putNotEmpty("pipeline", pipeline); 31 | try { 32 | String persistid = operater.pfop(bucket, key, pfops, params); 33 | //打印返回的persistid 34 | System.out.println(persistid); 35 | } catch (QiniuException e) { 36 | //捕获异常信息 37 | Response r = e.response; 38 | // 请求失败时简单状态信息 39 | System.out.println(r.toString()); 40 | try { 41 | // 响应的文本信息 42 | System.out.println(r.bodyString()); 43 | } catch (QiniuException e1) { 44 | //ignore 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /examples/stat.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.BucketManager; 4 | import com.qiniu.storage.model.FileInfo; 5 | import com.qiniu.util.Auth; 6 | import com.qiniu.common.Zone; 7 | import com.qiniu.storage.Configuration; 8 | 9 | public class BucketManagerDemo { 10 | 11 | public static void main(String args[]) { 12 | //设置需要操作的账号的AK和SK 13 | String ACCESS_KEY = "Access_Key"; 14 | String SECRET_KEY = "Secret_Key"; 15 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 16 | 17 | Zone z = Zone.zone0(); 18 | Configuration c = new Configuration(z); 19 | 20 | //实例化一个BucketManager对象 21 | BucketManager bucketManager = new BucketManager(auth, c); 22 | //要测试的空间和key,并且这个key在你空间中存在 23 | String bucket = "Bucket_Name"; 24 | String key = "Bucket_key"; 25 | try { 26 | //调用stat()方法获取文件的信息 27 | FileInfo info = bucketManager.stat(bucket, key); 28 | System.out.println(info.hash); 29 | System.out.println(info.key); 30 | } catch (QiniuException e) { 31 | //捕获异常信息 32 | Response r = e.response; 33 | System.out.println(r.toString()); 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /examples/upload.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.UploadManager; 4 | import com.qiniu.common.Zone; 5 | import com.qiniu.storage.Configuration; 6 | import com.qiniu.util.Auth; 7 | 8 | import java.io.IOException; 9 | 10 | 11 | public class UploadDemo { 12 | //设置好账号的ACCESS_KEY和SECRET_KEY 13 | String ACCESS_KEY = "Access_Key"; 14 | String SECRET_KEY = "Secret_Key"; 15 | //要上传的空间 16 | String bucketname = "Bucket_Name"; 17 | //上传到七牛后保存的文件名 18 | String key = "my-java.png"; 19 | //上传文件的路径 20 | String FilePath = "/.../..."; 21 | 22 | //密钥配置 23 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 24 | 25 | ///////////////////////指定上传的Zone的信息////////////////// 26 | //第一种方式: 指定具体的要上传的zone 27 | //注:该具体指定的方式和以下自动识别的方式选择其一即可 28 | //要上传的空间(bucket)的存储区域为华东时 29 | // Zone z = Zone.zone0(); 30 | //要上传的空间(bucket)的存储区域为华北时 31 | // Zone z = Zone.zone1(); 32 | //要上传的空间(bucket)的存储区域为华南时 33 | // Zone z = Zone.zone2(); 34 | 35 | //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。 36 | Zone z = Zone.autoZone(); 37 | Configuration c = new Configuration(z); 38 | 39 | //创建上传对象 40 | UploadManager uploadManager = new UploadManager(c); 41 | 42 | public static void main(String args[]) throws IOException { 43 | new UploadDemo().upload(); 44 | } 45 | 46 | //简单上传,使用默认策略,只需要设置上传的空间名就可以了 47 | public String getUpToken() { 48 | return auth.uploadToken(bucketname); 49 | } 50 | 51 | public void upload() throws IOException { 52 | try { 53 | //调用put方法上传 54 | Response res = uploadManager.put(FilePath, key, getUpToken()); 55 | //打印返回的信息 56 | System.out.println(res.bodyString()); 57 | } catch (QiniuException e) { 58 | Response r = e.response; 59 | // 请求失败时打印的异常的信息 60 | System.out.println(r.toString()); 61 | try { 62 | //响应的文本信息 63 | System.out.println(r.bodyString()); 64 | } catch (QiniuException e1) { 65 | //ignore 66 | } 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /examples/upload_ recorder.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.Recorder; 4 | import com.qiniu.storage.UploadManager; 5 | import com.qiniu.storage.persistent.FileRecorder; 6 | import com.qiniu.util.Auth; 7 | import com.qiniu.common.Zone; 8 | import com.qiniu.storage.Configuration; 9 | 10 | import java.io.IOException; 11 | 12 | public class UploadDemo { 13 | 14 | //设置好账号的ACCESS_KEY和SECRET_KEY 15 | String ACCESS_KEY = "Access_Key"; 16 | String SECRET_KEY = "Secret_Key"; 17 | //要上传的空间 18 | String bucketname = "Bucket_Name"; 19 | //上传到七牛后保存的文件名 20 | String key = "my-java.png"; 21 | //上传文件的路径 22 | String filePath = "/.../..."; 23 | 24 | //密钥配置 25 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 26 | 27 | ///////////////////////指定上传的Zone的信息////////////////// 28 | //第一种方式: 指定具体的要上传的zone 29 | //注:该具体指定的方式和以下自动识别的方式选择其一即可 30 | //要上传的空间(bucket)的存储区域为华东时 31 | // Zone z = Zone.zone0(); 32 | //要上传的空间(bucket)的存储区域为华北时 33 | // Zone z = Zone.zone1(); 34 | //要上传的空间(bucket)的存储区域为华南时 35 | // Zone z = Zone.zone2(); 36 | 37 | //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。 38 | Zone z = Zone.autoZone(); 39 | Configuration c = new Configuration(z); 40 | 41 | //创建上传对象 42 | UploadManager uploadManager = new UploadManager(c); 43 | 44 | public static void main(String args[]) throws IOException { 45 | new UploadDemo().upload(); 46 | } 47 | 48 | // 覆盖上传 49 | public String getUpToken() { 50 | return auth.uploadToken(bucketname); 51 | } 52 | 53 | public void upload() throws IOException { 54 | //设置断点记录文件保存在指定文件夹或的File对象 55 | String recordPath = "/.../..."; 56 | //实例化recorder对象 57 | Recorder recorder = new FileRecorder(recordPath); 58 | //实例化上传对象,并且传入一个recorder对象 59 | UploadManager uploadManager = new UploadManager(recorder); 60 | 61 | try { 62 | //调用put方法上传 63 | Response res = uploadManager.put("path/file", "key", getUpToken()); 64 | //打印返回的信息 65 | System.out.println(res.bodyString()); 66 | } catch (QiniuException e) { 67 | Response r = e.response; 68 | // 请求失败时打印的异常的信息 69 | System.out.println(r.toString()); 70 | try { 71 | //响应的文本信息 72 | System.out.println(r.bodyString()); 73 | } catch (QiniuException e1) { 74 | //ignore 75 | } 76 | } 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /examples/upload_callback.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.UploadManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | 7 | import java.io.IOException; 8 | 9 | import com.qiniu.common.QiniuException; 10 | import com.qiniu.http.Response; 11 | import com.qiniu.storage.UploadManager; 12 | import com.qiniu.common.Zone; 13 | import com.qiniu.storage.Configuration; 14 | 15 | public class UploadDemo { 16 | //设置好账号的ACCESS_KEY和SECRET_KEY 17 | String ACCESS_KEY = "Access_Key"; 18 | String SECRET_KEY = "Secret_Key"; 19 | //要上传的空间 20 | String bucketname = "Bucket_Name"; 21 | //上传到七牛后保存的文件名 22 | String key = "my-java.png"; 23 | //上传文件的路径 24 | String FilePath = "/.../..."; 25 | 26 | //密钥配置 27 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 28 | 29 | ///////////////////////指定上传的Zone的信息////////////////// 30 | //第一种方式: 指定具体的要上传的zone 31 | //注:该具体指定的方式和以下自动识别的方式选择其一即可 32 | //要上传的空间(bucket)的存储区域为华东时 33 | // Zone z = Zone.zone0(); 34 | //要上传的空间(bucket)的存储区域为华北时 35 | // Zone z = Zone.zone1(); 36 | //要上传的空间(bucket)的存储区域为华南时 37 | // Zone z = Zone.zone2(); 38 | 39 | //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。 40 | Zone z = Zone.autoZone(); 41 | Configuration c = new Configuration(z); 42 | 43 | //创建上传对象 44 | UploadManager uploadManager = new UploadManager(c); 45 | 46 | public static void main(String args[]) throws IOException { 47 | new UploadDemo().upload(); 48 | } 49 | 50 | //设置callbackUrl以及callbackBody,七牛将文件名和文件大小回调给业务服务器 51 | public String getUpToken() { 52 | return auth.uploadToken(bucketname, null, 3600, new StringMap() 53 | .put("callbackUrl", "http://your.domain.com/callback") 54 | .put("callbackBody", "filename=$(fname)&filesize=$(fsize)")); 55 | } 56 | 57 | public void upload() throws IOException { 58 | try { 59 | //调用put方法上传 60 | Response res = uploadManager.put(FilePath, null, getUpToken()); 61 | //打印返回的信息 62 | System.out.println(res.bodyString()); 63 | } catch (QiniuException e) { 64 | Response r = e.response; 65 | // 请求失败时打印的异常的信息 66 | System.out.println(r.toString()); 67 | try { 68 | //响应的文本信息 69 | System.out.println(r.bodyString()); 70 | } catch (QiniuException e1) { 71 | //ignore 72 | } 73 | } 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /examples/upload_overwrite.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.UploadManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | import com.qiniu.common.Zone; 7 | import com.qiniu.storage.Configuration; 8 | 9 | import java.io.IOException; 10 | 11 | public class UploadDemo { 12 | //设置好账号的ACCESS_KEY和SECRET_KEY 13 | String ACCESS_KEY = "Access_Key"; 14 | String SECRET_KEY = "Secret_Key"; 15 | //要上传的空间 16 | String bucketname = "Bucket_Name"; 17 | //上传到七牛后保存的文件名 18 | String key = "my-java.png"; 19 | //上传文件的路径 20 | String filePath = "/.../..."; 21 | 22 | //密钥配置 23 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 24 | 25 | ///////////////////////指定上传的Zone的信息////////////////// 26 | //第一种方式: 指定具体的要上传的zone 27 | //注:该具体指定的方式和以下自动识别的方式选择其一即可 28 | //要上传的空间(bucket)的存储区域为华东时 29 | // Zone z = Zone.zone0(); 30 | //要上传的空间(bucket)的存储区域为华北时 31 | // Zone z = Zone.zone1(); 32 | //要上传的空间(bucket)的存储区域为华南时 33 | // Zone z = Zone.zone2(); 34 | 35 | //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。 36 | Zone z = Zone.autoZone(); 37 | Configuration c = new Configuration(z); 38 | 39 | //创建上传对象 40 | UploadManager uploadManager = new UploadManager(c); 41 | 42 | // 覆盖上传 43 | public String getUpToken() { 44 | //:,表示只允许用户上传指定key的文件。在这种格式下文件默认允许“修改”,已存在同名资源则会被本次覆盖。 45 | //如果希望只能上传指定key的文件,并且不允许修改,那么可以将下面的 insertOnly 属性值设为 1。 46 | //第三个参数是token的过期时间 47 | return auth.uploadToken(bucketname, key, 3600); 48 | } 49 | 50 | // 覆盖上传 51 | public String getUpToken() { 52 | //:,表示只允许用户上传指定key的文件。在这种格式下文件默认允许“修改”,已存在同名资源则会被本次覆盖。 53 | //如果希望只能上传指定key的文件,并且不允许修改,那么可以将下面的 insertOnly 属性值设为 1。 54 | //第三个参数是token的过期时间 55 | return auth.uploadToken(bucketname, key, 3600, new StringMap().put("insertOnly", 1)); 56 | } 57 | 58 | public void upload() throws IOException { 59 | try { 60 | //调用put方法上传,这里指定的key和上传策略中的key要一致 61 | Response res = uploadManager.put(filePath, key, getUpToken()); 62 | //打印返回的信息 63 | System.out.println(res.bodyString()); 64 | } catch (QiniuException e) { 65 | Response r = e.response; 66 | // 请求失败时打印的异常的信息 67 | System.out.println(r.toString()); 68 | try { 69 | //响应的文本信息 70 | System.out.println(r.bodyString()); 71 | } catch (QiniuException e1) { 72 | //ignore 73 | } 74 | } 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /examples/upload_pfops.java: -------------------------------------------------------------------------------- 1 | import com.qiniu.common.QiniuException; 2 | import com.qiniu.http.Response; 3 | import com.qiniu.storage.UploadManager; 4 | import com.qiniu.util.Auth; 5 | import com.qiniu.util.StringMap; 6 | import com.qiniu.util.UrlSafeBase64; 7 | 8 | import java.io.IOException; 9 | 10 | import com.qiniu.common.QiniuException; 11 | import com.qiniu.http.Response; 12 | import com.qiniu.storage.UploadManager; 13 | import com.qiniu.storage.Configuration; 14 | import com.qiniu.common.Zone; 15 | 16 | public class UploadDemo { 17 | //设置好账号的ACCESS_KEY和SECRET_KEY 18 | String ACCESS_KEY = "Access_Key"; 19 | String SECRET_KEY = "Secret_Key"; 20 | //要上传的空间 21 | String bucketname = "Bucket_Name"; 22 | //上传到七牛后保存的文件名 23 | String key = "my-java.png"; 24 | //上传文件的路径 25 | String FilePath = "/.../..."; 26 | 27 | //设置转码操作参数 28 | String fops = "avthumb/mp4/s/640x360/vb/1.25m"; 29 | //设置转码的队列 30 | String pipeline = "yourpipelinename"; 31 | 32 | //可以对转码后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间。 33 | String urlbase64 = UrlSafeBase64.encodeToString("目标Bucket_Name:自定义文件key"); 34 | String pfops = fops + "|saveas/" + urlbase64; 35 | 36 | //密钥配置 37 | Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY); 38 | 39 | ///////////////////////指定上传的Zone的信息////////////////// 40 | //第一种方式: 指定具体的要上传的zone 41 | //注:该具体指定的方式和以下自动识别的方式选择其一即可 42 | //要上传的空间(bucket)的存储区域为华东时 43 | // Zone z = Zone.zone0(); 44 | //要上传的空间(bucket)的存储区域为华北时 45 | // Zone z = Zone.zone1(); 46 | //要上传的空间(bucket)的存储区域为华南时 47 | // Zone z = Zone.zone2(); 48 | 49 | //第二种方式: 自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。 50 | Zone z = Zone.autoZone(); 51 | Configuration c = new Configuration(z); 52 | 53 | //创建上传对象 54 | UploadManager uploadManager = new UploadManager(c); 55 | 56 | 57 | public static void main(String args[]) throws IOException { 58 | new UploadDemo().upload(); 59 | } 60 | 61 | //上传策略中设置persistentOps字段和persistentPipeline字段 62 | public String getUpToken() { 63 | return auth.uploadToken(bucketname, null, 3600, new StringMap() 64 | .putNotEmpty("persistentOps", pfops) 65 | .putNotEmpty("persistentPipeline", pipeline), true); 66 | } 67 | 68 | public void upload() throws IOException { 69 | try { 70 | //调用put方法上传 71 | Response res = uploadManager.put(FilePath, null, getUpToken()); 72 | //打印返回的信息 73 | System.out.println(res.bodyString()); 74 | } catch (QiniuException e) { 75 | Response r = e.response; 76 | // 请求失败时打印的异常的信息 77 | System.out.println(r.toString()); 78 | try { 79 | //响应的文本信息 80 | System.out.println(r.bodyString()); 81 | } catch (QiniuException e1) { 82 | //ignore 83 | } 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /examples/关于回调流程.md: -------------------------------------------------------------------------------- 1 | 一般的上传流程是用户获得上传凭证之后直接将资源上传到七牛空间,然后七牛回返回一个上传成功或者失败的信息,用户业务服务器是不清楚这些信息的,可以参考下面的流程图: 2 | ![不设置回调](http://7xkn2v.dl1.z0.glb.clouddn.com/QQ20151019-0@2x.png) 3 | 4 | 另外一种方式是用户在上传的时候设置回调,则七牛会在用户上传成功后将上传资源的元信息以json格式POST到用户设置的callbackurl,用户业务服务器收到这些信息时可以将其进行保存( 5 | 比如保存到数据库里面方面查询),但是到这一步并没有结束,用户业务服务器还需要对七牛服务器这次回调做出响应,同样是响应一个json格式的数据给七牛服务器,七牛会将回调的信息返回给上传客户端,流程参考如下: 6 | ![设置回调](http://7xkn2v.dl1.z0.glb.clouddn.com/QQ20151019-1@2x.png) 7 | 8 | 以下是具体回调过程: 9 | 10 | 1. 上传策略里面设置好callbackurl以及callbackbody,callbackHost和callbackBodyType这两个字段都是可以默认不设置的,关于这两个参数的规则可以参考七牛的上传策略文档: 11 | http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html 12 | 这个例子设置的callbackbody是: 13 | `"hash=$(etag)&key=$(key)&fsize=$(fsize)&mimeType=$(mimeType)"` 14 | 15 | 2.业务服务器设置接收该回调以及返回json的程序代码,可以参考: 16 | 17 | ``` 18 | public void doPost(HttpServletRequest request, HttpServletResponse response) 19 | throws ServletException, IOException { 20 | 21 | response.setContentType("text/html"); 22 | PrintWriter out = response.getWriter(); 23 | 24 | //接收七牛回调过来的内容 25 | String line=""; 26 | BufferedReader br=new BufferedReader(new InputStreamReader(request.getInputStream())); 27 | StringBuilder sb = new StringBuilder(); 28 | while((line = br.readLine())!=null){ 29 | sb.append(line); 30 | } 31 | System.out.println(sb);//打印回调内容 32 | 33 | //设置返回给七牛的json格式的数据 34 | JsonObject json=new JsonObject(); 35 | json.addProperty("response", "success"); 36 | out.println(json.toString()); 37 | 38 | out.flush(); 39 | out.close(); 40 | } 41 | ``` 42 | 43 | 3.业务服务器可以接收到该回调信息如下: 44 | ![业务服务器收到的回调信息](http://7xkn2v.dl1.z0.glb.clouddn.com/QQ20151019-5@2x.png) 45 | 46 | 客户端上传之后可以看到业务服务器返回的json数据: 47 | ![客户端收到的回调信息](http://7xkn2v.dl1.z0.glb.clouddn.com/QQ20151019-4@2x.png) 48 | 49 | -------------------------------------------------------------------------------- /examples/关于设置notifyURL没有收到回调.md: -------------------------------------------------------------------------------- 1 | ##七牛设置notifyURL没有收到回调 2 | 3 | 在使用七牛进行数据处理时用户可以使用 4 | 来主动查询持久化处理的执行状态,具体查询方法是发送一个Get请求:http://api.qiniu.com/status/get/prefop?id= 5 | 可以参考: 6 | http://developer.qiniu.com/docs/v6/api/reference/fop/pfop/prefop.html 7 | 8 | 但是调用查询的成本比较高,还得起脚本实时去遍历查询,如果能回调,就可以省掉这个工作了。 9 | 10 | 正好七牛这边针对上传预转持续化和触发持续化分别提供persistentNotifyUrl和notifyUrl讲处理结果POST到用户业务服务器,用户那边设置解析打印出处理结果就可以了。 11 | 12 | 那么问题来了,有的用户在使用过程中出现接受不到处理的结果,这种情况一般都是用户那边自己的问题,那应该怎样处理呢? 13 | 1.检查下用户设置的persistentNotifyUrl以及notifyUrl,必须是公网上可以正常进行POST请求并能响应HTTP/1.1 200 14 | OK的有效URL,可以使用curl访问下看是否满足这个条件。 15 | 另外,七牛这边发送body格式为Content-Type为"application/json"的POST请求,用户回调服务器需要按照读取流的形式读取请求的body才能获取。 16 | 17 | 2.如果第一个条件满足的情况,我们可以检测下用户后端设定的接收回调处理的程序是否是正常的,对此,我们可以主动POST一个数据给用户的回调服务器: 18 | eg:curl -vX POST "URL" -d "name=123.jpg" 19 | 用户那边如果能够正常打印出该内容,说明用户的接收程序是没有问题的。 20 | 21 | 3.如果以上条件都没有问题的情况下,应该是用户持续化处理本身的代码是有问题的,应该是用户设置的persistentNotifyUrl或者notifyurl没有设置成功,这个时候我们可以让用户在程序里面调试打印下这个URL的值,或者提供下返回的persistentID我们可以请求下获得ReqID然后在日志机上查询下是否是正确的,比如,之前查到的一个结果如下: 22 | url.Values{"notifyURL":[]string{""}, "force":[]string{""}} 23 | 这就明显看出用户设置的notifyURL是没有传进去的。 24 | 25 | 这时,我们可以让用户提供下代码,检查下用户代码参数设置是否是有问题的,因为,* 26 | *不同的语言对于notifyURL参数的写法是有问题的,比如java里面写法是notifyURL,而PHP里面该字段是notifyUrl** 27 | ,经排查果然,用户用的是PHP语言,但是里面设置notifyURL字段应该是: 28 | $notifyUrl = 'http://notify.fake.com'; 29 | 但用户设置的是$notifyURL,参数设置是有问题的 30 | 31 | 另外,可以参考java中Servlet回调处理的代码: 32 | 33 | ``` 34 | public class notify extends HttpServlet { 35 | 36 | public notify() { 37 | super(); 38 | } 39 | 40 | public void doGet(HttpServletRequest request, HttpServletResponse response) 41 | throws ServletException, IOException { 42 | 43 | response.setContentType("text/html"); 44 | response.setCharacterEncoding("gb2312"); 45 | PrintWriter out = response.getWriter(); 46 | 47 | 48 | request.getInputStream(); 49 | 50 | String line=""; 51 | BufferedReader br=new BufferedReader(new InputStreamReader( 52 | request.getInputStream())); 53 | StringBuilder sb = new StringBuilder(); 54 | while((line = br.readLine())!=null){ 55 | sb.append(line); 56 | } 57 | System.out.println( sb); 58 | 59 | } 60 | } 61 | ``` 62 | 63 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | VERSION_NAME= 2 | VERSION_CODE= 3 | GROUP=com.qiniu 4 | POM_DESCRIPTION=Qiniu Cloud Storage SDK for Java 5 | POM_URL=https://github.com/qiniu/java-sdk 6 | POM_SCM_URL=https://github.com/qiniu/java-sdk 7 | POM_SCM_CONNECTION=scm:git@github.com:qiniu/java-sdk.git 8 | POM_SCM_DEV_CONNECTION=scm:git@github.com:qiniu/java-sdk.git 9 | POM_LICENCE_NAME=MIT License 10 | POM_LICENCE_URL=http://opensource.org/licenses/MIT 11 | POM_LICENCE_DIST=repo 12 | POM_DEVELOPER_ID=qiniu 13 | POM_DEVELOPER_NAME=Qiniu 14 | POM_ARTIFACT_ID=qiniu-java-sdk 15 | POM_NAME=qiniu-java-sdk 16 | POM_PACKAGING=jar 17 | POM_INCEPTION_YEAR=2012 18 | POM_EMAIL=sdk@qiniu.com -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiniu/java-sdk/01d63732dc94582f49eb63989e5f86bd0bf5c20e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 20 14:26:10 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'qiniu-java-sdk' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.common; 2 | 3 | import java.io.File; 4 | import java.nio.charset.Charset; 5 | 6 | /** 7 | * SDK相关配置常量 8 | */ 9 | public final class Constants { 10 | /** 11 | * 版本号 12 | */ 13 | public static final String VERSION = "7.18.0"; 14 | /** 15 | * 块大小,不能改变 16 | */ 17 | public static final int BLOCK_SIZE = 4 * 1024 * 1024; 18 | /** 19 | * 所有都是UTF-8编码 20 | */ 21 | public static final Charset UTF_8 = Charset.forName("UTF-8"); 22 | /** 23 | * 连接超时时间 单位秒(默认10s) 24 | */ 25 | public static final int CONNECT_TIMEOUT = 10; 26 | /** 27 | * 写超时时间 单位秒(默认 0 , 不超时) 28 | */ 29 | public static final int WRITE_TIMEOUT = 0; 30 | /** 31 | * 回复超时时间 单位秒(默认30s) 32 | */ 33 | public static final int READ_TIMEOUT = 30; 34 | /** 35 | * 底层HTTP库所有的并发执行的请求数量 36 | */ 37 | public static final int DISPATCHER_MAX_REQUESTS = 64; 38 | /** 39 | * 底层HTTP库对每个独立的Host进行并发请求的数量 40 | */ 41 | public static final int DISPATCHER_MAX_REQUESTS_PER_HOST = 16; 42 | /** 43 | * 底层HTTP库中复用连接对象的最大空闲数量 44 | */ 45 | public static final int CONNECTION_POOL_MAX_IDLE_COUNT = 32; 46 | /** 47 | * 底层HTTP库中复用连接对象的回收周期(单位分钟) 48 | */ 49 | public static final int CONNECTION_POOL_MAX_IDLE_MINUTES = 5; 50 | 51 | public static final String CACHE_DIR = getCacheDir(); 52 | 53 | private Constants() { 54 | } 55 | 56 | private static String getCacheDir() { 57 | String tmpDir = System.getProperty("java.io.tmpdir"); 58 | if (tmpDir == null || tmpDir.isEmpty()) { 59 | return null; 60 | } 61 | 62 | String qiniuDir = tmpDir + "com.qiniu.java-sdk"; 63 | File dir = new File(qiniuDir); 64 | if (!dir.exists()) { 65 | return dir.mkdirs() ? qiniuDir : null; 66 | } 67 | 68 | if (dir.isDirectory()) { 69 | return qiniuDir; 70 | } 71 | 72 | return null; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/common/QiniuException.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.common; 2 | 3 | import com.qiniu.http.Error; 4 | import com.qiniu.http.Response; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * 七牛SDK异常封装类,封装了http响应数据 10 | */ 11 | public final class QiniuException extends IOException { 12 | 13 | public final Response response; 14 | private String error; 15 | private boolean isUnrecoverable = false; 16 | 17 | 18 | public QiniuException(Response response) { 19 | super(response != null ? response.getInfo() : null); 20 | this.response = response; 21 | if (response != null) { 22 | response.close(); 23 | } 24 | } 25 | 26 | public QiniuException(Exception e) { 27 | this(e, null); 28 | } 29 | 30 | public QiniuException(Exception e, String msg) { 31 | super(msg != null ? msg : (e != null ? e.getMessage() : null), e); 32 | this.response = null; 33 | this.error = msg; 34 | } 35 | 36 | public static QiniuException unrecoverable(Exception e) { 37 | QiniuException exception = new QiniuException(e); 38 | exception.isUnrecoverable = true; 39 | return exception; 40 | } 41 | 42 | public static QiniuException unrecoverable(String msg) { 43 | QiniuException exception = new QiniuException(null, msg); 44 | exception.isUnrecoverable = true; 45 | return exception; 46 | } 47 | 48 | public String url() { 49 | return response != null ? response.url() : ""; 50 | } 51 | 52 | public int code() { 53 | return response != null ? response.statusCode : Response.NetworkError; 54 | } 55 | 56 | public boolean isUnrecoverable() { 57 | return isUnrecoverable; 58 | } 59 | 60 | public String error() { 61 | if (error != null) { 62 | return error; 63 | } 64 | if (response == null || response.statusCode / 100 == 2 || !response.isJson()) { 65 | return null; 66 | } 67 | Error e = null; 68 | try { 69 | e = response.jsonToObject(Error.class); 70 | } catch (QiniuException e1) { 71 | e1.printStackTrace(); 72 | } 73 | error = e == null ? "" : e.error; 74 | return error; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/common/ZoneReqInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.common; 2 | 3 | import com.qiniu.util.Json; 4 | import com.qiniu.util.UrlSafeBase64; 5 | 6 | /** 7 | * 封装了 accessKey 和 bucket 的类 8 | */ 9 | @Deprecated 10 | public class ZoneReqInfo { 11 | private final String accessKey; 12 | private final String bucket; 13 | 14 | public ZoneReqInfo(String token) throws QiniuException { 15 | // http://developer.qiniu.com/article/developer/security/upload-token.html 16 | // http://developer.qiniu.com/article/developer/security/put-policy.html 17 | try { 18 | String[] strings = token.split(":"); 19 | accessKey = strings[0]; 20 | String policy = new String(UrlSafeBase64.decode(strings[2]), Constants.UTF_8); 21 | bucket = Json.decode(policy).get("scope").toString().split(":")[0]; 22 | } catch (Exception e) { 23 | throw new QiniuException(e, "token is invalid"); 24 | } 25 | } 26 | 27 | public ZoneReqInfo(String accessKey, String bucket) { 28 | this.accessKey = accessKey; 29 | this.bucket = bucket; 30 | } 31 | 32 | public String getAccessKey() { 33 | return accessKey; 34 | } 35 | 36 | public String getBucket() { 37 | return bucket; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/AsyncCallback.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | /** 4 | * 请求处理完成的异步回调接口 5 | */ 6 | public interface AsyncCallback { 7 | void complete(Response r); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/Dns.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | import java.util.List; 6 | 7 | public interface Dns { 8 | List lookup(String hostname) throws UnknownHostException; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/Error.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | /** 4 | * 七牛业务请求逻辑错误封装类,主要用来解析API请求返回如下的内容: 5 | *

 6 |  *     {"error" : "detailed error message"}
 7 |  * 
8 | */ 9 | public final class Error { 10 | public String error; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/MethodType.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | public enum MethodType { 4 | GET(false), 5 | PUT(true), 6 | POST(true), 7 | PATCH(true), 8 | DELETE(true), 9 | HEAD(false), 10 | OPTIONS(false); 11 | 12 | private boolean hasContent; 13 | 14 | MethodType(boolean hasContent) { 15 | this.hasContent = hasContent; 16 | } 17 | 18 | public boolean hasContent() { 19 | return hasContent; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | String m; 25 | switch (this) { 26 | case PUT: 27 | m = "PUT"; 28 | break; 29 | case POST: 30 | m = "POST"; 31 | break; 32 | case PATCH: 33 | m = "PATCH"; 34 | break; 35 | case HEAD: 36 | m = "HEAD"; 37 | break; 38 | case DELETE: 39 | m = "DELETE"; 40 | break; 41 | case OPTIONS: 42 | m = "OPTIONS"; 43 | break; 44 | default: 45 | m = "GET"; 46 | } 47 | return m; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/ProxyConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | import okhttp3.Authenticator; 4 | import okhttp3.Credentials; 5 | import okhttp3.Route; 6 | 7 | import java.io.IOException; 8 | import java.net.InetSocketAddress; 9 | import java.net.Proxy; 10 | 11 | /** 12 | * http 代理 13 | */ 14 | public final class ProxyConfiguration { 15 | 16 | public final String hostAddress; 17 | public final int port; 18 | public final String user; 19 | public final String password; 20 | public final Proxy.Type type; 21 | 22 | /** 23 | * @param hostAddress 服务器域名或IP,比如proxy.com, 192.168.1.1 24 | * @param port 端口 25 | * @param user 用户名,无则填null 26 | * @param password 用户密码,无则填null 27 | * @param type type 28 | */ 29 | public ProxyConfiguration(String hostAddress, int port, String user, String password, Proxy.Type type) { 30 | this.hostAddress = hostAddress; 31 | this.port = port; 32 | this.user = user; 33 | this.password = password; 34 | this.type = type; 35 | } 36 | 37 | public ProxyConfiguration(String hostAddress, int port) { 38 | this(hostAddress, port, null, null, Proxy.Type.HTTP); 39 | } 40 | 41 | Proxy proxy() { 42 | return new Proxy(type, new InetSocketAddress(hostAddress, port)); 43 | } 44 | 45 | Authenticator authenticator() { 46 | return new Authenticator() { 47 | @Override 48 | public okhttp3.Request authenticate(Route route, okhttp3.Response response) throws IOException { 49 | String credential = Credentials.basic(user, password); 50 | return response.request().newBuilder(). 51 | header("Proxy-Authorization", credential). 52 | header("Proxy-Connection", "Keep-Alive").build(); 53 | } 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/http/RequestStreamBody.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.http; 2 | 3 | import okhttp3.MediaType; 4 | import okhttp3.RequestBody; 5 | import okio.BufferedSink; 6 | import okio.Okio; 7 | import okio.Source; 8 | 9 | import java.io.EOFException; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | public class RequestStreamBody extends RequestBody { 14 | 15 | private final MediaType type; 16 | private final InputStream stream; 17 | private long limitSize = -1; 18 | private long sinkSize = 1024 * 100; 19 | 20 | /** 21 | * 构造函数 22 | * 23 | * @param stream 请求数据流 24 | * @param contentType 请求数据类型 25 | */ 26 | public RequestStreamBody(InputStream stream, String contentType) { 27 | this.stream = stream; 28 | this.type = MediaType.parse(contentType); 29 | } 30 | 31 | /** 32 | * 构造函数 33 | * 34 | * @param stream 请求数据流 35 | * @param contentType 请求数据类型 36 | */ 37 | public RequestStreamBody(InputStream stream, MediaType contentType) { 38 | this.stream = stream; 39 | this.type = contentType; 40 | } 41 | 42 | /** 43 | * 构造函数 44 | * 45 | * @param stream 请求数据流 46 | * @param contentType 请求数据类型 47 | * @param limitSize 最大读取 stream 的大小;为 -1 时不限制读取所有 48 | */ 49 | public RequestStreamBody(InputStream stream, MediaType contentType, long limitSize) { 50 | this.stream = stream; 51 | this.type = contentType; 52 | this.limitSize = limitSize; 53 | } 54 | 55 | /** 56 | * 配置请求时,每次从流中读取的数据大小 57 | * 58 | * @param sinkSize 每次从流中读取的数据大小 59 | * @return RequestStreamBody 60 | * @see RequestStreamBody#writeTo(BufferedSink) 61 | */ 62 | public RequestStreamBody setSinkSize(long sinkSize) { 63 | if (sinkSize > 0) { 64 | this.sinkSize = sinkSize; 65 | } 66 | return this; 67 | } 68 | 69 | @Override 70 | public MediaType contentType() { 71 | return type; 72 | } 73 | 74 | @Override 75 | public void writeTo(BufferedSink sink) throws IOException { 76 | try (Source source = Okio.source(stream)) { 77 | int offset = 0; 78 | while (limitSize < 0 || offset < limitSize) { 79 | long byteSize = sinkSize; 80 | if (offset < limitSize) { 81 | byteSize = Math.min(sinkSize, limitSize - offset); 82 | } 83 | 84 | try { 85 | sink.write(source, byteSize); 86 | sink.flush(); 87 | offset += byteSize; 88 | } catch (EOFException e) { 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/Channel.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | public class Channel { 4 | 5 | private int channelid; 6 | private String comment; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/DeviceHistoryItem.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class DeviceHistoryItem { 6 | 7 | @SerializedName("loginAt") 8 | private long loginAt; 9 | @SerializedName("logoutAt") 10 | private long logoutAt; 11 | @SerializedName("remoteIp") 12 | private String remoteIp; 13 | @SerializedName("logoutReason") 14 | private String logoutReason; 15 | 16 | public long getLoginAt() { 17 | return loginAt; 18 | } 19 | 20 | public void setLoginAt(long loginAt) { 21 | this.loginAt = loginAt; 22 | } 23 | 24 | public long getLogoutAt() { 25 | return logoutAt; 26 | } 27 | 28 | public void setLogoutAt(long logoutAt) { 29 | this.logoutAt = logoutAt; 30 | } 31 | 32 | public String getRemoteIp() { 33 | return remoteIp; 34 | } 35 | 36 | public void setRemoteIp(String remoteIp) { 37 | this.remoteIp = remoteIp; 38 | } 39 | 40 | public String getLogoutReason() { 41 | return logoutReason; 42 | } 43 | 44 | public void setLogoutReason(String logoutReason) { 45 | this.logoutReason = logoutReason; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/DeviceHistoryListing.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | public class DeviceHistoryListing { 4 | 5 | DeviceHistoryItem[] items; 6 | String marker; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/DeviceKey.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class DeviceKey { 6 | 7 | @SerializedName("accessKey") 8 | private String accessKey; 9 | @SerializedName("secretKey") 10 | private String secretKey; 11 | @SerializedName("state") 12 | private int state; 13 | @SerializedName("createdAt") 14 | private long createdAt; 15 | 16 | public String getAccessKey() { 17 | return accessKey; 18 | } 19 | 20 | public void setAccessKey(String accessKey) { 21 | this.accessKey = accessKey; 22 | } 23 | 24 | public String getSecretKey() { 25 | return secretKey; 26 | } 27 | 28 | public void setSecretKey(String secretKey) { 29 | this.secretKey = secretKey; 30 | } 31 | 32 | public int getState() { 33 | return state; 34 | } 35 | 36 | public void setState(int state) { 37 | this.state = state; 38 | } 39 | 40 | public long getCreatedAt() { 41 | return createdAt; 42 | } 43 | 44 | public void setCreatedAt(long createdAt) { 45 | this.createdAt = createdAt; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/DeviceListing.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | public class DeviceListing { 4 | 5 | public Device[] items; 6 | public String marker; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/PatchOperation.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | public class PatchOperation { 4 | 5 | // 更该或删除某个属性,replace:更改,delete:删除 6 | private String op; 7 | 8 | // 要修改或删除的属性 9 | private String key; 10 | 11 | // 要修改或删除属性的值 12 | private Object value; 13 | 14 | 15 | public PatchOperation(String op, String key, Object value) { 16 | this.op = op; 17 | this.key = key; 18 | this.value = value; 19 | } 20 | 21 | public String getOp() { 22 | return op; 23 | } 24 | 25 | public void setOp(String op) { 26 | this.op = op; 27 | } 28 | 29 | public String getKey() { 30 | return key; 31 | } 32 | 33 | public void setKey(String key) { 34 | this.key = key; 35 | } 36 | 37 | public Object getValue() { 38 | return value; 39 | } 40 | 41 | public void setValue(Object value) { 42 | this.value = value; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/SaveasReply.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class SaveasReply { 6 | @SerializedName("frame") 7 | private String frame; 8 | @SerializedName("persistentId") 9 | private String persistentId; 10 | @SerializedName("duration") 11 | private int duration; 12 | 13 | public String getFrame() { 14 | return frame; 15 | } 16 | 17 | public void setFrame(String frame) { 18 | this.frame = frame; 19 | } 20 | 21 | public String getPersistentId() { 22 | return persistentId; 23 | } 24 | 25 | public void setPersistentId(String persistentId) { 26 | this.persistentId = persistentId; 27 | } 28 | 29 | public int getDuration() { 30 | return duration; 31 | } 32 | 33 | public void setDuration(int duration) { 34 | this.duration = duration; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/Segment.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class Segment { 6 | @SerializedName("from") 7 | private int from; 8 | @SerializedName("to") 9 | private int to; 10 | @SerializedName("frame") 11 | private String frame; 12 | 13 | public int getFrom() { 14 | return from; 15 | } 16 | 17 | public void setFrom(int from) { 18 | this.from = from; 19 | } 20 | 21 | public int getTo() { 22 | return to; 23 | } 24 | 25 | public void setTo(int to) { 26 | this.to = to; 27 | } 28 | 29 | public String getFrame() { 30 | return frame; 31 | } 32 | 33 | public void setFrame(String frame) { 34 | this.frame = frame; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/linking/model/SegmentListing.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.linking.model; 2 | 3 | public class SegmentListing { 4 | 5 | Segment[] items; 6 | String marker; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/processing/OperationStatus.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.processing; 2 | 3 | /** 4 | * 定义了持久化处理状态类 5 | * 参考文档:持久化处理状态查询 6 | */ 7 | public class OperationStatus { 8 | /** 9 | * 持久化处理的进程ID,即 persistentId 10 | */ 11 | public String id; 12 | 13 | /** 14 | * 状态码 0 成功,1 等待处理,2 正在处理,3 处理失败,4 通知提交失败 15 | */ 16 | public int code; 17 | 18 | /** 19 | * 与状态码相对应的详细描述 20 | */ 21 | public String desc; 22 | 23 | /** 24 | * 处理源文件的文件名 25 | */ 26 | public String inputKey; 27 | 28 | /** 29 | * 处理源文件所在的空间名 30 | */ 31 | public String inputBucket; 32 | 33 | /*** 34 | * taskFrom 35 | * 1. 如果没有 taskFrom, 则表示是通过 api+fops命令 提交的任务, 否则见 2 36 | * 2. taskFrom 字段规则: {source}:{source_id},其中 source 当前可选: workflow|trigger 37 | **/ 38 | public String taskFrom; 39 | 40 | /** 41 | * 云处理操作的处理队列 42 | */ 43 | public String pipeline; 44 | 45 | /** 46 | * 云处理请求的请求id,主要用于七牛技术人员的问题排查 47 | */ 48 | public String reqid; 49 | 50 | /** 51 | * 是否是闲时任务 52 | * null 或 0:非闲时任务 53 | * 1:闲时任务 54 | */ 55 | public Integer type; 56 | 57 | /** 58 | * 任务创建时间 59 | */ 60 | public String creationDate; 61 | 62 | /** 63 | * 云处理操作列表,包含每个云处理操作的状态信息 64 | */ 65 | public OperationResult[] items; 66 | 67 | public class OperationResult { 68 | /** 69 | * 所执行的云处理操作命令fopN 70 | */ 71 | public String cmd; 72 | /** 73 | * 所执行的云处理操作命令状态码 74 | */ 75 | public int code; 76 | /** 77 | * 所执行的云处理操作命令状态描述 78 | */ 79 | public String desc; 80 | /** 81 | * 如果处理失败,该字段会给出失败的详细原因 82 | */ 83 | public String error; 84 | /** 85 | * 云处理结果保存在目标空间文件的hash值 86 | */ 87 | public String hash; 88 | /** 89 | * 云处理结果保存在目标空间的文件名 90 | */ 91 | public String key; 92 | 93 | /** 94 | * 云处理结果保存在目标空间的文件名列表 95 | */ 96 | public String[] keys; 97 | 98 | /** 99 | * 默认为0。当用户执行saveas时,如果未加force且指定的bucket:key存在,则返回1 ,告诉用户返回的是旧数据 100 | */ 101 | public int returnOld; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/QvsMap.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs; 2 | 3 | import com.qiniu.qvs.model.PlayContral; 4 | import com.qiniu.qvs.model.VoiceChat; 5 | import com.qiniu.util.StringMap; 6 | 7 | public class QvsMap { 8 | private QvsMap() { 9 | } 10 | 11 | public static StringMap getVoiceChatMap(VoiceChat voiceChat) { 12 | StringMap params = new StringMap().putNotNull("isV2", voiceChat.getLatency()); 13 | params.put("channels", voiceChat.getChannels()); 14 | params.put("version", voiceChat.getVersion()); 15 | params.put("transProtocol", voiceChat.getTransProtocol()); 16 | return params; 17 | } 18 | 19 | public static StringMap getPlayContralMap(PlayContral playContral) { 20 | StringMap params = new StringMap().putNotNull("command", playContral.getCommand()); 21 | params.put("range", playContral.getRange()); 22 | params.put("scale", playContral.getScale()); 23 | return params; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/StatsManager.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Client; 5 | import com.qiniu.http.Response; 6 | import com.qiniu.util.Auth; 7 | import com.qiniu.util.StringMap; 8 | import com.qiniu.util.UrlUtils; 9 | 10 | public class StatsManager { 11 | private final String apiServer; 12 | private final Client client; 13 | private final Auth auth; 14 | 15 | public StatsManager(Auth auth) { 16 | this(auth, "http://qvs.qiniuapi.com"); 17 | } 18 | 19 | public StatsManager(Auth auth, String apiServer) { 20 | this(auth, apiServer, new Client()); 21 | } 22 | 23 | public StatsManager(Auth auth, String apiServer, Client client) { 24 | this.auth = auth; 25 | this.apiServer = apiServer; 26 | this.client = client; 27 | } 28 | 29 | public Response queryFlow(String namespaceId, String streamId, String tu, int start, int end) throws QiniuException { 30 | String url = String.format("%s/v1/stats/flow", apiServer); 31 | StringMap map = new StringMap().put("nsId", namespaceId).putNotNull("streamId", streamId).put("start", start).put("end", end).put("tu", tu); 32 | url = UrlUtils.composeUrlWithQueries(url, map); 33 | return QvsResponse.get(url, client, auth); 34 | } 35 | 36 | public Response queryBandwidth(String namespaceId, String streamId, String tu, int start, int end) throws QiniuException { 37 | String url = String.format("%s/v1/stats/bandwidth", apiServer); 38 | StringMap map = new StringMap().put("nsId", namespaceId).putNotNull("streamId", streamId).put("start", start).put("end", end).put("tu", tu); 39 | url = UrlUtils.composeUrlWithQueries(url, map); 40 | return QvsResponse.get(url, client, auth); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/ChannelInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | public class ChannelInfo { 4 | private String[] channels; 5 | private int start; 6 | private int end; 7 | 8 | public ChannelInfo(String[] channels, int start, int end) { 9 | this.channels = channels; 10 | this.start = start; 11 | this.end = end; 12 | } 13 | 14 | public String[] getChannels() { 15 | return channels; 16 | } 17 | 18 | public void setChannels(String[] channels) { 19 | this.channels = channels; 20 | } 21 | 22 | public int getStart() { 23 | return start; 24 | } 25 | 26 | public void setStart(int start) { 27 | this.start = start; 28 | } 29 | 30 | public int getEnd() { 31 | return end; 32 | } 33 | 34 | public void setEnd(int end) { 35 | this.end = end; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/Device.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.reflect.TypeToken; 6 | import com.qiniu.util.StringMap; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | @Builder 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class Device { 20 | private int type; //可选项为摄像头、平台两类,1:摄像头,2:平台。 21 | private String name; // 设备名称 (可包含 字母、数字、中划线、下划线;1 ~ 100 个字符长) 22 | private String username; // 用户名, 4~40位,可包含大写字母、小写字母、数字、中划线,建议与设备国标ID一致 23 | private String password; // 密码, 4~40位,可包含大写字母、小写字母、数字、中划线 24 | private boolean pullIfRegister; // 注册成功后启动拉流, 默认关闭 25 | private String desc; // 关于设备的描述信息 26 | private String gbId; // 设备国标ID 27 | 28 | /** 29 | * 转换为POST参数对象 30 | * 31 | * @return POST参数对象 32 | */ 33 | public StringMap transferPostParam() { 34 | Map paramMap = getStringObjectMap(); 35 | StringMap result = new StringMap(); 36 | result.putAll(paramMap); 37 | return result; 38 | } 39 | 40 | private Map getStringObjectMap() { 41 | Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); 42 | Map paramMap = gson.fromJson(gson.toJson(this), new TypeToken>() { 43 | }.getType()); 44 | paramMap.put("type", type); 45 | paramMap.put("pullIfRegister", pullIfRegister); 46 | return paramMap; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/DynamicLiveRoute.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | public class DynamicLiveRoute { 4 | private String publishIP; // 推流端对外IP地址 5 | private String playIP; // 拉流端对外IP地址 6 | private int urlExpireSec; // 地址过期时间,urlExpireSec:100代表100秒后过期; 默认urlExpireSec:0,永不过期. 7 | private int playExpireSec; // 播放过期时间(单位为秒) 8 | 9 | public DynamicLiveRoute(String publishIP, String playIP) { 10 | this.publishIP = publishIP; 11 | this.playIP = playIP; 12 | } 13 | 14 | public DynamicLiveRoute(String publishIP, String playIP, int urlExpireSec) { 15 | this.publishIP = publishIP; 16 | this.playIP = playIP; 17 | this.urlExpireSec = urlExpireSec; 18 | } 19 | 20 | public DynamicLiveRoute(String publishIP, String playIP, int urlExpireSec, int playExpireSec) { 21 | this.publishIP = publishIP; 22 | this.playIP = playIP; 23 | this.urlExpireSec = urlExpireSec; 24 | this.playExpireSec = playExpireSec; 25 | } 26 | 27 | public String getPublishIP() { 28 | return publishIP; 29 | } 30 | 31 | public void setPublishIP(String publishIP) { 32 | this.publishIP = publishIP; 33 | } 34 | 35 | public String getPlayIP() { 36 | return playIP; 37 | } 38 | 39 | public void setPlayIP(String playIP) { 40 | this.playIP = playIP; 41 | } 42 | 43 | public int getUrlExpireSec() { 44 | return urlExpireSec; 45 | } 46 | 47 | public void setUrlExpireSec(int urlExpireSec) { 48 | this.urlExpireSec = urlExpireSec; 49 | } 50 | 51 | public int getPlayExpireSec() { 52 | return playExpireSec; 53 | } 54 | 55 | public void setPlayExpireSec(int playExpireSec) { 56 | this.playExpireSec = playExpireSec; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/PatchOperation.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | public class PatchOperation { 4 | // 更该或删除某个属性,replace:更改,delete:删除 5 | private String op; 6 | 7 | // 要修改或删除的属性 8 | private String key; 9 | 10 | // 要修改或删除属性的值 11 | private Object value; 12 | 13 | 14 | public PatchOperation(String op, String key, Object value) { 15 | this.op = op; 16 | this.key = key; 17 | this.value = value; 18 | } 19 | 20 | public String getOp() { 21 | return op; 22 | } 23 | 24 | public void setOp(String op) { 25 | this.op = op; 26 | } 27 | 28 | public String getKey() { 29 | return key; 30 | } 31 | 32 | public void setKey(String key) { 33 | this.key = key; 34 | } 35 | 36 | public Object getValue() { 37 | return value; 38 | } 39 | 40 | public void setValue(Object value) { 41 | this.value = value; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/PlayContral.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | public class PlayContral { 4 | private String command; 5 | private String range; 6 | private Float scale; 7 | 8 | public PlayContral(String command, String range, Float scale) { 9 | this.command = command; 10 | this.range = range; 11 | this.scale = scale; 12 | } 13 | 14 | public String getCommand() { 15 | return command; 16 | } 17 | 18 | public void setCommand(String command) { 19 | this.command = command; 20 | } 21 | 22 | public String getRange() { 23 | return range; 24 | } 25 | 26 | public void setRange(String range) { 27 | this.range = range; 28 | } 29 | 30 | public Float getScale() { 31 | return scale; 32 | } 33 | 34 | public void setScale(Float scale) { 35 | this.scale = scale; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/qvs/model/VoiceChat.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.qvs.model; 2 | 3 | public class VoiceChat { 4 | private Boolean latency; // 该字段为true时,启用低延迟版本,收到返回地址后在发送语音数据 5 | private String[] channels; // 平台设备指定需要启动的通道国标ID(为空表示启动平台下的所有设备) 6 | private String version; // 对讲国标协议版本,取值"2014"或"2016",默认为2014,例如大部分大华摄像头为GBT 28181-2014版本对讲模式 7 | private String transProtocol; // 取值"tcp"或"udp",流传输模式,默认udp 8 | 9 | public VoiceChat(Boolean latency, String[] channels, String version, String transProtocol) { 10 | this.latency = latency; 11 | this.channels = channels; 12 | this.version = version; 13 | this.transProtocol = transProtocol; 14 | } 15 | 16 | public Boolean getLatency() { 17 | return latency; 18 | } 19 | 20 | public void setLatency(Boolean latency) { 21 | this.latency = latency; 22 | } 23 | 24 | public String[] getChannels() { 25 | return channels; 26 | } 27 | 28 | public void setChannels(String[] channels) { 29 | this.channels = channels; 30 | } 31 | 32 | public String getVersion() { 33 | return version; 34 | } 35 | 36 | public void setVersion(String version) { 37 | this.version = version; 38 | } 39 | 40 | public String getTransProtocol() { 41 | return transProtocol; 42 | } 43 | 44 | public void setTransProtocol(String transProtocol) { 45 | this.transProtocol = transProtocol; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/ServiceCallFunc.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Response; 5 | 6 | public interface ServiceCallFunc { 7 | Response call() throws QiniuException; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/AppParam.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class AppParam { 7 | private String appId; 8 | private String hub; 9 | private String title; 10 | private int maxUsers; 11 | private boolean noAutoKickUser; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/AppResult.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class AppResult { 8 | private String appId; 9 | private String hub; 10 | private String title; 11 | private int maxUsers; 12 | private boolean noAutoKickUser; 13 | private String createdAt; 14 | private String updatedAt; 15 | private String error; 16 | private String status; 17 | 18 | @Data 19 | public static class AppMergeInfo { 20 | private boolean enable; 21 | private boolean audioOnly; 22 | private int height; 23 | private int width; 24 | private int fps; 25 | private int kbps; 26 | private String url; 27 | private String streamTitle; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/CallbackParam.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class CallbackParam { 7 | private String eventCbUrl; 8 | private String eventCbSecret; 9 | private int eventCbVersion; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/ForwardParam.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 转推的参数 9 | */ 10 | @Data 11 | public class ForwardParam { 12 | private String id; 13 | private String publishUrl; 14 | private String playerId; 15 | private List tracks; 16 | 17 | public ForwardParam(String id, String publishUrl, String playerId) { 18 | this.id = id; 19 | this.publishUrl = publishUrl; 20 | this.playerId = playerId; 21 | } 22 | 23 | public ForwardParam() { 24 | } 25 | 26 | @Data 27 | public static class TrackInfo { 28 | private String trackId; 29 | 30 | public TrackInfo(String trackId) { 31 | this.trackId = trackId; 32 | } 33 | 34 | public TrackInfo() { 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/ForwardResult.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ForwardResult { 7 | /** 8 | * 单路转推状态 9 | */ 10 | private String status; 11 | /** 12 | * 单路转推ID 13 | */ 14 | private String id; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MediaConfig.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MediaConfig implements Serializable { 6 | 7 | private static final long serialVersionUID = -2781620162179559305L; 8 | 9 | /** 10 | * 输出帧率 11 | */ 12 | private int fps; 13 | 14 | /** 15 | * 输出码率 16 | */ 17 | private int kbps; 18 | 19 | /** 20 | * 指定输出宽度 必须为偶数 21 | */ 22 | private int width; 23 | 24 | /** 25 | * 指定输出高度 必须为偶数 26 | */ 27 | private int height; 28 | 29 | /** 30 | * 可选 是否保留用户最后一帧 默认false 31 | */ 32 | private boolean holdLastFrame; 33 | 34 | /** 35 | * 可选 是否仅仅做音频合流 36 | */ 37 | private boolean audioOnly; 38 | 39 | /** 40 | * 可选 指定拉伸模式 默认为 aspectFill 41 | */ 42 | private StretchModeEnum stretchMode; 43 | 44 | public int getFps() { 45 | return fps; 46 | } 47 | 48 | public void setFps(int fps) { 49 | this.fps = fps; 50 | } 51 | 52 | public int getKbps() { 53 | return kbps; 54 | } 55 | 56 | public void setKbps(int kbps) { 57 | this.kbps = kbps; 58 | } 59 | 60 | public int getWidth() { 61 | return width; 62 | } 63 | 64 | public void setWidth(int width) { 65 | this.width = width; 66 | } 67 | 68 | public int getHeight() { 69 | return height; 70 | } 71 | 72 | public void setHeight(int height) { 73 | this.height = height; 74 | } 75 | 76 | public boolean isHoldLastFrame() { 77 | return holdLastFrame; 78 | } 79 | 80 | public void setHoldLastFrame(boolean holdLastFrame) { 81 | this.holdLastFrame = holdLastFrame; 82 | } 83 | 84 | public boolean isAudioOnly() { 85 | return audioOnly; 86 | } 87 | 88 | public void setAudioOnly(boolean audioOnly) { 89 | this.audioOnly = audioOnly; 90 | } 91 | 92 | public StretchModeEnum getStretchMode() { 93 | return stretchMode; 94 | } 95 | 96 | public void setStretchMode(StretchModeEnum stretchMode) { 97 | this.stretchMode = stretchMode; 98 | } 99 | 100 | @Override 101 | public String toString() { 102 | return "MediaConfig{" 103 | + "fps=" + fps 104 | + ", kbps=" + kbps 105 | + ", width=" + width 106 | + ", height=" + height 107 | + ", holdLastFrame=" + holdLastFrame 108 | + ", audioOnly=" + audioOnly 109 | + ", stretchMode=" + stretchMode 110 | + '}'; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MediaInput.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MediaInput implements Serializable { 6 | 7 | private static final long serialVersionUID = -9162560559667684764L; 8 | 9 | /** 10 | * 可选,默认为media类型。 11 | * 选值范围 image/media,media时 userId必须,image时imageUrl必填 12 | */ 13 | private String kind; 14 | 15 | /** 16 | * kind == media 必填,用户加入房间时用户名 17 | */ 18 | private String userId; 19 | 20 | /** 21 | * kind == image 必填,图片地址。 22 | */ 23 | private String url; 24 | 25 | /** 26 | * 可选,发布多路时候用于区分不同输入 27 | */ 28 | private String tag; 29 | 30 | /** 31 | * 可选,任务为basic并且多路进行合流时候必填 32 | */ 33 | private MediaPosition position; 34 | 35 | /** 36 | * 可选,拉伸模式 默认为 aspectFill 37 | */ 38 | private StretchModeEnum stretchMode; 39 | 40 | public String getUserId() { 41 | return userId; 42 | } 43 | 44 | public void setUserId(String userId) { 45 | this.userId = userId; 46 | } 47 | 48 | public String getTag() { 49 | return tag; 50 | } 51 | 52 | public void setTag(String tag) { 53 | this.tag = tag; 54 | } 55 | 56 | public String getUrl() { 57 | return url; 58 | } 59 | 60 | public void setUrl(String url) { 61 | this.url = url; 62 | } 63 | 64 | public String getKind() { 65 | return kind; 66 | } 67 | 68 | public void setKind(String kind) { 69 | this.kind = kind; 70 | } 71 | 72 | 73 | public StretchModeEnum getStretchMode() { 74 | return stretchMode; 75 | } 76 | 77 | public void setStretchMode(StretchModeEnum stretchMode) { 78 | this.stretchMode = stretchMode; 79 | } 80 | 81 | public MediaPosition getPosition() { 82 | return position; 83 | } 84 | 85 | public void setPosition(MediaPosition position) { 86 | this.position = position; 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "MediaInput{" 92 | + "kind='" + kind + '\'' 93 | + ", userId='" + userId + '\'' 94 | + ", url='" + url + '\'' 95 | + ", tag='" + tag + '\'' 96 | + ", position=" + position 97 | + ", stretchMode=" + stretchMode 98 | + '}'; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MediaOutput.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MediaOutput implements Serializable { 6 | 7 | private static final long serialVersionUID = 5010528238721566857L; 8 | 9 | /** 10 | * 现仅支持 rtmp 11 | */ 12 | private String type; 13 | 14 | /** 15 | * rtmp地址, example: rtmp://qiniu.com/stream 16 | */ 17 | private String url; 18 | 19 | public MediaOutput() { 20 | } 21 | 22 | public MediaOutput(String type, String url) { 23 | this.type = type; 24 | this.url = url; 25 | } 26 | 27 | public String getType() { 28 | return type; 29 | } 30 | 31 | public void setType(String type) { 32 | this.type = type; 33 | } 34 | 35 | public String getUrl() { 36 | return url; 37 | } 38 | 39 | public void setUrl(String url) { 40 | this.url = url; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "MediaOutput{" 46 | + "type='" + type + '\'' 47 | + ", url='" + url + '\'' 48 | + '}'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MediaPosition.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MediaPosition implements Serializable { 6 | 7 | private static final long serialVersionUID = 3616082871842887188L; 8 | 9 | private int x; 10 | 11 | private int y; 12 | 13 | /** 14 | * 必须为偶数 15 | */ 16 | private int w; 17 | 18 | /** 19 | * 必须为偶数 20 | */ 21 | private int h; 22 | 23 | /** 24 | * 可选 0 ~ 65535 25 | */ 26 | private int z; 27 | 28 | public MediaPosition() { 29 | } 30 | 31 | public MediaPosition(int x, int y, int w, int h, int z) { 32 | this.x = x; 33 | this.y = y; 34 | this.w = w; 35 | this.h = h; 36 | this.z = z; 37 | } 38 | 39 | public int getX() { 40 | return x; 41 | } 42 | 43 | public void setX(int x) { 44 | this.x = x; 45 | } 46 | 47 | public int getY() { 48 | return y; 49 | } 50 | 51 | public void setY(int y) { 52 | this.y = y; 53 | } 54 | 55 | public int getW() { 56 | return w; 57 | } 58 | 59 | public void setW(int w) { 60 | this.w = w; 61 | } 62 | 63 | public int getH() { 64 | return h; 65 | } 66 | 67 | public void setH(int h) { 68 | this.h = h; 69 | } 70 | 71 | public int getZ() { 72 | return z; 73 | } 74 | 75 | public void setZ(int z) { 76 | this.z = z; 77 | } 78 | 79 | @Override 80 | public String toString() { 81 | return "MediaPosition{" 82 | + "x=" + x 83 | + ", y=" + y 84 | + ", w=" + w 85 | + ", h=" + h 86 | + ", z=" + z 87 | + '}'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MergeJob.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | public class MergeJob implements Serializable { 7 | 8 | private static final long serialVersionUID = -6100722396626298717L; 9 | 10 | private String id; 11 | 12 | /** 13 | * 固定 现在仅支持 basic 14 | */ 15 | private String type; 16 | 17 | /** 18 | * 输入媒体信息 19 | */ 20 | private List inputs; 21 | 22 | /** 23 | * 设置推流地址,现仅支持单地址 24 | */ 25 | private List outputs; 26 | 27 | /** 28 | * 合流任务设置。 29 | */ 30 | private MediaConfig config; 31 | 32 | public String getId() { 33 | return id; 34 | } 35 | 36 | public void setId(String id) { 37 | this.id = id; 38 | } 39 | 40 | public String getType() { 41 | return type; 42 | } 43 | 44 | public void setType(String type) { 45 | this.type = type; 46 | } 47 | 48 | public List getInputs() { 49 | return inputs; 50 | } 51 | 52 | public void setInputs(List inputs) { 53 | this.inputs = inputs; 54 | } 55 | 56 | public List getOutputs() { 57 | return outputs; 58 | } 59 | 60 | public void setOutputs(List outputs) { 61 | this.outputs = outputs; 62 | } 63 | 64 | public MediaConfig getConfig() { 65 | return config; 66 | } 67 | 68 | public void setConfig(MediaConfig config) { 69 | this.config = config; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "MergeJob{" 75 | + "id='" + id + '\'' 76 | + ", type='" + type + '\'' 77 | + ", inputs=" + inputs 78 | + ", outputs=" + outputs 79 | + ", config=" + config 80 | + '}'; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MergeParam.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 合流业务请求参数 10 | */ 11 | @Data 12 | public class MergeParam { 13 | private String id; 14 | private boolean audioOnly; 15 | private int width; 16 | private int height; 17 | private int fps; 18 | private int kbps; 19 | private int minRate; 20 | private int maxRate; 21 | private String stretchMode; 22 | private String publishUrl; 23 | private MergeBackGround background; 24 | private List waterMarks; 25 | private boolean holdLastFrame; 26 | private String template; 27 | private List userInfos; 28 | 29 | 30 | /** 31 | * 合流背景参数 32 | */ 33 | @Data 34 | public static class MergeBackGround { 35 | private String url; 36 | private int x; 37 | private int y; 38 | private int w; 39 | private int h; 40 | private String stretchMode; 41 | } 42 | 43 | @Data 44 | public static class MergeWaterMarks { 45 | private String url; 46 | private int x; 47 | private int y; 48 | private int w; 49 | private int h; 50 | private String stretchMode; 51 | } 52 | 53 | @Data 54 | public static class MergeUserInfo { 55 | private String userId; 56 | private String backgroundUrl; 57 | private String stretchMode; 58 | private int sequence; 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MergeResult.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class MergeResult { 7 | private String id; 8 | private String status; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/MergeTrackParam.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class MergeTrackParam { 10 | private int mode = ModeEnum.INCREMENT.getVal(); 11 | private List add; 12 | private List remove; 13 | private List all; 14 | 15 | public enum ModeEnum { 16 | //增量,指定add和remove 17 | INCREMENT(0), 18 | //全量,替换替换原有数据 19 | FULL(1); 20 | 21 | private int val; 22 | 23 | ModeEnum(int val) { 24 | this.val = val; 25 | } 26 | 27 | public int getVal() { 28 | return val; 29 | } 30 | } 31 | 32 | @Data 33 | public static class MergeTrack { 34 | private String trackID; 35 | private int x; 36 | private int y; 37 | private int z; 38 | private int w; 39 | private int h; 40 | 41 | /** 42 | * @see com.qiniu.rtc.model.StretchModeEnum 43 | */ 44 | private String stretchMode; 45 | private boolean supportSei = false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/QRTCResult.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class QRTCResult { 7 | private int code; 8 | private String message; 9 | private T result; 10 | 11 | public QRTCResult(int code, String message, T result) { 12 | this.code = code; 13 | this.message = message; 14 | this.result = result; 15 | } 16 | 17 | public static QRTCResult fail(int code, String message) { 18 | return new QRTCResult<>(code, message, null); 19 | } 20 | 21 | public static QRTCResult success(int code, T result) { 22 | return new QRTCResult<>(code, "OK", result); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/RoomAccess.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * Created by jemy on 2018/4/18. 7 | */ 8 | public class RoomAccess { 9 | @SerializedName("appId") 10 | private String appId; 11 | @SerializedName("roomName") 12 | private String roomName; 13 | @SerializedName("userId") 14 | private String userId; 15 | @SerializedName("expireAt") 16 | private long expireAt; 17 | @SerializedName("permission") 18 | private String permission; 19 | 20 | public RoomAccess(String appId, String roomName, String userId, long expireAt, String permission) { 21 | this.appId = appId; 22 | this.roomName = roomName; 23 | this.userId = userId; 24 | this.expireAt = expireAt; 25 | this.permission = permission; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/RoomParam.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class RoomParam { 8 | private String roomName; 9 | private int maxUsers; 10 | private int autoCloseTtlS; 11 | private int noEntreTtlS; 12 | private boolean openRoom; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/RoomResult.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS]MergeBackGround 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class RoomResult { 10 | 11 | private List users; 12 | private String error; 13 | private String status; 14 | private List rooms; 15 | private boolean end; 16 | private int offset; 17 | private String roomId; 18 | 19 | @Data 20 | public static class UserInfo { 21 | private String userId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/StretchModeEnum.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.model; 2 | 3 | public enum StretchModeEnum { 4 | aspectFill, 5 | aspectFit, 6 | scaleToFit; 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/UrlParam.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | @Data 8 | @Builder 9 | public class UrlParam { 10 | /** 11 | * 应用ID 12 | */ 13 | String appId; 14 | /** 15 | * 房间名称 16 | */ 17 | String roomName; 18 | /** 19 | * 游标 20 | */ 21 | int offset; 22 | /** 23 | * 数量 24 | */ 25 | int limit; 26 | 27 | String jobId; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/model/WatermarksParam.java: -------------------------------------------------------------------------------- 1 | // codebeat:disable[TOO_MANY_IVARS] 2 | package com.qiniu.rtc.model; 3 | 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class WatermarksParam { 10 | 11 | private List watermarks; 12 | 13 | @Data 14 | public static class Watermarks { 15 | private String url; 16 | private int x; 17 | private int y; 18 | private int w; 19 | private int h; 20 | 21 | /** 22 | * @see com.qiniu.rtc.model.StretchModeEnum 23 | */ 24 | private String stretchMode; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/service/AppService.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.service; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Response; 5 | import com.qiniu.rtc.model.AppParam; 6 | import com.qiniu.util.Auth; 7 | 8 | public class AppService extends AbstractService { 9 | /** 10 | * 初始化 11 | * 12 | * @param auth auth 13 | */ 14 | public AppService(Auth auth) { 15 | super(auth); 16 | } 17 | 18 | /** 19 | * @param appParam hub 绑定的直播 hub,可选,使用此 hub 的资源进行推流等业务功能,hub 与 app 必须属于同一个七牛账户 20 | * title app 的名称,可选,注意,Title 不是唯一标识,重复 create 动作将生成多个 app 21 | * maxUsers int 类型,可选,连麦房间支持的最大在线人数。 22 | * noAutoKickUser bool 类型,可选,禁止自动踢人(抢流)。默认为 false ,即同一个身份的 client (app/room/user) ,新的连 23 | * 麦请求可以成功,旧连接被关闭。 24 | * @return Response 如果不读取Response的数据,请注意调用Close方法关闭 25 | * @throws QiniuException 异常 26 | */ 27 | public Response createApp(AppParam appParam) throws QiniuException { 28 | String urlPattern = "/v3/apps"; 29 | return postCall(appParam, urlPattern); 30 | } 31 | 32 | /** 33 | * 获取房间信息 34 | * 35 | * @param appId 房间所属帐号的 app 36 | * @return Response 如果不读取Response的数据,请注意调用Close方法关闭 37 | * @throws QiniuException 异常 38 | */ 39 | public Response getApp(String appId) throws QiniuException { 40 | String urlPattern = "/v3/apps/%s"; 41 | return getCall(urlPattern, appId); 42 | } 43 | 44 | /** 45 | * 删除app 46 | * 47 | * @param appId appId 48 | * @return Response 49 | * @throws QiniuException 异常 50 | */ 51 | public Response deleteApp(String appId) throws QiniuException { 52 | String urlPattern = "/v3/apps/%s"; 53 | return deleteCall(null, urlPattern, appId); 54 | } 55 | 56 | /** 57 | * 更新app信息 58 | * 注意!调用这个接口后仅对调用后新创建的房间有效,已经存在的房间需要等待被关闭重新创建后生效 59 | * 60 | * @param appParam appParam 61 | * @return Response 62 | * @throws QiniuException 异常 63 | */ 64 | public Response updateApp(AppParam appParam) throws QiniuException { 65 | String urlPattern = "/v3/apps/%s"; 66 | return postCall(appParam, urlPattern, appParam.getAppId()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/service/CallbackService.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.service; 2 | 3 | 4 | import com.qiniu.common.QiniuException; 5 | import com.qiniu.http.Response; 6 | import com.qiniu.rtc.model.CallbackParam; 7 | import com.qiniu.util.Auth; 8 | import com.qiniu.util.StringUtils; 9 | 10 | /** 11 | * HTTP回调的api 12 | */ 13 | public class CallbackService extends AbstractService { 14 | 15 | /** 16 | * 初始化 17 | * 18 | * @param auth auth 19 | */ 20 | public CallbackService(Auth auth) { 21 | super(auth); 22 | } 23 | 24 | /** 25 | * 设置http业务回调 26 | * 27 | * @param appId appId 28 | * @param param param 29 | * @return Response 30 | * @throws QiniuException 异常 31 | */ 32 | public Response setHttpCallback(String appId, CallbackParam param) throws QiniuException { 33 | if (null == param 34 | || StringUtils.isNullOrEmpty(param.getEventCbUrl()) 35 | || StringUtils.isNullOrEmpty(param.getEventCbSecret())) { 36 | throw new IllegalArgumentException("CallbackParam cannot be null..."); 37 | } 38 | param.setEventCbVersion(1); //only support http 39 | String urlPattern = "/v3/apps/%s"; 40 | return postCall(param, urlPattern, appId); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/service/ForwardService.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.service; 2 | 3 | 4 | import com.qiniu.common.QiniuException; 5 | import com.qiniu.http.Response; 6 | import com.qiniu.rtc.model.ForwardParam; 7 | import com.qiniu.util.Auth; 8 | import com.qiniu.util.StringUtils; 9 | 10 | /** 11 | * 流媒体相关处理服务的api 12 | */ 13 | public class ForwardService extends AbstractService { 14 | 15 | /** 16 | * 初始化,暴露次级接口,客户也可以直接初始化 17 | * 18 | * @param auth 授权对象 19 | * @throws IllegalArgumentException 参数不合法异常 20 | */ 21 | public ForwardService(Auth auth) { 22 | super(auth); 23 | } 24 | 25 | /** 26 | * 创建单路转推任务 27 | * 28 | * @param appId 应用ID 29 | * @param roomId 房间ID 30 | * @param param id和playerId不能为空 31 | * @return 回应信息 32 | * @throws QiniuException 未知异常 33 | * @throws IllegalArgumentException 参数不合法异常 34 | */ 35 | public Response createForwardJob(String appId, String roomId, ForwardParam param) throws QiniuException, 36 | IllegalArgumentException { 37 | checkParams(roomId, param); 38 | String urlPattern = "/v3/apps/%s/rooms/%s/forward_job"; 39 | return postCall(param, urlPattern, appId, roomId); 40 | } 41 | 42 | /** 43 | * 停止单路转推任务 44 | * 45 | * @param appId 应用ID 46 | * @param roomId 房间ID 47 | * @param param id和playerId不能为空 48 | * @return 回应信息 49 | * @throws QiniuException 未知异常 50 | * @throws IllegalArgumentException 参数不合法异常 51 | */ 52 | public Response stopForwardJob(String appId, String roomId, ForwardParam param) throws QiniuException, 53 | IllegalArgumentException { 54 | checkParams(roomId, param); 55 | String urlPattern = "/v3/apps/%s/rooms/%s/forward_job/delete"; 56 | return postCall(param, urlPattern, appId, roomId); 57 | } 58 | 59 | /** 60 | * 参数校验 61 | * 62 | * @param roomId 房间ID 63 | * @param param 转推参数对象 64 | * @throws IllegalArgumentException 参数不合法异常 65 | */ 66 | private void checkParams(String roomId, ForwardParam param) throws IllegalArgumentException { 67 | if (null == param || null == roomId 68 | || StringUtils.isNullOrEmpty(param.getId()) || StringUtils.isNullOrEmpty(param.getPlayerId())) { 69 | throw new IllegalArgumentException(""); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/service/MergeService.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.service; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Response; 5 | import com.qiniu.rtc.model.MergeParam; 6 | import com.qiniu.rtc.model.MergeTrackParam; 7 | import com.qiniu.rtc.model.UrlParam; 8 | import com.qiniu.rtc.model.WatermarksParam; 9 | import com.qiniu.util.Auth; 10 | 11 | @Deprecated 12 | public class MergeService extends AbstractService { 13 | /** 14 | * 初始化 15 | * 16 | * @param auth auth 17 | */ 18 | public MergeService(Auth auth) { 19 | super(auth); 20 | } 21 | 22 | /** 23 | * 创建合流任务 24 | * 25 | * @param mergeParam 合流业务请求参数 26 | * @param appId appId 27 | * @param roomName roomName 28 | * @return Response 29 | * @throws QiniuException 异常 30 | */ 31 | public Response createMergeJob(MergeParam mergeParam, String appId, String roomName) throws QiniuException { 32 | String urlPattern = "/v3/apps/%s/rooms/%s/merge_job"; 33 | return postCall(mergeParam, urlPattern, appId, roomName); 34 | } 35 | 36 | /** 37 | * 更新合流track 信息 38 | * 39 | * @param mergeTrackParam MergeTrackParam 40 | * @param param UrlParam 41 | * @return Response 42 | * @throws QiniuException 异常 43 | */ 44 | public Response updateMergeTrack(MergeTrackParam mergeTrackParam, UrlParam param) 45 | throws QiniuException { 46 | String urlPattern = "/v3/apps/%s/rooms/%s/merge_job/%s/tracks"; 47 | return postCall(mergeTrackParam, urlPattern, param.getAppId(), param.getRoomName(), param.getJobId()); 48 | } 49 | 50 | 51 | /** 52 | * 更新合流水印 53 | * 54 | * @param watermarksParam WatermarksParam 55 | * @param urlParam UrlParam 56 | * @return Response 57 | * @throws QiniuException 异常 58 | */ 59 | public Response updateMergeWatermarks(WatermarksParam watermarksParam, UrlParam urlParam) 60 | throws QiniuException { 61 | String urlPattern = "/v3/apps/%s/rooms/%s/merge_job/%s/watermarks"; 62 | return postCall(watermarksParam, urlPattern, urlParam.getAppId(), urlParam.getRoomName(), urlParam.getJobId()); 63 | } 64 | 65 | /** 66 | * 停止合流任务 67 | * 68 | * @param appId appId 69 | * @param roomName roomName 70 | * @param jobId jobId 71 | * @return Response 72 | * @throws QiniuException 异常 73 | */ 74 | public Response stopMergeJob(String appId, String roomName, String jobId) throws QiniuException { 75 | String urlPattern = "/v3/apps/%s/rooms/%s/merge_job/%s"; 76 | return deleteCall(null, urlPattern, appId, roomName, jobId); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/rtc/service/MergeServiceV4.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.rtc.service; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Response; 5 | import com.qiniu.rtc.model.MergeJob; 6 | import com.qiniu.util.Auth; 7 | import com.qiniu.util.StringUtils; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | public class MergeServiceV4 extends AbstractService { 13 | /** 14 | * 初始化 15 | * 16 | * @param auth auth 17 | */ 18 | public MergeServiceV4(Auth auth) { 19 | super(auth); 20 | } 21 | 22 | /** 23 | * 创建合流任务 24 | * 25 | * @param job 任务信息 26 | * @param appId appId 27 | * @param roomName roomName 28 | * @return Response 29 | * @throws QiniuException 异常 30 | */ 31 | public Response createMergeJob(MergeJob job, String appId, String roomName) throws QiniuException { 32 | String urlPattern = "/v4/apps/%s/rooms/%s/jobs"; 33 | return postCall(job, urlPattern, appId, roomName); 34 | } 35 | 36 | /** 37 | * 更新合流任务 38 | * 39 | * @param job 任务信息 40 | * @param appId appId 41 | * @param roomName roomName 42 | * @return Response 43 | * @throws QiniuException 异常 44 | */ 45 | public Response updateMergeJob(MergeJob job, String appId, String roomName) throws QiniuException { 46 | if (job == null || StringUtils.isNullOrEmpty(job.getId())) { 47 | throw new IllegalArgumentException(""); 48 | } 49 | String urlPattern = "/v4/apps/%s/rooms/%s/jobs/update"; 50 | return postCall(job, urlPattern, appId, roomName); 51 | } 52 | 53 | /** 54 | * 删除合流任务 55 | * 56 | * @param jobId 合流任务ID 57 | * @param appId appId 58 | * @param roomName roomName 59 | * @return Response 60 | * @throws QiniuException 异常 61 | */ 62 | public Response stopMergeJob(String jobId, String appId, String roomName) throws QiniuException { 63 | if (StringUtils.isNullOrEmpty(jobId)) { 64 | throw new IllegalArgumentException(""); 65 | } 66 | String urlPattern = "/v4/apps/%s/rooms/%s/jobs/stop"; 67 | Map params = new HashMap<>(); 68 | params.put("id", jobId); 69 | return postCall(params, urlPattern, appId, roomName); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/sms/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.sms; 2 | 3 | import com.qiniu.common.Constants; 4 | 5 | public class Configuration implements Cloneable { 6 | /* 7 | * 特殊默认域名 8 | */ 9 | public static String defaultSmsHost = "https://sms.qiniuapi.com"; 10 | /** 11 | * 连接超时时间 单位秒(默认10s) 12 | */ 13 | public int connectTimeout = Constants.CONNECT_TIMEOUT; 14 | /** 15 | * 写超时时间 单位秒(默认 0 , 不超时) 16 | */ 17 | public int writeTimeout = Constants.WRITE_TIMEOUT; 18 | /** 19 | * 回复超时时间 单位秒(默认30s) 20 | */ 21 | public int readTimeout = Constants.READ_TIMEOUT; 22 | /** 23 | * 底层HTTP库所有的并发执行的请求数量 24 | */ 25 | public int dispatcherMaxRequests = Constants.DISPATCHER_MAX_REQUESTS; 26 | /** 27 | * 底层HTTP库对每个独立的Host进行并发请求的数量 28 | */ 29 | public int dispatcherMaxRequestsPerHost = Constants.DISPATCHER_MAX_REQUESTS_PER_HOST; 30 | /** 31 | * 底层HTTP库中复用连接对象的最大空闲数量 32 | */ 33 | public int connectionPoolMaxIdleCount = Constants.CONNECTION_POOL_MAX_IDLE_COUNT; 34 | /** 35 | * 底层HTTP库中复用连接对象的回收周期(单位分钟) 36 | */ 37 | public int connectionPoolMaxIdleMinutes = Constants.CONNECTION_POOL_MAX_IDLE_MINUTES; 38 | /** 39 | * 上传失败重试次数 40 | */ 41 | public int retryMax = 5; 42 | 43 | public Configuration() { 44 | } 45 | 46 | public Configuration clone() { 47 | try { 48 | return (Configuration) super.clone(); 49 | } catch (CloneNotSupportedException e) { 50 | e.printStackTrace(); 51 | } 52 | return null; 53 | } 54 | 55 | public String smsHost() { 56 | return defaultSmsHost; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/ApiInterceptorAuth.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Headers; 5 | import com.qiniu.util.Auth; 6 | 7 | /** 8 | * 仅是 Qiniu 签名,Body 必须是 bytes[] 9 | **/ 10 | final class ApiInterceptorAuth extends Api.Interceptor { 11 | 12 | private final Auth auth; 13 | 14 | private ApiInterceptorAuth(Auth auth) { 15 | this.auth = auth; 16 | } 17 | 18 | @Override 19 | int priority() { 20 | return Api.Interceptor.PriorityAuth; 21 | } 22 | 23 | @Override 24 | Api.Response intercept(Api.Request request, Api.Handler handler) throws QiniuException { 25 | if (auth == null || request == null) { 26 | return handler.handle(request); 27 | } 28 | 29 | if (request.getAuthType() == Api.Request.AuthTypeQiniu) { 30 | String url = request.getUrl().toString(); 31 | String method = request.getMethodString(); 32 | Headers headers = Headers.of(request.getHeader()); 33 | byte[] body = request.getBytesBody(); 34 | String authorization = "Qiniu " + auth.signQiniuAuthorization(url, method, body, headers); 35 | request.addHeaderField("Authorization", authorization); 36 | } 37 | 38 | return handler.handle(request); 39 | } 40 | 41 | static final class Builder { 42 | 43 | private Auth auth; 44 | 45 | Builder setAuth(Auth auth) { 46 | this.auth = auth; 47 | return this; 48 | } 49 | 50 | Builder setAuthType(int authType) { 51 | return this; 52 | } 53 | 54 | Api.Interceptor build() { 55 | return new ApiInterceptorAuth(auth); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/ApiInterceptorDefaultHeader.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.util.DefaultHeader; 5 | 6 | final class ApiInterceptorDefaultHeader extends Api.Interceptor { 7 | 8 | private ApiInterceptorDefaultHeader() { 9 | } 10 | 11 | @Override 12 | int priority() { 13 | return Api.Interceptor.PrioritySetHeader; 14 | } 15 | 16 | @Override 17 | Api.Response intercept(final Api.Request request, Api.Handler handler) throws QiniuException { 18 | if (request == null) { 19 | return handler.handle(request); 20 | } 21 | 22 | DefaultHeader.setDefaultHeader(new DefaultHeader.HeadAdder() { 23 | @Override 24 | public void addHeader(String key, String value) { 25 | request.addHeaderField(key, value); 26 | } 27 | }); 28 | request.addHeaderField("Host", request.getHost()); 29 | return handler.handle(request); 30 | } 31 | 32 | static final class Builder { 33 | 34 | Api.Interceptor build() { 35 | return new ApiInterceptorDefaultHeader(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/ApiUpload.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Client; 5 | import com.qiniu.util.StringMap; 6 | 7 | public class ApiUpload extends Api { 8 | 9 | public ApiUpload(Client client) { 10 | super(client); 11 | } 12 | 13 | public ApiUpload(Client client, Config config) { 14 | super(client, config); 15 | } 16 | 17 | /** 18 | * upload api 请求基类 19 | */ 20 | public static class Request extends Api.Request { 21 | 22 | /** 23 | * 上传凭证 24 | */ 25 | private String token; 26 | 27 | /** 28 | * 构造请求对象 29 | * 30 | * @param urlPrefix 请求的 urlPrefix, scheme + host 31 | */ 32 | public Request(String urlPrefix) { 33 | super(urlPrefix); 34 | } 35 | 36 | /** 37 | * 获取请求头信息 38 | * 39 | * @return 请求头信息 40 | */ 41 | public StringMap getHeader() throws QiniuException { 42 | if (token == null || !getUploadToken().isValid()) { 43 | ApiUtils.throwInvalidRequestParamException("token"); 44 | } 45 | 46 | addHeaderField("Authorization", "UpToken " + token); 47 | addHeaderField("Host", getHost()); 48 | return super.getHeader(); 49 | } 50 | 51 | /** 52 | * 设置上传凭证 53 | * 54 | * @param token 上传凭证 55 | */ 56 | protected void setToken(String token) { 57 | this.token = token; 58 | } 59 | 60 | /** 61 | * 获取上传凭证 62 | * 63 | * @return 上传凭证 64 | * @throws QiniuException 异常 65 | */ 66 | protected UploadToken getUploadToken() throws QiniuException { 67 | return new UploadToken(token); 68 | } 69 | 70 | @Override 71 | protected void prepareToRequest() throws QiniuException { 72 | if (token == null || !getUploadToken().isValid()) { 73 | ApiUtils.throwInvalidRequestParamException("token"); 74 | } 75 | 76 | super.prepareToRequest(); 77 | } 78 | } 79 | 80 | 81 | /** 82 | * api 响应基类 83 | */ 84 | public static class Response extends Api.Response { 85 | 86 | /** 87 | * 构建 Response 88 | * 89 | * @param response com.qiniu.http.Response 90 | * @throws QiniuException 解析 data 异常 91 | */ 92 | protected Response(com.qiniu.http.Response response) throws QiniuException { 93 | super(response); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/BaseUploader.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.http.Client; 5 | import com.qiniu.http.Response; 6 | 7 | public abstract class BaseUploader { 8 | 9 | protected final Client client; 10 | protected final String key; 11 | protected final String upToken; 12 | protected final ConfigHelper configHelper; 13 | protected final Configuration config; 14 | 15 | BaseUploader(Client client, String upToken, String key, Configuration config) { 16 | this.client = client; 17 | this.key = key; 18 | this.upToken = upToken; 19 | if (config == null) { 20 | this.config = new Configuration(); 21 | } else { 22 | this.config = config.clone(); 23 | } 24 | this.configHelper = new ConfigHelper(this.config); 25 | } 26 | 27 | public Response upload() throws QiniuException { 28 | if (this.config == null) { 29 | throw QiniuException.unrecoverable("config can't be empty"); 30 | } 31 | return uploadWithRegionRetry(); 32 | } 33 | 34 | private Response uploadWithRegionRetry() throws QiniuException { 35 | Response response = null; 36 | QiniuException exception = null; 37 | while (true) { 38 | response = null; 39 | exception = null; 40 | 41 | try { 42 | response = uploadFlows(); 43 | } catch (QiniuException e) { 44 | exception = e; 45 | } 46 | 47 | if (!Retry.canSwitchRegionAndRetry(response, exception) 48 | || !couldReloadSource() || !reloadSource()) { 49 | break; 50 | } 51 | 52 | // context 过期,不需要切换 region 53 | if (response != null && response.isContextExpiredError() 54 | || exception != null && exception.response != null && exception.response.isContextExpiredError()) { 55 | continue; 56 | } 57 | 58 | // 切换 region 59 | if (config.region == null || !config.region.switchRegion(new UploadToken(upToken))) { 60 | break; 61 | } 62 | } 63 | 64 | if (exception != null) { 65 | throw exception; 66 | } 67 | 68 | return response; 69 | } 70 | 71 | abstract Response uploadFlows() throws QiniuException; 72 | 73 | abstract boolean couldReloadSource(); 74 | 75 | abstract boolean reloadSource(); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/Recorder.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 定义分片上传时纪录上传进度的接口 7 | */ 8 | public interface Recorder { 9 | 10 | /** 11 | * 新建或更新文件分片上传的进度 12 | * 13 | * @param key 持久化的键 14 | * @param data 持久化的内容 15 | */ 16 | void set(String key, byte[] data); 17 | 18 | /** 19 | * 获取文件分片上传的进度信息 20 | * 21 | * @param key 持久化的键 22 | * @return 对应的信息 23 | */ 24 | byte[] get(String key); 25 | 26 | /** 27 | * 删除文件分片上传的进度文件 28 | * 29 | * @param key 持久化的键 30 | */ 31 | void del(String key); 32 | 33 | /** 34 | * 根据服务器的key和本地文件名生成持久化纪录的key 35 | * 36 | * @param key 服务器的key 37 | * @param file 本地文件名 38 | * @return 持久化上传纪录的key 39 | */ 40 | String recorderKeyGenerate(String key, File file); 41 | 42 | /** 43 | * 根据目标bucket, key和本地文件名生成持久化纪录的key 44 | * 45 | * @param bucket 空间名或其变换的值 46 | * @param key 文件名或其变换的值 47 | * @param contentDataSUID 上传内容的标识字符串 48 | * @param uploaderSUID 上传方式的标识字符串 49 | * @return 持久化上传纪录的key 50 | */ 51 | String recorderKeyGenerate(String bucket, String key, String contentDataSUID, String uploaderSUID); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/RegionReqInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.Constants; 4 | import com.qiniu.common.QiniuException; 5 | import com.qiniu.util.Json; 6 | import com.qiniu.util.UrlSafeBase64; 7 | 8 | /** 9 | * 封装了 accessKey 和 bucket 的类 10 | */ 11 | class RegionReqInfo { 12 | private final String accessKey; 13 | private final String bucket; 14 | 15 | RegionReqInfo(String token) throws QiniuException { 16 | // http://developer.qiniu.com/article/developer/security/upload-token.html 17 | // http://developer.qiniu.com/article/developer/security/put-policy.html 18 | try { 19 | String[] strings = token.split(":"); 20 | accessKey = strings[0]; 21 | String policy = new String(UrlSafeBase64.decode(strings[2]), Constants.UTF_8); 22 | bucket = Json.decode(policy).get("scope").toString().split(":")[0]; 23 | } catch (Exception e) { 24 | throw new QiniuException(e, "token is invalid"); 25 | } 26 | } 27 | 28 | RegionReqInfo(String accessKey, String bucket) { 29 | this.accessKey = accessKey; 30 | this.bucket = bucket; 31 | } 32 | 33 | public String getAccessKey() { 34 | return accessKey; 35 | } 36 | 37 | public String getBucket() { 38 | return bucket; 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return accessKey.hashCode() + bucket.hashCode(); 44 | } 45 | 46 | @Override 47 | public boolean equals(Object obj) { 48 | if (this == obj) { 49 | return true; 50 | } 51 | if (obj instanceof RegionReqInfo) { 52 | RegionReqInfo t = (RegionReqInfo) obj; 53 | return this.accessKey.equals(t.accessKey) && this.bucket.equals(t.bucket); 54 | } 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/UpCompletionHandler.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.http.Response; 4 | 5 | /** 6 | * 定义了文件上传结束回调接口 7 | */ 8 | public interface UpCompletionHandler { 9 | void complete(String key, Response r); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/UploadToken.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import com.qiniu.common.QiniuException; 4 | import com.qiniu.util.StringUtils; 5 | 6 | class UploadToken extends RegionReqInfo { 7 | 8 | private final String token; 9 | 10 | UploadToken(String token) throws QiniuException { 11 | super(token); 12 | this.token = token; 13 | } 14 | 15 | String getToken() { 16 | return token; 17 | } 18 | 19 | boolean isValid() { 20 | return !StringUtils.isNullOrEmpty(token) && !StringUtils.isNullOrEmpty(getBucket()) && !StringUtils.isNullOrEmpty(getAccessKey()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/AccessStyleMode.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 原图保护模式 5 | */ 6 | public enum AccessStyleMode { 7 | 8 | /** 9 | * 原图保护关闭 10 | */ 11 | CLOSE(0), 12 | /** 13 | * 原图保护开启 14 | */ 15 | OPEN(1); 16 | 17 | private int type = 0; 18 | 19 | AccessStyleMode(int t) { 20 | type = t; 21 | } 22 | 23 | public int getType() { 24 | return type; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/AclType.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 空间类型:公开空间、私有空间 5 | */ 6 | public enum AclType { 7 | /** 8 | * 公开空间 9 | */ 10 | PUBLIC(0), 11 | /** 12 | * 私有空间 13 | */ 14 | PRIVATE(1); 15 | 16 | private int type = 0; 17 | 18 | AclType(int t) { 19 | type = t; 20 | } 21 | 22 | public int getType() { 23 | return type; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/BatchOpData.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 该类封装了batch接口回复中的data部分 5 | * 参考文档:批量操作 6 | */ 7 | public class BatchOpData { 8 | //batch stat结果 9 | public long fsize; 10 | public String hash; 11 | public String mimeType; 12 | public long putTime; 13 | //batch stat, move, copy, delete, chgm 遇到错误时才有值 14 | public String error; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/BatchStatus.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 定义批量请求的状态码 5 | * 参考文档:批量操作 6 | */ 7 | public final class BatchStatus { 8 | /** 9 | * 批量请求的每个命令的执行结果状态码 10 | */ 11 | public int code; 12 | /** 13 | * 批量请求的每个命令返回的结果 14 | */ 15 | public BatchOpData data; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/BucketQuota.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 空间配额 5 | */ 6 | public class BucketQuota { 7 | 8 | /** 9 | * 空间存储量配额 10 | */ 11 | long size = 0; 12 | 13 | /** 14 | * 空间文件数配额 15 | */ 16 | long count = 0; 17 | 18 | public BucketQuota() { 19 | } 20 | 21 | public BucketQuota(long size, long count) { 22 | this.size = size; 23 | this.count = count; 24 | } 25 | 26 | /** 27 | * 获取空间存储量配额 28 | * 29 | * @return 空间存储量配额 30 | */ 31 | public long getSize() { 32 | return this.size; 33 | } 34 | 35 | /** 36 | * 设置空间存储量配额
37 | * 参数传入0或不传表示不更改当前配置,传入-1表示取消限额,新创建的空间默认没有限额。 38 | * 39 | * @param size 空间存储量配额 40 | * @return 空间配置信息 41 | */ 42 | public BucketQuota setSize(long size) { 43 | this.size = size; 44 | return this; 45 | } 46 | 47 | /** 48 | * 获取空间文件数配额 49 | * 50 | * @return 空间文件数配额 51 | */ 52 | public long getCount() { 53 | return this.count; 54 | } 55 | 56 | /** 57 | * 设置 58 | * 参数传入0或不传表示不更改当前配置,传入-1表示取消限额,新创建的空间默认没有限额。 59 | * 60 | * @param count 空间文件数配额 61 | * @return 空间配置信息 62 | */ 63 | public BucketQuota setCount(long count) { 64 | this.count = count; 65 | return this; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/DefaultPutRet.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 默认上传接口回复对象 5 | */ 6 | public final class DefaultPutRet { 7 | /** 8 | * 文件hash值 9 | */ 10 | public String hash; 11 | /** 12 | * 文件名 13 | */ 14 | public String key; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/FetchRet.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * fetch 接口的回复对象 5 | * 参考文档:资源抓取 6 | */ 7 | public class FetchRet { 8 | /** 9 | * 抓取后保存到空间文件名 10 | */ 11 | public String key; 12 | /** 13 | * 抓取后保存到空间的文件hash值 14 | */ 15 | public String hash; 16 | /** 17 | * 抓取后保存到空间的文件的mimeType 18 | */ 19 | public String mimeType; 20 | /** 21 | * 抓取后保存到空间的文件的大小,单位:字节 22 | */ 23 | public long fsize; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/FileListing.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | import com.qiniu.util.StringUtils; 4 | 5 | /** 6 | * 该类封装了文件列举请求回复 7 | */ 8 | public final class FileListing { 9 | /** 10 | * 文件对象列表 11 | */ 12 | public FileInfo[] items; 13 | /** 14 | * 下一次列举的marker 15 | */ 16 | public String marker; 17 | /** 18 | * 通用前缀 19 | */ 20 | public String[] commonPrefixes; 21 | 22 | /** 23 | * 列举操作是否已到所有文件列表结尾,如果为true表示无需再发送列举请求 24 | * 25 | * @return 是否 list 结束 26 | */ 27 | public boolean isEOF() { 28 | return StringUtils.isNullOrEmpty(marker); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/IndexPageType.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | public enum IndexPageType { 4 | HAS(0), 5 | NO(1); 6 | 7 | private int type = 0; 8 | 9 | IndexPageType(int t) { 10 | type = t; 11 | } 12 | 13 | public int getType() { 14 | return type; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/ResumeBlockInfo.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 封装了分片上传请求的回复内容 5 | */ 6 | public final class ResumeBlockInfo { 7 | public String ctx; 8 | public long crc32; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/storage/model/StorageType.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage.model; 2 | 3 | /** 4 | * 存储类型 5 | */ 6 | public enum StorageType { 7 | /** 8 | * 普通存储 9 | */ 10 | COMMON, 11 | 12 | /** 13 | * 低频存储 14 | */ 15 | INFREQUENCY, 16 | 17 | /** 18 | * 归档存储 19 | */ 20 | Archive, 21 | 22 | /** 23 | * 深度归档存储 24 | */ 25 | DeepArchive, 26 | 27 | /** 28 | * 归档直读存储 29 | */ 30 | ArchiveIR, 31 | 32 | /** 33 | * 智能分层 34 | */ 35 | IntelligentTiering, 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/streaming/model/ActivityRecords.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.streaming.model; 2 | 3 | /** 4 | * Created by bailong on 16/9/22. 5 | */ 6 | public final class ActivityRecords { 7 | public Item[] items; 8 | 9 | public static class Item { 10 | public long start; 11 | public long end; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/streaming/model/StreamAttribute.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.streaming.model; 2 | 3 | /** 4 | * Created by bailong on 16/9/22. 5 | */ 6 | public final class StreamAttribute { 7 | public long createdAt; 8 | public long updatedAt; 9 | public long expireAt; 10 | public long disabledTill; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/streaming/model/StreamListing.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.streaming.model; 2 | 3 | import com.qiniu.util.StringUtils; 4 | 5 | /** 6 | * Created by bailong on 16/9/23. 7 | */ 8 | public final class StreamListing { 9 | public Item[] items; 10 | public String marker; 11 | 12 | public boolean isEOF() { 13 | return StringUtils.isNullOrEmpty(marker); 14 | } 15 | 16 | public String[] keys() { 17 | String[] keys = new String[items.length]; 18 | int i = 0; 19 | for (Item item : items) { 20 | keys[i++] = item.key; 21 | } 22 | return keys; 23 | } 24 | 25 | private static class Item { 26 | public String key; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/streaming/model/StreamStatus.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.streaming.model; 2 | 3 | /** 4 | * Created by bailong on 16/9/22. 5 | */ 6 | public final class StreamStatus { 7 | public long startAt; 8 | public String clientIP; 9 | public long bps; 10 | 11 | public Fps fps; 12 | 13 | public static class Fps { 14 | public int audio; 15 | public int video; 16 | public int data; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/Crc32.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.util.zip.CRC32; 7 | 8 | /** 9 | * 计算文件或二进制数据的crc32校验码 10 | */ 11 | public final class Crc32 { 12 | 13 | private Crc32() { 14 | } 15 | 16 | /** 17 | * 计算二进制字节校验码 18 | * 19 | * @param data 二进制数据 20 | * @param offset 起始字节索引 21 | * @param length 校验字节长度 22 | * @return 校验码 23 | */ 24 | public static long bytes(byte[] data, int offset, int length) { 25 | CRC32 crc32 = new CRC32(); 26 | crc32.update(data, offset, length); 27 | return crc32.getValue(); 28 | } 29 | 30 | /** 31 | * 计算二进制字节校验码 32 | * 33 | * @param data 二进制数据 34 | * @return 校验码 35 | */ 36 | public static long bytes(byte[] data) { 37 | return bytes(data, 0, data.length); 38 | } 39 | 40 | /** 41 | * 对文件内容计算crc32校验码 42 | * 43 | * @param f 需要计算crc32校验码的文件 44 | * @return crc校验码 45 | * @throws IOException 读取文件异常 46 | */ 47 | public static long file(File f) throws IOException { 48 | FileInputStream fi = new FileInputStream(f); 49 | byte[] buff = new byte[64 * 1024]; 50 | int len; 51 | CRC32 crc32 = new CRC32(); 52 | try { 53 | while ((len = fi.read(buff)) != -1) { 54 | crc32.update(buff, 0, len); 55 | } 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } finally { 59 | fi.close(); 60 | } 61 | 62 | return crc32.getValue(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/DefaultHeader.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import com.qiniu.http.Client; 4 | 5 | import java.text.DateFormat; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | import java.util.Locale; 9 | import java.util.TimeZone; 10 | 11 | public final class DefaultHeader { 12 | public static final String DISABLE_TIMESTAMP_SIGNATURE_ENV_KEY = "DISABLE_QINIU_TIMESTAMP_SIGNATURE"; 13 | 14 | private DefaultHeader() { 15 | } 16 | 17 | public static void setDefaultHeader(HeadAdder adder) { 18 | if (adder == null) { 19 | return; 20 | } 21 | 22 | if (!isDisableQiniuTimestampSignature()) { 23 | adder.addHeader("X-Qiniu-Date", xQiniuDate()); 24 | } 25 | 26 | adder.addHeader("User-Agent", Client.userAgent()); 27 | } 28 | 29 | private static boolean isDisableQiniuTimestampSignature() { 30 | String value = System.getenv(DISABLE_TIMESTAMP_SIGNATURE_ENV_KEY); 31 | if (value == null) { 32 | return false; 33 | } 34 | value = value.toLowerCase(); 35 | return value.equals("true") || value.equals("yes") || value.equals("y") || value.equals("1"); 36 | } 37 | 38 | private static String xQiniuDate() { 39 | DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US); 40 | format.setTimeZone(TimeZone.getTimeZone("UTC")); 41 | return format.format(new Date()); 42 | } 43 | 44 | public interface HeadAdder { 45 | void addHeader(String key, String value); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/IOUtils.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | public class IOUtils { 8 | 9 | private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 10 | 11 | private IOUtils() { 12 | 13 | } 14 | 15 | /** 16 | * 输入InputSteam,返回byte[]. 17 | * 参考: 链接
18 | * 19 | * @param input 输入流 20 | * @return byte 数组 21 | * @throws IOException 异常 22 | */ 23 | public static byte[] toByteArray(final InputStream input) throws IOException { 24 | try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { 25 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 26 | int n; 27 | while (-1 != (n = input.read(buffer))) { 28 | output.write(buffer, 0, n); 29 | } 30 | return output.toByteArray(); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/Json.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.reflect.TypeToken; 7 | 8 | import java.lang.reflect.Type; 9 | import java.util.Map; 10 | 11 | public final class Json { 12 | private Json() { 13 | } 14 | 15 | public static String encode(StringMap map) { 16 | return new Gson().toJson(map.map()); 17 | } 18 | 19 | public static String encode(Object obj) { 20 | return new GsonBuilder().serializeNulls().create().toJson(obj); 21 | } 22 | 23 | public static T decode(String json, Class classOfT) { 24 | return new Gson().fromJson(json, classOfT); 25 | } 26 | 27 | public static T decode(JsonElement jsonElement, Class clazz) { 28 | Gson gson = new Gson(); 29 | return gson.fromJson(jsonElement, clazz); 30 | } 31 | 32 | public static StringMap decode(String json) { 33 | // CHECKSTYLE:OFF 34 | Type t = new TypeToken>() { 35 | }.getType(); 36 | // CHECKSTYLE:ON 37 | Map x = new Gson().fromJson(json, t); 38 | return new StringMap(x); 39 | } 40 | 41 | public static Object[] decodeArray(String json) { 42 | // CHECKSTYLE:OFF 43 | Type t = new TypeToken() { 44 | }.getType(); 45 | // CHECKSTYLE:ON 46 | return new Gson().fromJson(json, t); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/Md5.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.security.MessageDigest; 8 | import java.security.NoSuchAlgorithmException; 9 | 10 | 11 | public class Md5 { 12 | private Md5() { 13 | 14 | } 15 | 16 | public static String md5(byte[] data) { 17 | return md5(data, 0, data.length); 18 | } 19 | 20 | public static String md5(byte[] data, int offset, int len) { 21 | MessageDigest md; 22 | try { 23 | md = MessageDigest.getInstance("MD5"); 24 | } catch (NoSuchAlgorithmException e) { 25 | throw new RuntimeException(e); 26 | } 27 | md.update(data, offset, len); 28 | byte[] secretBytes = md.digest(); 29 | return getFormattedText(secretBytes); 30 | } 31 | 32 | public static String md5(File file) throws IOException { 33 | FileInputStream fis = new FileInputStream(file); 34 | try { 35 | return md5(fis, file.length()); 36 | } finally { 37 | fis.close(); 38 | } 39 | } 40 | 41 | 42 | public static String md5(InputStream in, final long length) throws IOException { 43 | MessageDigest md; 44 | try { 45 | md = MessageDigest.getInstance("MD5"); 46 | } catch (NoSuchAlgorithmException e) { 47 | throw new RuntimeException(e); 48 | } 49 | byte[] buffer = new byte[1024 * 4]; 50 | int buffSize = buffer.length; 51 | long len = length; 52 | while (len != 0) { 53 | int next = (int) (buffSize > len ? len : buffSize); 54 | next = in.read(buffer, 0, next); 55 | if (next == -1) { 56 | throw new IOException("input stream length: " + len + " does not match the argument: " + length); 57 | } 58 | if (next != 0) { 59 | md.update(buffer, 0, next); 60 | len -= next; 61 | } else { 62 | try { 63 | Thread.sleep(100); 64 | } catch (InterruptedException e) { 65 | // do nothing 66 | } 67 | } 68 | } 69 | byte[] secretBytes = md.digest(); 70 | return getFormattedText(secretBytes); 71 | } 72 | 73 | 74 | private static String getFormattedText(byte[] src) { 75 | if (src == null || src.length == 0) { 76 | return ""; 77 | } 78 | StringBuilder stringBuilder = new StringBuilder(32); 79 | for (int i = 0; i < src.length; i++) { 80 | int v = src[i] & 0xFF; 81 | String hv = Integer.toHexString(v); 82 | if (hv.length() < 2) { 83 | stringBuilder.append(0); 84 | } 85 | stringBuilder.append(hv); 86 | } 87 | return stringBuilder.toString(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/Timestamp.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | public final class Timestamp { 4 | 5 | private Timestamp() { 6 | } 7 | 8 | public static long second() { 9 | return System.currentTimeMillis() / 1000; 10 | } 11 | 12 | public static long milliSecond() { 13 | return System.currentTimeMillis(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/qiniu/util/UrlSafeBase64.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.util; 2 | 3 | import com.qiniu.common.Constants; 4 | 5 | /** 6 | * URL安全的Base64编码和解码 7 | */ 8 | 9 | public final class UrlSafeBase64 { 10 | 11 | private UrlSafeBase64() { 12 | } // don't instantiate 13 | 14 | /** 15 | * 编码字符串 16 | * 17 | * @param data 待编码字符串 18 | * @return 结果字符串 19 | */ 20 | public static String encodeToString(String data) { 21 | return encodeToString(data.getBytes(Constants.UTF_8)); 22 | } 23 | 24 | /** 25 | * 编码数据 26 | * 27 | * @param data 字节数组 28 | * @return 结果字符串 29 | */ 30 | public static String encodeToString(byte[] data) { 31 | return Base64.encodeToString(data, Base64.URL_SAFE | Base64.NO_WRAP); 32 | } 33 | 34 | /** 35 | * 解码数据 36 | * 37 | * @param data 编码过的字符串 38 | * @return 原始数据 39 | */ 40 | public static byte[] decode(String data) { 41 | return Base64.decode(data, Base64.URL_SAFE | Base64.NO_WRAP); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/qiniu/common/AutoZoneTest.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.common; 2 | 3 | import org.junit.jupiter.api.Tag; 4 | import org.junit.jupiter.api.Test; 5 | import test.com.qiniu.TestConfig; 6 | 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | /** 10 | * Created by Simon on 6/22/16. 11 | */ 12 | public class AutoZoneTest { 13 | 14 | @Test 15 | @Tag("IntegrationTest") 16 | public void testHttp() { 17 | 18 | String bucket = TestConfig.testBucket_z0; 19 | try { 20 | AutoZone zone = AutoZone.instance; 21 | AutoZone.ZoneInfo zoneInfo = zone.queryZoneInfo(TestConfig.testAccessKey, bucket); 22 | assertTrue(zoneInfo.upHttp.contains("http://")); 23 | assertTrue(zoneInfo.upBackupHttp.contains("http://")); 24 | assertTrue(zoneInfo.upHttps.contains("https://")); 25 | assertTrue(zoneInfo.upBackupHttps.contains("https://")); 26 | } catch (QiniuException e) { 27 | fail(e.response.toString()); 28 | } 29 | } 30 | 31 | @Test 32 | @Tag("IntegrationTest") 33 | public void testHttpFail() { 34 | try { 35 | AutoZone zone = AutoZone.instance; 36 | zone.queryZoneInfo(TestConfig.dummyAccessKey, TestConfig.dummyBucket); 37 | fail(); 38 | } catch (QiniuException e) { 39 | assertEquals(e.code(), 612); 40 | } 41 | } 42 | 43 | @Test 44 | @Tag("UnitTest") 45 | public void testSplitE() { 46 | String s1 = "bkt:key"; 47 | String s2 = "bkt"; 48 | assertEquals(s1.split(":")[0], s2.split(":")[0]); 49 | } 50 | 51 | @Test 52 | @Tag("IntegrationTest") 53 | public void testC1() { 54 | try { 55 | AutoZone.ZoneInfo info = AutoZone.instance.queryZoneInfo(TestConfig.testAccessKey, 56 | TestConfig.testBucket_z0); 57 | System.out.println("zone0: " + info.toString()); 58 | 59 | AutoZone.ZoneInfo info2 = AutoZone.instance.queryZoneInfo(TestConfig.testAccessKey, 60 | TestConfig.testBucket_z0); 61 | assertSame(info, info2); 62 | 63 | } catch (QiniuException e) { 64 | fail(e.response.toString()); 65 | } 66 | } 67 | 68 | @Test 69 | @Tag("UnitTest") 70 | public void testZ() { 71 | Zone z1 = new Zone.Builder(Zone.zone0()).upHttp("http://uphttp").build(); 72 | assertSame(z1.getUpHttp(null), "http://uphttp"); 73 | assertSame(Zone.zone0().getUpHttp(null), "http://upload.qiniup.com"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/qiniu/iam/apis/ApiTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.iam.apis; 2 | 3 | import com.qiniu.storage.Api; 4 | import test.com.qiniu.TestConfig; 5 | 6 | public class ApiTestConfig { 7 | static final String policyAlias = "JavaTestPolicy"; 8 | static final String groupAlias = "JavaTestGroup"; 9 | static final String userAlias = "JavaTestUser"; 10 | static final String userPWD = "JavaTestUserPWD"; 11 | static final String baseUrl = "api.qiniu.com"; 12 | static final Api.Config config = new Api.Config.Builder() 13 | .setAuth(TestConfig.testAuth) 14 | .setRequestDebugLevel(Api.Config.DebugLevelDetail) 15 | .setResponseDebugLevel(Api.Config.DebugLevelDetail) 16 | .build(); 17 | 18 | private ApiTestConfig() { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/qiniu/storage/BatchTest.java: -------------------------------------------------------------------------------- 1 | package com.qiniu.storage; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Tag; 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class BatchTest { 8 | 9 | @Test 10 | @Tag("UnitTest") 11 | public void testBatchCondition() { 12 | 13 | BucketManager.Condition condition = new BucketManager.Condition.Builder() 14 | .build(); 15 | String encodedString = condition.encodedString(); 16 | Assertions.assertNull(encodedString); 17 | 18 | condition = new BucketManager.Condition.Builder() 19 | .setHash("hash") 20 | .build(); 21 | encodedString = condition.encodedString(); 22 | Assertions.assertEquals(encodedString, "aGFzaD1oYXNo"); 23 | 24 | condition = new BucketManager.Condition.Builder() 25 | .setHash("hash") 26 | .setPutTime(1993232L) 27 | .build(); 28 | encodedString = condition.encodedString(); 29 | Assertions.assertEquals(encodedString, "aGFzaD1oYXNoJnB1dFRpbWU9MTk5MzIzMg=="); 30 | 31 | condition = new BucketManager.Condition.Builder() 32 | .setHash("hash") 33 | .setMime("application/txt") 34 | .setPutTime(1993232L) 35 | .build(); 36 | encodedString = condition.encodedString(); 37 | Assertions.assertEquals(encodedString, "aGFzaD1oYXNoJm1pbWU9YXBwbGljYXRpb24vdHh0JnB1dFRpbWU9MTk5MzIzMg=="); 38 | 39 | condition = new BucketManager.Condition.Builder() 40 | .setHash("hash") 41 | .setMime("application/txt") 42 | .setFileSize(100L) 43 | .setPutTime(1993232L) 44 | .build(); 45 | encodedString = condition.encodedString(); 46 | Assertions.assertEquals(encodedString, "aGFzaD1oYXNoJm1pbWU9YXBwbGljYXRpb24vdHh0JmZzaXplPTEwMCZwdXRUaW1lPTE5OTMyMzI="); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/DnsTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu; 2 | 3 | import com.qiniu.common.Zone; 4 | import com.qiniu.http.Dns; 5 | import com.qiniu.storage.Configuration; 6 | import com.qiniu.storage.UploadManager; 7 | import org.junit.jupiter.api.Disabled; 8 | import org.junit.jupiter.api.Tag; 9 | import org.junit.jupiter.api.Test; 10 | import qiniu.happydns.DnsClient; 11 | import qiniu.happydns.Domain; 12 | import qiniu.happydns.IResolver; 13 | import qiniu.happydns.local.Resolver; 14 | import qiniu.happydns.local.SystemDnsServer; 15 | 16 | import java.io.IOException; 17 | import java.net.InetAddress; 18 | import java.net.UnknownHostException; 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | // example 24 | public class DnsTest { 25 | private Configuration config; 26 | private UploadManager uploadManager; 27 | 28 | public void setUp() throws UnknownHostException { 29 | IResolver[] resolvers = new IResolver[2]; 30 | resolvers[0] = SystemDnsServer.defaultResolver(); 31 | resolvers[1] = new Resolver(InetAddress.getByName("119.29.29.29")); 32 | final DnsClient dnsClient = new DnsClient(resolvers); 33 | 34 | config = new Configuration(); 35 | config.zone = Zone.zone0(); 36 | config.dns = new Dns() { 37 | @Override 38 | public List lookup(String hostname) throws UnknownHostException { 39 | InetAddress[] ips; 40 | try { 41 | Domain domain = new Domain(hostname, true, true); 42 | ips = dnsClient.queryInetAddress(domain); 43 | } catch (IOException e) { 44 | e.printStackTrace(); 45 | throw new UnknownHostException(e.getMessage()); 46 | } 47 | if (ips == null) { 48 | throw new UnknownHostException(hostname + " resolve failed."); 49 | } 50 | List l = new ArrayList<>(ips.length); 51 | Collections.addAll(l, ips); 52 | return l; 53 | } 54 | }; 55 | 56 | uploadManager = new UploadManager(config); 57 | } 58 | 59 | @Test 60 | @Disabled 61 | @Tag("IntegrationTest") 62 | public void testSome() { 63 | // uploadManager.xxxxx 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/ResCode.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 8 | 9 | public class ResCode { 10 | public static boolean find(int code, int... codes) { 11 | System.out.println("response code is: " + code + ", possible code is in: " + Arrays.toString(codes)); 12 | for (int i : codes) { 13 | if (code == i) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | public static int[] getPossibleResCode(int... codes) { 21 | return codes; 22 | } 23 | 24 | @Test 25 | public void testAddCode() { 26 | assertArrayEquals(new int[]{401}, ResCode.getPossibleResCode(401)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/cdn/CdnManagerTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.cdn; 2 | 3 | import com.qiniu.cdn.CdnManager; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static org.junit.jupiter.api.Assertions.fail; 8 | 9 | public class CdnManagerTest { 10 | @Test 11 | public void testencodePath() { 12 | try { 13 | // 空格替换为 %20 14 | String path = "/ hello/ world"; 15 | String got = CdnManager.encodePath(path); 16 | String want = "/%20hello/%20world"; 17 | assertEquals(want, got); 18 | 19 | // 半角 + 号替换为 %2B 20 | path = "/+hello/+world"; 21 | got = CdnManager.encodePath(path); 22 | want = "/%2Bhello/%2Bworld"; 23 | 24 | assertEquals(want, got); 25 | 26 | // % 号替换为 %25 27 | path = "/%hello/+world"; 28 | got = CdnManager.encodePath(path); 29 | want = "/%25hello/%2Bworld"; 30 | assertEquals(want, got); 31 | 32 | 33 | } catch (Exception e) { 34 | fail(e.toString()); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/qvs/RecordTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.qvs; 2 | 3 | import com.qiniu.http.Response; 4 | import com.qiniu.qvs.RecordManager; 5 | import com.qiniu.util.Auth; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import test.com.qiniu.TestConfig; 8 | 9 | public class RecordTest { 10 | private final String namespaceId = "3nm4x1e0xw855"; 11 | private final String streamId = "31011500991320007536"; 12 | private final String format = "m3u8"; 13 | private final int start = 1640599830; 14 | private final int end = 1640600430; 15 | Auth auth = TestConfig.testAuth; 16 | private RecordManager recordManager; 17 | private Response res = null; 18 | private Response res2 = null; 19 | 20 | @BeforeEach 21 | public void setUp() throws Exception { 22 | this.recordManager = new RecordManager(auth); 23 | } 24 | 25 | /* @Test 26 | @Tag("IntegrationTest") 27 | public void testOndemandRecord() throws Exception { 28 | try { 29 | res = recordManager.startRecord(namespaceId, streamId); 30 | assertNotNull(res); 31 | System.out.println(res.bodyString()); 32 | Thread.sleep(1000 * 60); 33 | res2 = recordManager.stopRecord(namespaceId, streamId); 34 | assertNotNull(res2); 35 | System.out.println(res2.bodyString()); 36 | } catch (QiniuException e) { 37 | e.printStackTrace(); 38 | } finally { 39 | if (res != null) { 40 | res.close(); 41 | } 42 | if (res2 != null) { 43 | res2.close(); 44 | } 45 | } 46 | } 47 | 48 | @Test 49 | @Tag("IntegrationTest") 50 | public void testRecordClipsSaveas() { 51 | try { 52 | res = recordManager.recordClipsSaveas(namespaceId, streamId, "", format, start, end, false, "", "", 0); 53 | assertNotNull(res); 54 | System.out.println(res.bodyString()); 55 | } catch (QiniuException e) { 56 | e.printStackTrace(); 57 | } finally { 58 | if (res != null) { 59 | res.close(); 60 | } 61 | } 62 | } 63 | 64 | @Test 65 | @Tag("IntegrationTest") 66 | public void testRecordsPlayback() { 67 | try { 68 | res = recordManager.recordsPlayback(namespaceId, streamId, start, end); 69 | assertNotNull(res); 70 | System.out.println(res.bodyString()); 71 | } catch (QiniuException e) { 72 | e.printStackTrace(); 73 | } finally { 74 | if (res != null) { 75 | res.close(); 76 | } 77 | } 78 | } 79 | */ 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/qvs/StatsTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.qvs; 2 | 3 | import com.qiniu.http.Response; 4 | import com.qiniu.qvs.StatsManager; 5 | import com.qiniu.util.Auth; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import test.com.qiniu.TestConfig; 8 | 9 | public class StatsTest { 10 | private final String namespaceId = ""; 11 | private final String streamId = ""; 12 | private final String tu = "5min"; 13 | private final int start = 20200901; 14 | private final int end = 20200902; 15 | Auth auth = TestConfig.testAuth; 16 | private StatsManager statsManager; 17 | private Response res = null; 18 | 19 | @BeforeEach 20 | public void setUp() throws Exception { 21 | this.statsManager = new StatsManager(auth); 22 | } 23 | 24 | /* @Test 25 | @Tag("IntegrationTest") 26 | public void testQueryFlow() { 27 | try { 28 | res = statsManager.queryFlow(namespaceId, streamId, tu, start, end); 29 | assertNotNull(res); 30 | System.out.println(res.bodyString()); 31 | } catch (QiniuException e) { 32 | e.printStackTrace(); 33 | } finally { 34 | if (res != null) { 35 | res.close(); 36 | } 37 | } 38 | } 39 | 40 | @Test 41 | @Tag("IntegrationTest") 42 | public void testQueryBandwidth() { 43 | try { 44 | res = statsManager.queryBandwidth(namespaceId, streamId, tu, start, end); 45 | assertNotNull(res); 46 | System.out.println(res.bodyString()); 47 | } catch (QiniuException e) { 48 | e.printStackTrace(); 49 | } finally { 50 | if (res != null) { 51 | res.close(); 52 | } 53 | } 54 | } 55 | */ 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/storage/BucketManagerTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.storage; 2 | 3 | import com.qiniu.storage.BucketManager; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Tag; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class BucketManagerTest { 9 | @Test 10 | @Tag("UnitTest") 11 | public void testBatchOperationsSize() { 12 | BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations(); 13 | Assertions.assertEquals(0, batchOperations.size()); 14 | 15 | batchOperations.addDeleteOp("bucket1", "1", "2"); 16 | Assertions.assertEquals(2, batchOperations.size()); 17 | 18 | batchOperations.addCopyOp( 19 | "fromBucket", "fromFileKey", 20 | "toBucket", "toFileKey" 21 | ); 22 | Assertions.assertEquals(3, batchOperations.size()); 23 | 24 | batchOperations.addRenameOp("fromBucket", "fromFileKey", "toFileKey"); 25 | Assertions.assertEquals(4, batchOperations.size()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/storage/RegionGroupTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.storage; 2 | 3 | import com.qiniu.storage.Region; 4 | import com.qiniu.storage.RegionGroup; 5 | import org.junit.jupiter.api.Tag; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertNotSame; 9 | 10 | public class RegionGroupTest { 11 | 12 | @Test 13 | @Tag("UnitTest") 14 | public void testSign() { 15 | RegionGroup group01 = new RegionGroup(); 16 | group01.addRegion(Region.region1()); 17 | group01.addRegion(Region.region2()); 18 | 19 | RegionGroup group02 = (RegionGroup) group01.clone(); 20 | 21 | assertNotSame(group01, group02); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/storage/ZoneTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.storage; 2 | 3 | import com.qiniu.common.Zone; 4 | import com.qiniu.storage.Configuration; 5 | import com.qiniu.util.Auth; 6 | import org.junit.jupiter.api.Tag; 7 | import org.junit.jupiter.api.Test; 8 | 9 | public class ZoneTest { 10 | 11 | @Test 12 | @Tag("UnitTest") 13 | public void zone1() { 14 | String ak = ""; 15 | String sk = ""; 16 | Auth auth = Auth.create(ak, sk); 17 | 18 | // Configuration.defaultApiHost = "apiserver-sdfrsd-s.qiniubbo.com"; 19 | // Configuration.defaultRsHost = "rs-sdfrsd-s.qiniubbo.com"; 20 | Zone zone = new Zone.Builder().upHttp("http://up-sdfrsd-s.qiniubbo.com") 21 | .upBackupHttp("http://up-sdfrsd-s.qiniubbo.com") 22 | .rsHttp("http://rs-sdfrsd-s.qiniubbo.com").rsfHttp("http://rsf-sdfrsd-s.qiniubbo.com") 23 | .apiHttp("http://apiserver-sdfrsd-s.qiniubbo.com") 24 | .iovipHttp("http://io-sdfrsd-s.qiniubbo.com").build(); 25 | 26 | Zone zone2 = new Zone.Builder(zone).iovipHttp("http://io-sdfrsd-s.qiniubbo.com").build(); 27 | 28 | Configuration cfg = new Configuration(Zone.autoZone()); 29 | cfg.zone = zone2; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/streaming/UrlTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.streaming; 2 | 3 | import com.qiniu.streaming.UrlFactory; 4 | import org.junit.jupiter.api.Disabled; 5 | import org.junit.jupiter.api.Tag; 6 | import org.junit.jupiter.api.Test; 7 | import test.com.qiniu.TestConfig; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertTrue; 10 | 11 | /** 12 | * Created by bailong on 16/9/22. 13 | */ 14 | public class UrlTest { 15 | @Test 16 | @Disabled 17 | @Tag("UnitTest") 18 | public void testUrl() { 19 | String hubName = "test"; 20 | String pubDomain = "publish-rtmp.test.com"; 21 | String rtmpDomain = "live-rtmp.test.com"; 22 | String hlsDomain = "live-hls.test.com"; 23 | String hdlDomain = "live-hdl.test.com"; 24 | String snapDomain = "live-snapshot.test.com"; 25 | 26 | UrlFactory uf = new UrlFactory(hubName, TestConfig.dummyAuth, pubDomain, rtmpDomain, hlsDomain, hdlDomain, 27 | snapDomain); 28 | String expect = "rtmp://publish-rtmp.test.com/" + hubName + "/key?e="; 29 | String url = uf.rtmpPublishUrl("key", 3600); 30 | System.out.println(url); 31 | assertTrue(url.startsWith(expect)); 32 | 33 | expect = "rtmp://live-rtmp.test.com/" + hubName + "/key"; 34 | url = uf.rtmpPlayUrl("key"); 35 | assertTrue(url.startsWith(expect)); 36 | 37 | expect = "http://live-hls.test.com/" + hubName + "/key.m3u8"; 38 | url = uf.hlsPlayUrl("key"); 39 | assertTrue(url.startsWith(expect)); 40 | 41 | expect = "http://live-hdl.test.com/" + hubName + "/key.flv"; 42 | url = uf.hdlPlayUrl("key"); 43 | assertTrue(url.startsWith(expect)); 44 | 45 | expect = "http://live-snapshot.test.com/" + hubName + "/key.jpg"; 46 | url = uf.snapshotUrl("key"); 47 | assertTrue(url.startsWith(expect)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/Base64Test.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.util.UrlSafeBase64; 4 | import org.junit.jupiter.api.Tag; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import java.io.UnsupportedEncodingException; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class Base64Test { 12 | @Test 13 | @Tag("UnitTest") 14 | public void testEncode() throws UnsupportedEncodingException { 15 | String data = "你好/+="; 16 | String result = UrlSafeBase64.encodeToString(data); 17 | assertEquals("5L2g5aW9Lys9", result); 18 | } 19 | 20 | @Test 21 | @Tag("UnitTest") 22 | public void testEmpty() { 23 | String base64Empty = UrlSafeBase64.encodeToString(""); 24 | assertEquals("", base64Empty); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/CacheTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.util.Cache; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | public class CacheTest { 9 | 10 | @Test 11 | public void testCache() { 12 | Info info = new Info(); 13 | info.foo = "foo"; 14 | info.bar = 1; 15 | 16 | String key = "info_key"; 17 | Cache cache = new Cache.Builder(Info.class) 18 | .setVersion("v1") 19 | .builder(); 20 | 21 | cache.cache(key, info); 22 | 23 | 24 | // 1. 测试内存缓存 25 | Info memInfo = (Info) cache.cacheForKey(key); 26 | assertEquals("foo", memInfo.foo); 27 | 28 | // 2. 测试删除内存缓存 29 | cache.clearMemoryCache(); 30 | memInfo = (Info) cache.cacheForKey(key); 31 | assertEquals(null, memInfo); 32 | 33 | // 3. 测试 load 34 | cache = new Cache.Builder(Info.class) 35 | .setVersion("v1") 36 | .builder(); 37 | memInfo = (Info) cache.cacheForKey(key); 38 | assertEquals("foo", memInfo.foo); 39 | } 40 | 41 | static class Info { 42 | String foo; 43 | int bar; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/CrcTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.util.Crc32; 4 | import org.junit.jupiter.api.Tag; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals; 8 | 9 | public class CrcTest { 10 | @Test 11 | @Tag("UnitTest") 12 | public void testCrc() { 13 | byte[] data = "Hello, World!".getBytes(); 14 | long result = Crc32.bytes(data); 15 | assertEquals(3964322768L, result); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/EtagTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.common.Constants; 4 | import com.qiniu.util.Etag; 5 | import org.junit.jupiter.api.Tag; 6 | import org.junit.jupiter.api.Test; 7 | import test.com.qiniu.TempFile; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertEquals; 13 | 14 | public class EtagTest { 15 | @Test 16 | @Tag("UnitTest") 17 | public void testData() { 18 | String m = Etag.data(new byte[0]); 19 | assertEquals("Fto5o-5ea0sNMlW_75VgGJCv2AcJ", m); 20 | 21 | String etag = Etag.data("etag".getBytes(Constants.UTF_8)); 22 | assertEquals("FpLiADEaVoALPkdb8tJEJyRTXoe_", etag); 23 | } 24 | 25 | @Test 26 | @Tag("UnitTest") 27 | public void testFile() throws IOException { 28 | File f = TempFile.createFileOld(1024); 29 | assertEquals("FqOV9T8l48x1u9dFEOROzwp4b0jr", Etag.file(f)); 30 | TempFile.remove(f); 31 | 32 | f = TempFile.createFileOld(4 * 1024); 33 | // System.out.println(Etag.file(f)); 34 | assertEquals("FgtlGCfS97kgqopAxq0vvKRA5o_R", Etag.file(f)); 35 | TempFile.remove(f); 36 | 37 | f = TempFile.createFileOld(5 * 1024); 38 | // System.out.println(Etag.file(f)); 39 | assertEquals("lvtM_iKNnZXkZR8U3Fvi_QQO2yyi", Etag.file(f)); 40 | TempFile.remove(f); 41 | 42 | f = TempFile.createFileOld(8 * 1024); 43 | // System.out.println(Etag.file(f)); 44 | assertEquals("lhiIbcJgsRrl46LwMD9KHAQRLH2O", Etag.file(f)); 45 | TempFile.remove(f); 46 | 47 | f = TempFile.createFileOld(9 * 1024); 48 | // System.out.println(Etag.file(f)); 49 | assertEquals("ll1xhlUFKQqynVgMMt_J1TuTrdB1", Etag.file(f)); 50 | TempFile.remove(f); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/JsonTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.qiniu.util.Json; 5 | import com.qiniu.util.StringMap; 6 | import org.junit.jupiter.api.Tag; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | public class JsonTest { 13 | @Test 14 | @Tag("UnitTest") 15 | public void testMapToString() { 16 | StringMap map = new StringMap().put("k", "v").put("n", 1); 17 | String j = Json.encode(map); 18 | assertTrue(j.equals("{\"k\":\"v\",\"n\":1}") || j.equals("{\"n\":1,\"k\":\"v\"}")); 19 | } 20 | 21 | @Test 22 | @Tag("UnitTest") 23 | public void testJ0() { 24 | User u = new User("a", 23); 25 | u.s1 = "s1"; 26 | u.i1 = 1; 27 | String j = u.toString(); 28 | System.out.println(u); 29 | System.out.println(j); 30 | assertTrue(j.indexOf("s1") == -1, " no s1, i1 fields"); 31 | } 32 | 33 | @Test 34 | @Tag("UnitTest") 35 | public void testJ() { 36 | String s = "{\"name\":\"怪盗kidou\",\"age\":24}"; 37 | User u = new Gson().fromJson(s, User.class); 38 | System.out.println(u); 39 | assertEquals("怪盗kidou", u.name); 40 | assertEquals(24, u.age); 41 | } 42 | 43 | @Test 44 | @Tag("UnitTest") 45 | public void testJ2() { 46 | String s = "{\"emailAddress\":\"怪盗kidou\",\"age\":24}"; 47 | User u = new Gson().fromJson(s, User.class); 48 | System.out.println(u); 49 | assertEquals("怪盗kidou", u.emailAddress); 50 | assertEquals(24, u.age); 51 | } 52 | 53 | @Test 54 | @Tag("UnitTest") 55 | public void testJ3() { 56 | String s = "{\"name\":\"怪盗kidou\",\"age\":24, \"emailAddress\":\"s.com\", \"xxx\":98}"; 57 | User u = new Gson().fromJson(s, User.class); 58 | System.out.println(u); 59 | assertEquals("怪盗kidou", u.name); 60 | assertEquals("s.com", u.emailAddress); 61 | assertEquals(24, u.age); 62 | } 63 | 64 | private class User { 65 | transient String s1; 66 | transient int i1; 67 | // 省略其它 68 | private String name; 69 | private int age; 70 | private String emailAddress; 71 | private String nameNull; 72 | 73 | User(String name, int age) { 74 | this.name = name; 75 | this.age = age; 76 | // this.emailAddress = emailAddress; 77 | } 78 | 79 | public String toString() { 80 | return new Gson().toJson(this); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/Md5Test.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.util.Md5; 4 | import com.qiniu.util.StringUtils; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Tag; 7 | import org.junit.jupiter.api.Test; 8 | import test.com.qiniu.TempFile; 9 | 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.IOException; 13 | import java.security.NoSuchAlgorithmException; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | 17 | public class Md5Test { 18 | File f; 19 | 20 | @BeforeEach 21 | public void init() throws IOException { 22 | f = TempFile.createFileOld(1); 23 | } 24 | 25 | @Test 26 | @Tag("UnitTest") 27 | public void test1() throws IOException, NoSuchAlgorithmException { 28 | System.out.println(f.getAbsolutePath()); 29 | String md5 = Md5.md5(f); 30 | System.out.println(md5); 31 | 32 | FileInputStream fis = new FileInputStream(f); 33 | byte[] data = new byte[1024 * 1024 * 7]; 34 | int l = fis.read(data); 35 | String md5_data = Md5.md5(data, 0, l); 36 | System.out.println(l + ", " + data.length + " md5 " + md5_data); 37 | 38 | assertEquals(md5, md5_data); 39 | assertEquals(md5, "0f343b0931126a20f133d67c2b018a3b"); 40 | String src = "FileInputStream fis = new FileInputStream(f);"; 41 | 42 | String md5Str = StringUtils.md5Lower(src); 43 | System.out.println(md5Str); 44 | 45 | assertEquals(md5Str, Md5.md5(src.getBytes())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/test/com/qiniu/util/UrlComposerTest.java: -------------------------------------------------------------------------------- 1 | package test.com.qiniu.util; 2 | 3 | import com.qiniu.util.StringMap; 4 | import com.qiniu.util.UrlUtils; 5 | import org.junit.jupiter.api.Tag; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | public class UrlComposerTest { 11 | @Test 12 | @Tag("UnitTest") 13 | public void testComposeUrlWithQueries() { 14 | String testUrl = "http://sms.qiniuapi.com/v1/signature"; 15 | StringMap queryMap = new StringMap().put("page", 1).put("page_size", 10); 16 | String url = UrlUtils.composeUrlWithQueries(testUrl, queryMap); 17 | assertTrue(url.equals("http://sms.qiniuapi.com/v1/signature?page=1&page_size=10") 18 | || url.equals("http://sms.qiniuapi.com/v1/signature?page_size=10&page=1")); 19 | } 20 | 21 | @Test 22 | @Tag("UnitTest") 23 | public void testNonEncoding() { 24 | String u = "http://asfd.clouddn.com/s共df/_-+./*/~/@/:/!/$/&/&/'/(/)/*/+/,/;\"/=/ /" 25 | + "sdf/*/~/@/:/!/$/&/&/'/(/)/*/+/,/;\"/=/ /?sdfr=34sdf"; 26 | String f = "http://asfd.clouddn.com/s%E5%85%B1df/_-+./%2A/~/@/:/%21/$/&/&/%27/%28/%29/%2A/+/,/;%22/=/%20/" 27 | + "sdf/%2A/~/@/:/%21/$/&/&/%27/%28/%29/%2A/+/,/;%22/=/%20/?sdfr=34sdf"; 28 | String c = UrlUtils.urlEncode(u, UrlUtils.PLUS_NON_ENCODING); // ~@:$&+,;=/? no !'()* 29 | String cdefault = UrlUtils.urlEncode(u); // use UrlUtils.PLUS_NON_ENCODING 30 | assertEquals(c, cdefault); 31 | assertTrue(c.indexOf("%20") > -1 && c.indexOf(" ") == -1); 32 | assertFalse(java.util.regex.Pattern.compile("[!'()*]").matcher(f).find()); 33 | assertEquals(f, c); 34 | 35 | String f2 = "http://asfd.clouddn.com/s%E5%85%B1df/_-+./*/~/@/:/!/$/&/&/'/(/)/*/+/,/;%22/=/%20/" 36 | + "sdf/*/~/@/:/!/$/&/&/'/(/)/*/+/,/;%22/=/%20/?sdfr=34sdf"; 37 | String c2 = UrlUtils.urlEncode(u, UrlUtils.PLUS_NON_ENCODING2); // ~@:!$&'()*+,;=/? 38 | assertEquals(f2, c2); 39 | assertTrue(java.util.regex.Pattern.compile("[!'()*]").matcher(f2).find()); 40 | 41 | assertNotEquals(c, c2); 42 | String c3 = c.replaceAll("%21", "!").replaceAll("%27", "'").replaceAll("%28", "(") 43 | .replaceAll("%29", ")").replaceAll("%2A", "*"); 44 | assertEquals(c2, c3); 45 | } 46 | 47 | } 48 | --------------------------------------------------------------------------------