├── openapi ├── .openapi-generator │ ├── VERSION │ └── FILES ├── docs │ ├── Status.md │ ├── Failure.md │ ├── PinResults.md │ ├── FailureError.md │ ├── Pin.md │ ├── PinStatus.md │ └── PinsApi.md ├── .openapi-generator-ignore ├── response.go ├── model_status.go ├── model_failure.go ├── model_pin_results.go ├── model_failure_error.go ├── README.md ├── model_pin.go ├── model_pin_status.go ├── configuration.go ├── utils.go └── client.go ├── version.json ├── .github └── workflows │ ├── stale.yml │ ├── releaser.yml │ ├── tagpush.yml │ ├── automerge.yml │ ├── release-check.yml │ ├── go-check.yml │ └── go-test.yml ├── .gitignore ├── LICENSE ├── go.mod ├── README.md ├── cmd └── main.go ├── model.go ├── go.sum └── client.go /openapi/.openapi-generator/VERSION: -------------------------------------------------------------------------------- 1 | 5.0.0-beta -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v0.1.3" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close and mark stale issue 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | stale: 9 | uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3 10 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Releaser 5 | on: 6 | push: 7 | paths: [ 'version.json' ] 8 | 9 | jobs: 10 | releaser: 11 | uses: protocol/.github/.github/workflows/releaser.yml@master 12 | -------------------------------------------------------------------------------- /.github/workflows/tagpush.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Tag Push Checker 5 | on: 6 | push: 7 | tags: 8 | - v* 9 | 10 | jobs: 11 | releaser: 12 | uses: protocol/.github/.github/workflows/tagpush.yml@master 13 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Automerge 5 | on: [ pull_request ] 6 | 7 | jobs: 8 | automerge: 9 | uses: protocol/.github/.github/workflows/automerge.yml@master 10 | with: 11 | job: 'automerge' 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /openapi/docs/Status.md: -------------------------------------------------------------------------------- 1 | # Status 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | 8 | 9 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/release-check.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Release Checker 5 | on: 6 | pull_request_target: 7 | paths: [ 'version.json' ] 8 | 9 | jobs: 10 | release-check: 11 | uses: protocol/.github/.github/workflows/release-check.yml@master 12 | with: 13 | go-version: 1.20.x 14 | -------------------------------------------------------------------------------- /openapi/.openapi-generator/FILES: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .openapi-generator-ignore 3 | .travis.yml 4 | README.md 5 | api/openapi.yaml 6 | api_pins.go 7 | client.go 8 | configuration.go 9 | docs/Failure.md 10 | docs/FailureError.md 11 | docs/Pin.md 12 | docs/PinResults.md 13 | docs/PinStatus.md 14 | docs/PinsApi.md 15 | docs/Status.md 16 | git_push.sh 17 | go.mod 18 | go.sum 19 | model_failure.go 20 | model_failure_error.go 21 | model_pin.go 22 | model_pin_results.go 23 | model_pin_status.go 24 | model_status.go 25 | response.go 26 | utils.go 27 | -------------------------------------------------------------------------------- /openapi/.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | # OpenAPI Generator Ignore 2 | # Generated by openapi-generator https://github.com/openapitools/openapi-generator 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The software contents of this repository are Copyright (c) Protocol Labs, 2 | Licensed under the `Permissive License Stack`, meaning either of: 3 | 4 | - Apache-2.0 Software License: https://www.apache.org/licenses/LICENSE-2.0 5 | ([...4tr2kfsq](https://gateway.ipfs.io/ipfs/bafkreiankqxazcae4onkp436wag2lj3ccso4nawxqkkfckd6cg4tr2kfsq)) 6 | 7 | - MIT Software License: https://opensource.org/licenses/MIT 8 | ([...vljevcba](https://gateway.ipfs.io/ipfs/bafkreiepofszg4gfe2gzuhojmksgemsub2h4uy2gewdnr35kswvljevcba)) 9 | 10 | You may not use the contents of this repository except in compliance 11 | with one of the listed Licenses. For an extended clarification of the 12 | intent behind the choice of Licensing please refer to 13 | https://protocol.ai/blog/announcing-the-permissive-license-stack/ 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the terms listed in this notice is distributed on 17 | an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 18 | either express or implied. See each License for the specific language 19 | governing permissions and limitations under that License. 20 | 21 | 22 | `SPDX-License-Identifier: Apache-2.0 OR MIT` -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ipfs/go-pinning-service-http-client 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/ipfs/go-cid v0.1.0 7 | github.com/ipfs/go-log/v2 v2.1.1 8 | github.com/multiformats/go-multiaddr v0.5.0 9 | github.com/multiformats/go-multibase v0.0.3 10 | github.com/pkg/errors v0.9.1 11 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 12 | ) 13 | 14 | require ( 15 | github.com/golang/protobuf v1.2.0 // indirect 16 | github.com/klauspost/cpuid/v2 v2.0.4 // indirect 17 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect 18 | github.com/minio/sha256-simd v1.0.0 // indirect 19 | github.com/mr-tron/base58 v1.2.0 // indirect 20 | github.com/multiformats/go-base32 v0.0.3 // indirect 21 | github.com/multiformats/go-base36 v0.1.0 // indirect 22 | github.com/multiformats/go-multihash v0.0.15 // indirect 23 | github.com/multiformats/go-varint v0.0.6 // indirect 24 | go.uber.org/atomic v1.6.0 // indirect 25 | go.uber.org/multierr v1.5.0 // indirect 26 | go.uber.org/zap v1.14.1 // indirect 27 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf // indirect 28 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect 29 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect 30 | google.golang.org/appengine v1.4.0 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /openapi/docs/Failure.md: -------------------------------------------------------------------------------- 1 | # Failure 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | **Error** | [**FailureError**](Failure_error.md) | | 8 | 9 | ## Methods 10 | 11 | ### NewFailure 12 | 13 | `func NewFailure(error_ FailureError, ) *Failure` 14 | 15 | NewFailure instantiates a new Failure object 16 | This constructor will assign default values to properties that have it defined, 17 | and makes sure properties required by API are set, but the set of arguments 18 | will change when the set of required properties is changed 19 | 20 | ### NewFailureWithDefaults 21 | 22 | `func NewFailureWithDefaults() *Failure` 23 | 24 | NewFailureWithDefaults instantiates a new Failure object 25 | This constructor will only assign default values to properties that have it defined, 26 | but it doesn't guarantee that properties required by API are set 27 | 28 | ### GetError 29 | 30 | `func (o *Failure) GetError() FailureError` 31 | 32 | GetError returns the Error field if non-nil, zero value otherwise. 33 | 34 | ### GetErrorOk 35 | 36 | `func (o *Failure) GetErrorOk() (*FailureError, bool)` 37 | 38 | GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise 39 | and a boolean to check if the value has been set. 40 | 41 | ### SetError 42 | 43 | `func (o *Failure) SetError(v FailureError)` 44 | 45 | SetError sets Error field to given value. 46 | 47 | 48 | 49 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 50 | 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-pinning-service-http-client 2 | 3 | > This repo is contains a reference implementation of a client for the [IPFS Pinning Services API Spec](https://github.com/ipfs/pinning-services-api-spec) 4 | 5 | 6 | [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai) 7 | [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.io/) 8 | [![](https://img.shields.io/badge/status-draft-yellow.svg?style=flat-square)](https://github.com/ipfs/specs/#understanding-the-meaning-of-the-spec-badges-and-their-lifecycle) 9 | 10 | ## ❗ This repo is no longer maintained. 11 | 12 | 👉 We highly recommend switching to the maintained version at https://github.com/ipfs/boxo/tree/main/pinning/remote. 13 | 🏎️ Good news! There is [tooling and documentation](https://github.com/ipfs/boxo#migrating-to-boxo) to expedite a switch in your repo. 14 | 15 | ⚠️ If you continue using this repo, please note that security fixes will not be provided (unless someone steps in to maintain it). 16 | 17 | 📚 Learn more, including how to take the maintainership mantle or ask questions, [here](https://github.com/ipfs/boxo/wiki/Copied-or-Migrated-Repos-FAQ). 18 | 19 | 20 | ## Updating Pinning Service Spec 21 | 22 | Download the openapi-generator from https://github.com/OpenAPITools/openapi-generator and generate the code using: 23 | 24 | Current code generated with: openapi-generator 5.0.0-beta 25 | 26 | ``` 27 | openapi-generator generate -g go-experimental -i https://raw.githubusercontent.com/ipfs/pinning-services-api-spec/master/ipfs-pinning-service.yaml -o openapi 28 | rm openapi/go.mod openapi/go.sum 29 | ``` 30 | 31 | Notes: 32 | Due to https://github.com/OpenAPITools/openapi-generator/issues/7473 the code generator the http error codes processing 33 | may need some manual editing. 34 | 35 | `go-experimental` is becoming mainstream and so in later versions will be replaced with `go` 36 | 37 | ## License 38 | 39 | [SPDX-License-Identifier: Apache-2.0 OR MIT](LICENSE.md) 40 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "time" 8 | 9 | "github.com/ipfs/go-cid" 10 | pinclient "github.com/ipfs/go-pinning-service-http-client" 11 | ) 12 | 13 | func main() { 14 | ctx, cancel := context.WithCancel(context.Background()) 15 | defer cancel() 16 | 17 | url, ok := os.LookupEnv("PS_URL") 18 | if !ok { 19 | panic("No Pinning Service URL found") 20 | } 21 | 22 | key, ok := os.LookupEnv("PS_KEY") 23 | if !ok { 24 | panic("No Pinning Service API Key found") 25 | } 26 | 27 | c := pinclient.NewClient(url, key) 28 | 29 | ipfsPgCid, err := cid.Parse("bafybeiayvrj27f65vbecspbnuavehcb3znvnt2strop2rfbczupudoizya") 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | libp2pCid, err := cid.Parse("bafybeiejgrxo4p4uofgfzvlg5twrg5w7tfwpf7aciiswfacfbdpevg2xfy") 35 | if err != nil { 36 | panic(err) 37 | } 38 | _ = ipfsPgCid 39 | 40 | listPins(ctx, c) 41 | 42 | fmt.Println("Adding libp2p home page") 43 | ps, err := c.Add(ctx, libp2pCid, pinclient.PinOpts.WithName("libp2p")) 44 | if err == nil { 45 | fmt.Printf("PinStatus: %v \n", ps) 46 | } else { 47 | fmt.Println(err) 48 | } 49 | 50 | listPins(ctx, c) 51 | 52 | fmt.Println("Check on pin status") 53 | if ps == nil { 54 | panic("Skipping pin status check because the pin is null") 55 | } 56 | 57 | var pinned bool 58 | for !pinned { 59 | status, err := c.GetStatusByID(ctx, ps.GetRequestId()) 60 | if err == nil { 61 | fmt.Println(status.GetStatus()) 62 | pinned = status.GetStatus() == pinclient.StatusPinned 63 | } else { 64 | fmt.Println(err) 65 | } 66 | time.Sleep(time.Millisecond * 500) 67 | } 68 | 69 | listPins(ctx, c) 70 | 71 | fmt.Println("Delete pin") 72 | err = c.DeleteByID(ctx, ps.GetRequestId()) 73 | if err == nil { 74 | fmt.Println("Successfully deleted pin") 75 | } else { 76 | fmt.Println(err) 77 | } 78 | 79 | listPins(ctx, c) 80 | } 81 | 82 | func listPins(ctx context.Context, c *pinclient.Client) { 83 | fmt.Println("List all pins") 84 | pins, err := c.LsSync(ctx) 85 | if err != nil { 86 | fmt.Println(err) 87 | } else { 88 | for _, p := range pins { 89 | fmt.Printf("Pin: %v \n", p) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /openapi/docs/PinResults.md: -------------------------------------------------------------------------------- 1 | # PinResults 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | **Count** | **int32** | The total number of pin objects that exist for passed query filters | 8 | **Results** | [**[]PinStatus**](PinStatus.md) | An array of PinStatus results | 9 | 10 | ## Methods 11 | 12 | ### NewPinResults 13 | 14 | `func NewPinResults(count int32, results []PinStatus, ) *PinResults` 15 | 16 | NewPinResults instantiates a new PinResults object 17 | This constructor will assign default values to properties that have it defined, 18 | and makes sure properties required by API are set, but the set of arguments 19 | will change when the set of required properties is changed 20 | 21 | ### NewPinResultsWithDefaults 22 | 23 | `func NewPinResultsWithDefaults() *PinResults` 24 | 25 | NewPinResultsWithDefaults instantiates a new PinResults object 26 | This constructor will only assign default values to properties that have it defined, 27 | but it doesn't guarantee that properties required by API are set 28 | 29 | ### GetCount 30 | 31 | `func (o *PinResults) GetCount() int32` 32 | 33 | GetCount returns the Count field if non-nil, zero value otherwise. 34 | 35 | ### GetCountOk 36 | 37 | `func (o *PinResults) GetCountOk() (*int32, bool)` 38 | 39 | GetCountOk returns a tuple with the Count field if it's non-nil, zero value otherwise 40 | and a boolean to check if the value has been set. 41 | 42 | ### SetCount 43 | 44 | `func (o *PinResults) SetCount(v int32)` 45 | 46 | SetCount sets Count field to given value. 47 | 48 | 49 | ### GetResults 50 | 51 | `func (o *PinResults) GetResults() []PinStatus` 52 | 53 | GetResults returns the Results field if non-nil, zero value otherwise. 54 | 55 | ### GetResultsOk 56 | 57 | `func (o *PinResults) GetResultsOk() (*[]PinStatus, bool)` 58 | 59 | GetResultsOk returns a tuple with the Results field if it's non-nil, zero value otherwise 60 | and a boolean to check if the value has been set. 61 | 62 | ### SetResults 63 | 64 | `func (o *PinResults) SetResults(v []PinStatus)` 65 | 66 | SetResults sets Results field to given value. 67 | 68 | 69 | 70 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 71 | 72 | 73 | -------------------------------------------------------------------------------- /openapi/docs/FailureError.md: -------------------------------------------------------------------------------- 1 | # FailureError 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | **Reason** | **string** | Mandatory string identifying the type of error | 8 | **Details** | Pointer to **string** | Optional, longer description of the error; may include UUID of transaction for support, links to documentation etc | [optional] 9 | 10 | ## Methods 11 | 12 | ### NewFailureError 13 | 14 | `func NewFailureError(reason string, ) *FailureError` 15 | 16 | NewFailureError instantiates a new FailureError object 17 | This constructor will assign default values to properties that have it defined, 18 | and makes sure properties required by API are set, but the set of arguments 19 | will change when the set of required properties is changed 20 | 21 | ### NewFailureErrorWithDefaults 22 | 23 | `func NewFailureErrorWithDefaults() *FailureError` 24 | 25 | NewFailureErrorWithDefaults instantiates a new FailureError object 26 | This constructor will only assign default values to properties that have it defined, 27 | but it doesn't guarantee that properties required by API are set 28 | 29 | ### GetReason 30 | 31 | `func (o *FailureError) GetReason() string` 32 | 33 | GetReason returns the Reason field if non-nil, zero value otherwise. 34 | 35 | ### GetReasonOk 36 | 37 | `func (o *FailureError) GetReasonOk() (*string, bool)` 38 | 39 | GetReasonOk returns a tuple with the Reason field if it's non-nil, zero value otherwise 40 | and a boolean to check if the value has been set. 41 | 42 | ### SetReason 43 | 44 | `func (o *FailureError) SetReason(v string)` 45 | 46 | SetReason sets Reason field to given value. 47 | 48 | 49 | ### GetDetails 50 | 51 | `func (o *FailureError) GetDetails() string` 52 | 53 | GetDetails returns the Details field if non-nil, zero value otherwise. 54 | 55 | ### GetDetailsOk 56 | 57 | `func (o *FailureError) GetDetailsOk() (*string, bool)` 58 | 59 | GetDetailsOk returns a tuple with the Details field if it's non-nil, zero value otherwise 60 | and a boolean to check if the value has been set. 61 | 62 | ### SetDetails 63 | 64 | `func (o *FailureError) SetDetails(v string)` 65 | 66 | SetDetails sets Details field to given value. 67 | 68 | ### HasDetails 69 | 70 | `func (o *FailureError) HasDetails() bool` 71 | 72 | HasDetails returns a boolean if a field has been set. 73 | 74 | 75 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 76 | 77 | 78 | -------------------------------------------------------------------------------- /.github/workflows/go-check.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | on: [push, pull_request] 5 | name: Go Checks 6 | 7 | jobs: 8 | unit: 9 | runs-on: ubuntu-latest 10 | name: All 11 | steps: 12 | - uses: actions/checkout@v3 13 | with: 14 | submodules: recursive 15 | - id: config 16 | uses: protocol/.github/.github/actions/read-config@master 17 | - uses: actions/setup-go@v3 18 | with: 19 | go-version: 1.20.x 20 | - name: Run repo-specific setup 21 | uses: ./.github/actions/go-check-setup 22 | if: hashFiles('./.github/actions/go-check-setup') != '' 23 | - name: Install staticcheck 24 | run: go install honnef.co/go/tools/cmd/staticcheck@4970552d932f48b71485287748246cf3237cebdf # 2023.1 (v0.4.0) 25 | - name: Check that go.mod is tidy 26 | uses: protocol/multiple-go-modules@v1.2 27 | with: 28 | run: | 29 | go mod tidy 30 | if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then 31 | echo "go.sum was added by go mod tidy" 32 | exit 1 33 | fi 34 | git diff --exit-code -- go.sum go.mod 35 | - name: gofmt 36 | if: success() || failure() # run this step even if the previous one failed 37 | run: | 38 | out=$(gofmt -s -l .) 39 | if [[ -n "$out" ]]; then 40 | echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}' 41 | exit 1 42 | fi 43 | - name: go vet 44 | if: success() || failure() # run this step even if the previous one failed 45 | uses: protocol/multiple-go-modules@v1.2 46 | with: 47 | run: go vet ./... 48 | - name: staticcheck 49 | if: success() || failure() # run this step even if the previous one failed 50 | uses: protocol/multiple-go-modules@v1.2 51 | with: 52 | run: | 53 | set -o pipefail 54 | staticcheck ./... | sed -e 's@\(.*\)\.go@./\1.go@g' 55 | - name: go generate 56 | uses: protocol/multiple-go-modules@v1.2 57 | if: (success() || failure()) && fromJSON(steps.config.outputs.json).gogenerate == true 58 | with: 59 | run: | 60 | git clean -fd # make sure there aren't untracked files / directories 61 | go generate -x ./... 62 | # check if go generate modified or added any files 63 | if ! $(git add . && git diff-index HEAD --exit-code --quiet); then 64 | echo "go generated caused changes to the repository:" 65 | git status --short 66 | exit 1 67 | fi 68 | -------------------------------------------------------------------------------- /.github/workflows/go-test.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | on: [push, pull_request] 5 | name: Go Test 6 | 7 | jobs: 8 | unit: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [ "ubuntu", "windows", "macos" ] 13 | go: ["1.19.x","1.20.x"] 14 | env: 15 | COVERAGES: "" 16 | runs-on: ${{ fromJSON(vars[format('UCI_GO_TEST_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }} 17 | name: ${{ matrix.os }} (go ${{ matrix.go }}) 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | submodules: recursive 22 | - id: config 23 | uses: protocol/.github/.github/actions/read-config@master 24 | - uses: actions/setup-go@v3 25 | with: 26 | go-version: ${{ matrix.go }} 27 | - name: Go information 28 | run: | 29 | go version 30 | go env 31 | - name: Use msys2 on windows 32 | if: matrix.os == 'windows' 33 | shell: bash 34 | # The executable for msys2 is also called bash.cmd 35 | # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#shells 36 | # If we prepend its location to the PATH 37 | # subsequent 'shell: bash' steps will use msys2 instead of gitbash 38 | run: echo "C:/msys64/usr/bin" >> $GITHUB_PATH 39 | - name: Run repo-specific setup 40 | uses: ./.github/actions/go-test-setup 41 | if: hashFiles('./.github/actions/go-test-setup') != '' 42 | - name: Run tests 43 | if: contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 44 | uses: protocol/multiple-go-modules@v1.2 45 | with: 46 | # Use -coverpkg=./..., so that we include cross-package coverage. 47 | # If package ./A imports ./B, and ./A's tests also cover ./B, 48 | # this means ./B's coverage will be significantly higher than 0%. 49 | run: go test -v -shuffle=on -coverprofile=module-coverage.txt -coverpkg=./... ./... 50 | - name: Run tests (32 bit) 51 | # can't run 32 bit tests on OSX. 52 | if: matrix.os != 'macos' && 53 | fromJSON(steps.config.outputs.json).skip32bit != true && 54 | contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 55 | uses: protocol/multiple-go-modules@v1.2 56 | env: 57 | GOARCH: 386 58 | with: 59 | run: | 60 | export "PATH=$PATH_386:$PATH" 61 | go test -v -shuffle=on ./... 62 | - name: Run tests with race detector 63 | # speed things up. Windows and OSX VMs are slow 64 | if: matrix.os == 'ubuntu' && 65 | contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 66 | uses: protocol/multiple-go-modules@v1.2 67 | with: 68 | run: go test -v -race ./... 69 | - name: Collect coverage files 70 | shell: bash 71 | run: echo "COVERAGES=$(find . -type f -name 'module-coverage.txt' | tr -s '\n' ',' | sed 's/,$//')" >> $GITHUB_ENV 72 | - name: Upload coverage to Codecov 73 | uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 74 | with: 75 | files: '${{ env.COVERAGES }}' 76 | env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }} 77 | -------------------------------------------------------------------------------- /openapi/docs/Pin.md: -------------------------------------------------------------------------------- 1 | # Pin 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | **Cid** | **string** | Content Identifier (CID) to be pinned recursively | 8 | **Name** | Pointer to **string** | Optional name for pinned data; can be used for lookups later | [optional] 9 | **Origins** | Pointer to **[]string** | Optional list of multiaddrs known to provide the data | [optional] 10 | **Meta** | Pointer to **map[string]string** | Optional metadata for pin object | [optional] 11 | 12 | ## Methods 13 | 14 | ### NewPin 15 | 16 | `func NewPin(cid string, ) *Pin` 17 | 18 | NewPin instantiates a new Pin object 19 | This constructor will assign default values to properties that have it defined, 20 | and makes sure properties required by API are set, but the set of arguments 21 | will change when the set of required properties is changed 22 | 23 | ### NewPinWithDefaults 24 | 25 | `func NewPinWithDefaults() *Pin` 26 | 27 | NewPinWithDefaults instantiates a new Pin object 28 | This constructor will only assign default values to properties that have it defined, 29 | but it doesn't guarantee that properties required by API are set 30 | 31 | ### GetCid 32 | 33 | `func (o *Pin) GetCid() string` 34 | 35 | GetCid returns the Cid field if non-nil, zero value otherwise. 36 | 37 | ### GetCidOk 38 | 39 | `func (o *Pin) GetCidOk() (*string, bool)` 40 | 41 | GetCidOk returns a tuple with the Cid field if it's non-nil, zero value otherwise 42 | and a boolean to check if the value has been set. 43 | 44 | ### SetCid 45 | 46 | `func (o *Pin) SetCid(v string)` 47 | 48 | SetCid sets Cid field to given value. 49 | 50 | 51 | ### GetName 52 | 53 | `func (o *Pin) GetName() string` 54 | 55 | GetName returns the Name field if non-nil, zero value otherwise. 56 | 57 | ### GetNameOk 58 | 59 | `func (o *Pin) GetNameOk() (*string, bool)` 60 | 61 | GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise 62 | and a boolean to check if the value has been set. 63 | 64 | ### SetName 65 | 66 | `func (o *Pin) SetName(v string)` 67 | 68 | SetName sets Name field to given value. 69 | 70 | ### HasName 71 | 72 | `func (o *Pin) HasName() bool` 73 | 74 | HasName returns a boolean if a field has been set. 75 | 76 | ### GetOrigins 77 | 78 | `func (o *Pin) GetOrigins() []string` 79 | 80 | GetOrigins returns the Origins field if non-nil, zero value otherwise. 81 | 82 | ### GetOriginsOk 83 | 84 | `func (o *Pin) GetOriginsOk() (*[]string, bool)` 85 | 86 | GetOriginsOk returns a tuple with the Origins field if it's non-nil, zero value otherwise 87 | and a boolean to check if the value has been set. 88 | 89 | ### SetOrigins 90 | 91 | `func (o *Pin) SetOrigins(v []string)` 92 | 93 | SetOrigins sets Origins field to given value. 94 | 95 | ### HasOrigins 96 | 97 | `func (o *Pin) HasOrigins() bool` 98 | 99 | HasOrigins returns a boolean if a field has been set. 100 | 101 | ### GetMeta 102 | 103 | `func (o *Pin) GetMeta() map[string]string` 104 | 105 | GetMeta returns the Meta field if non-nil, zero value otherwise. 106 | 107 | ### GetMetaOk 108 | 109 | `func (o *Pin) GetMetaOk() (*map[string]string, bool)` 110 | 111 | GetMetaOk returns a tuple with the Meta field if it's non-nil, zero value otherwise 112 | and a boolean to check if the value has been set. 113 | 114 | ### SetMeta 115 | 116 | `func (o *Pin) SetMeta(v map[string]string)` 117 | 118 | SetMeta sets Meta field to given value. 119 | 120 | ### HasMeta 121 | 122 | `func (o *Pin) HasMeta() bool` 123 | 124 | HasMeta returns a boolean if a field has been set. 125 | 126 | 127 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 128 | 129 | 130 | -------------------------------------------------------------------------------- /openapi/docs/PinStatus.md: -------------------------------------------------------------------------------- 1 | # PinStatus 2 | 3 | ## Properties 4 | 5 | Name | Type | Description | Notes 6 | ------------ | ------------- | ------------- | ------------- 7 | **Requestid** | **string** | Globally unique identifier of the pin request; can be used to check the status of ongoing pinning, or pin removal | 8 | **Status** | [**Status**](Status.md) | | 9 | **Created** | [**time.Time**](time.Time.md) | Immutable timestamp indicating when a pin request entered a pinning service; can be used for filtering results and pagination | 10 | **Pin** | [**Pin**](Pin.md) | | 11 | **Delegates** | **[]string** | List of multiaddrs designated by pinning service for transferring any new data from external peers | 12 | **Info** | Pointer to **map[string]string** | Optional info for PinStatus response | [optional] 13 | 14 | ## Methods 15 | 16 | ### NewPinStatus 17 | 18 | `func NewPinStatus(requestid string, status Status, created time.Time, pin Pin, delegates []string, ) *PinStatus` 19 | 20 | NewPinStatus instantiates a new PinStatus object 21 | This constructor will assign default values to properties that have it defined, 22 | and makes sure properties required by API are set, but the set of arguments 23 | will change when the set of required properties is changed 24 | 25 | ### NewPinStatusWithDefaults 26 | 27 | `func NewPinStatusWithDefaults() *PinStatus` 28 | 29 | NewPinStatusWithDefaults instantiates a new PinStatus object 30 | This constructor will only assign default values to properties that have it defined, 31 | but it doesn't guarantee that properties required by API are set 32 | 33 | ### GetRequestid 34 | 35 | `func (o *PinStatus) GetRequestid() string` 36 | 37 | GetRequestid returns the Requestid field if non-nil, zero value otherwise. 38 | 39 | ### GetRequestidOk 40 | 41 | `func (o *PinStatus) GetRequestidOk() (*string, bool)` 42 | 43 | GetRequestidOk returns a tuple with the Requestid field if it's non-nil, zero value otherwise 44 | and a boolean to check if the value has been set. 45 | 46 | ### SetRequestid 47 | 48 | `func (o *PinStatus) SetRequestid(v string)` 49 | 50 | SetRequestid sets Requestid field to given value. 51 | 52 | 53 | ### GetStatus 54 | 55 | `func (o *PinStatus) GetStatus() Status` 56 | 57 | GetStatus returns the Status field if non-nil, zero value otherwise. 58 | 59 | ### GetStatusOk 60 | 61 | `func (o *PinStatus) GetStatusOk() (*Status, bool)` 62 | 63 | GetStatusOk returns a tuple with the Status field if it's non-nil, zero value otherwise 64 | and a boolean to check if the value has been set. 65 | 66 | ### SetStatus 67 | 68 | `func (o *PinStatus) SetStatus(v Status)` 69 | 70 | SetStatus sets Status field to given value. 71 | 72 | 73 | ### GetCreated 74 | 75 | `func (o *PinStatus) GetCreated() time.Time` 76 | 77 | GetCreated returns the Created field if non-nil, zero value otherwise. 78 | 79 | ### GetCreatedOk 80 | 81 | `func (o *PinStatus) GetCreatedOk() (*time.Time, bool)` 82 | 83 | GetCreatedOk returns a tuple with the Created field if it's non-nil, zero value otherwise 84 | and a boolean to check if the value has been set. 85 | 86 | ### SetCreated 87 | 88 | `func (o *PinStatus) SetCreated(v time.Time)` 89 | 90 | SetCreated sets Created field to given value. 91 | 92 | 93 | ### GetPin 94 | 95 | `func (o *PinStatus) GetPin() Pin` 96 | 97 | GetPin returns the Pin field if non-nil, zero value otherwise. 98 | 99 | ### GetPinOk 100 | 101 | `func (o *PinStatus) GetPinOk() (*Pin, bool)` 102 | 103 | GetPinOk returns a tuple with the Pin field if it's non-nil, zero value otherwise 104 | and a boolean to check if the value has been set. 105 | 106 | ### SetPin 107 | 108 | `func (o *PinStatus) SetPin(v Pin)` 109 | 110 | SetPin sets Pin field to given value. 111 | 112 | 113 | ### GetDelegates 114 | 115 | `func (o *PinStatus) GetDelegates() []string` 116 | 117 | GetDelegates returns the Delegates field if non-nil, zero value otherwise. 118 | 119 | ### GetDelegatesOk 120 | 121 | `func (o *PinStatus) GetDelegatesOk() (*[]string, bool)` 122 | 123 | GetDelegatesOk returns a tuple with the Delegates field if it's non-nil, zero value otherwise 124 | and a boolean to check if the value has been set. 125 | 126 | ### SetDelegates 127 | 128 | `func (o *PinStatus) SetDelegates(v []string)` 129 | 130 | SetDelegates sets Delegates field to given value. 131 | 132 | 133 | ### GetInfo 134 | 135 | `func (o *PinStatus) GetInfo() map[string]string` 136 | 137 | GetInfo returns the Info field if non-nil, zero value otherwise. 138 | 139 | ### GetInfoOk 140 | 141 | `func (o *PinStatus) GetInfoOk() (*map[string]string, bool)` 142 | 143 | GetInfoOk returns a tuple with the Info field if it's non-nil, zero value otherwise 144 | and a boolean to check if the value has been set. 145 | 146 | ### SetInfo 147 | 148 | `func (o *PinStatus) SetInfo(v map[string]string)` 149 | 150 | SetInfo sets Info field to given value. 151 | 152 | ### HasInfo 153 | 154 | `func (o *PinStatus) HasInfo() bool` 155 | 156 | HasInfo returns a boolean if a field has been set. 157 | 158 | 159 | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) 160 | 161 | 162 | -------------------------------------------------------------------------------- /model.go: -------------------------------------------------------------------------------- 1 | package go_pinning_service_http_client 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/ipfs/go-cid" 9 | "github.com/ipfs/go-pinning-service-http-client/openapi" 10 | "github.com/multiformats/go-multiaddr" 11 | ) 12 | 13 | // PinGetter Getter for Pin object 14 | // 15 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.PinGetter 16 | type PinGetter interface { 17 | fmt.Stringer 18 | json.Marshaler 19 | // CID to be pinned recursively 20 | GetCid() cid.Cid 21 | // Optional name for pinned data; can be used for lookups later 22 | GetName() string 23 | // Optional list of multiaddrs known to provide the data 24 | GetOrigins() []string 25 | // Optional metadata for pin object 26 | GetMeta() map[string]string 27 | } 28 | 29 | type pinObject struct { 30 | openapi.Pin 31 | } 32 | 33 | func (p *pinObject) MarshalJSON() ([]byte, error) { 34 | var originsStr string 35 | if o := p.GetOrigins(); o != nil { 36 | originsBytes, err := json.Marshal(o) 37 | if err == nil { 38 | originsStr = string(originsBytes) 39 | } 40 | } 41 | 42 | metaStr := "{}" 43 | if meta := p.GetMeta(); meta != nil { 44 | metaBytes, err := json.Marshal(meta) 45 | if err == nil { 46 | metaStr = string(metaBytes) 47 | } 48 | } 49 | 50 | str := fmt.Sprintf("{ \"Cid\" : \"%v\", \"Name\" : \"%s\", \"Origins\" : %v, \"Meta\" : %v }", 51 | p.GetCid(), p.GetName(), originsStr, metaStr) 52 | return []byte(str), nil 53 | } 54 | 55 | func (p *pinObject) String() string { 56 | marshalled, err := json.MarshalIndent(p, "", "\t") 57 | if err != nil { 58 | return "" 59 | } 60 | 61 | return string(marshalled) 62 | } 63 | 64 | func (p *pinObject) GetCid() cid.Cid { 65 | c, err := cid.Parse(p.Pin.Cid) 66 | if err != nil { 67 | return cid.Undef 68 | } 69 | return c 70 | } 71 | 72 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.Status 73 | type Status string 74 | 75 | const ( 76 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.StatusUnknown 77 | StatusUnknown Status = "" 78 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.StatusQueued 79 | StatusQueued Status = Status(openapi.QUEUED) 80 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.StatusPinning 81 | StatusPinning Status = Status(openapi.PINNING) 82 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.StatusPinned 83 | StatusPinned Status = Status(openapi.PINNED) 84 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.StatusFailed 85 | StatusFailed Status = Status(openapi.FAILED) 86 | ) 87 | 88 | func (s Status) String() string { 89 | switch s { 90 | case StatusQueued, StatusPinning, StatusPinned, StatusFailed: 91 | return string(s) 92 | default: 93 | return string(StatusUnknown) 94 | } 95 | } 96 | 97 | var validStatuses = []Status{"queued", "pinning", "pinned", "failed"} 98 | 99 | // PinStatusGetter Getter for Pin object with status 100 | // 101 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.PinStatusGetter 102 | type PinStatusGetter interface { 103 | fmt.Stringer 104 | json.Marshaler 105 | // Globally unique ID of the pin request; can be used to check the status of ongoing pinning, modification of pin object, or pin removal 106 | GetRequestId() string 107 | GetStatus() Status 108 | // Immutable timestamp indicating when a pin request entered a pinning service; can be used for filtering results and pagination 109 | GetCreated() time.Time 110 | GetPin() PinGetter 111 | // List of multiaddrs designated by pinning service for transferring any new data from external peers 112 | GetDelegates() []multiaddr.Multiaddr 113 | // Optional info for PinStatus response 114 | GetInfo() map[string]string 115 | } 116 | 117 | type pinStatusObject struct { 118 | openapi.PinStatus 119 | } 120 | 121 | func (p *pinStatusObject) GetDelegates() []multiaddr.Multiaddr { 122 | delegates := p.PinStatus.GetDelegates() 123 | addrs := make([]multiaddr.Multiaddr, 0, len(delegates)) 124 | for _, d := range delegates { 125 | a, err := multiaddr.NewMultiaddr(d) 126 | if err != nil { 127 | logger.Errorf("returned delegate is an invalid multiaddr: %w", err) 128 | continue 129 | } 130 | addrs = append(addrs, a) 131 | } 132 | return addrs 133 | } 134 | 135 | func (p *pinStatusObject) GetPin() PinGetter { 136 | return &pinObject{p.Pin} 137 | } 138 | 139 | func (p *pinStatusObject) GetStatus() Status { 140 | return Status(p.PinStatus.GetStatus()) 141 | } 142 | 143 | func (p *pinStatusObject) GetRequestId() string { 144 | return p.GetRequestid() 145 | } 146 | 147 | func (p *pinStatusObject) MarshalJSON() ([]byte, error) { 148 | var delegatesStr string 149 | if d := p.GetDelegates(); d != nil { 150 | delegatesBytes, err := json.Marshal(d) 151 | if err == nil { 152 | delegatesStr = string(delegatesBytes) 153 | } 154 | } 155 | 156 | infoStr := "{}" 157 | if info := p.GetInfo(); info != nil { 158 | infoBytes, err := json.Marshal(info) 159 | if err == nil { 160 | infoStr = string(infoBytes) 161 | } 162 | } 163 | 164 | str := fmt.Sprintf("{\"Pin\" : %v, \"RequestID\" : \"%s\", \"Status\" : \"%s\", \"Created\" : \"%v\", \"Delegates\" : %v, \"Info\" : %v }", 165 | p.GetPin(), p.GetRequestId(), p.GetStatus(), p.GetCreated(), delegatesStr, infoStr) 166 | 167 | return []byte(str), nil 168 | } 169 | 170 | func (p *pinStatusObject) String() string { 171 | marshalled, err := json.MarshalIndent(p, "", "\t") 172 | if err != nil { 173 | return "" 174 | } 175 | 176 | return string(marshalled) 177 | } 178 | -------------------------------------------------------------------------------- /openapi/response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "net/http" 14 | ) 15 | 16 | // APIResponse stores the API response returned by the server. 17 | // 18 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.APIResponse 19 | type APIResponse struct { 20 | *http.Response `json:"-"` 21 | Message string `json:"message,omitempty"` 22 | // Operation is the name of the OpenAPI operation. 23 | Operation string `json:"operation,omitempty"` 24 | // RequestURL is the request URL. This value is always available, even if the 25 | // embedded *http.Response is nil. 26 | RequestURL string `json:"url,omitempty"` 27 | // Method is the HTTP method used for the request. This value is always 28 | // available, even if the embedded *http.Response is nil. 29 | Method string `json:"method,omitempty"` 30 | // Payload holds the contents of the response body (which may be nil or empty). 31 | // This is provided here as the raw response.Body() reader will have already 32 | // been drained. 33 | Payload []byte `json:"-"` 34 | } 35 | 36 | // NewAPIResponse returns a new APIResonse object. 37 | // 38 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewAPIResponse 39 | func NewAPIResponse(r *http.Response) *APIResponse { 40 | 41 | response := &APIResponse{Response: r} 42 | return response 43 | } 44 | 45 | // NewAPIResponseWithError returns a new APIResponse object with the provided error message. 46 | // 47 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewAPIResponseWithError 48 | func NewAPIResponseWithError(errorMessage string) *APIResponse { 49 | 50 | response := &APIResponse{Message: errorMessage} 51 | return response 52 | } 53 | -------------------------------------------------------------------------------- /openapi/model_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | "fmt" 15 | ) 16 | 17 | // Status Status a pin object can have at a pinning service 18 | // 19 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.Status 20 | type Status string 21 | 22 | // List of Status 23 | const ( 24 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.QUEUED 25 | QUEUED Status = "queued" 26 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PINNING 27 | PINNING Status = "pinning" 28 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PINNED 29 | PINNED Status = "pinned" 30 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.FAILED 31 | FAILED Status = "failed" 32 | ) 33 | 34 | func (v *Status) UnmarshalJSON(src []byte) error { 35 | var value string 36 | err := json.Unmarshal(src, &value) 37 | if err != nil { 38 | return err 39 | } 40 | enumTypeValue := Status(value) 41 | for _, existing := range []Status{"queued", "pinning", "pinned", "failed"} { 42 | if existing == enumTypeValue { 43 | *v = enumTypeValue 44 | return nil 45 | } 46 | } 47 | 48 | return fmt.Errorf("%+v is not a valid Status", value) 49 | } 50 | 51 | // Ptr returns reference to Status value 52 | func (v Status) Ptr() *Status { 53 | return &v 54 | } 55 | 56 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableStatus 57 | type NullableStatus struct { 58 | value *Status 59 | isSet bool 60 | } 61 | 62 | func (v NullableStatus) Get() *Status { 63 | return v.value 64 | } 65 | 66 | func (v *NullableStatus) Set(val *Status) { 67 | v.value = val 68 | v.isSet = true 69 | } 70 | 71 | func (v NullableStatus) IsSet() bool { 72 | return v.isSet 73 | } 74 | 75 | func (v *NullableStatus) Unset() { 76 | v.value = nil 77 | v.isSet = false 78 | } 79 | 80 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableStatus 81 | func NewNullableStatus(val *Status) *NullableStatus { 82 | return &NullableStatus{value: val, isSet: true} 83 | } 84 | 85 | func (v NullableStatus) MarshalJSON() ([]byte, error) { 86 | return json.Marshal(v.value) 87 | } 88 | 89 | func (v *NullableStatus) UnmarshalJSON(src []byte) error { 90 | v.isSet = true 91 | return json.Unmarshal(src, &v.value) 92 | } 93 | -------------------------------------------------------------------------------- /openapi/model_failure.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | ) 15 | 16 | // Failure Response for a failed request 17 | // 18 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.Failure 19 | type Failure struct { 20 | Error FailureError `json:"error"` 21 | } 22 | 23 | // NewFailure instantiates a new Failure object 24 | // This constructor will assign default values to properties that have it defined, 25 | // and makes sure properties required by API are set, but the set of arguments 26 | // will change when the set of required properties is changed 27 | // 28 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewFailure 29 | func NewFailure(error_ FailureError) *Failure { 30 | this := Failure{} 31 | this.Error = error_ 32 | return &this 33 | } 34 | 35 | // NewFailureWithDefaults instantiates a new Failure object 36 | // This constructor will only assign default values to properties that have it defined, 37 | // but it doesn't guarantee that properties required by API are set 38 | // 39 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewFailureWithDefaults 40 | func NewFailureWithDefaults() *Failure { 41 | this := Failure{} 42 | return &this 43 | } 44 | 45 | // GetError returns the Error field value 46 | func (o *Failure) GetError() FailureError { 47 | if o == nil { 48 | var ret FailureError 49 | return ret 50 | } 51 | 52 | return o.Error 53 | } 54 | 55 | // GetErrorOk returns a tuple with the Error field value 56 | // and a boolean to check if the value has been set. 57 | func (o *Failure) GetErrorOk() (*FailureError, bool) { 58 | if o == nil { 59 | return nil, false 60 | } 61 | return &o.Error, true 62 | } 63 | 64 | // SetError sets field value 65 | func (o *Failure) SetError(v FailureError) { 66 | o.Error = v 67 | } 68 | 69 | func (o Failure) MarshalJSON() ([]byte, error) { 70 | toSerialize := map[string]interface{}{} 71 | if true { 72 | toSerialize["error"] = o.Error 73 | } 74 | return json.Marshal(toSerialize) 75 | } 76 | 77 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableFailure 78 | type NullableFailure struct { 79 | value *Failure 80 | isSet bool 81 | } 82 | 83 | func (v NullableFailure) Get() *Failure { 84 | return v.value 85 | } 86 | 87 | func (v *NullableFailure) Set(val *Failure) { 88 | v.value = val 89 | v.isSet = true 90 | } 91 | 92 | func (v NullableFailure) IsSet() bool { 93 | return v.isSet 94 | } 95 | 96 | func (v *NullableFailure) Unset() { 97 | v.value = nil 98 | v.isSet = false 99 | } 100 | 101 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableFailure 102 | func NewNullableFailure(val *Failure) *NullableFailure { 103 | return &NullableFailure{value: val, isSet: true} 104 | } 105 | 106 | func (v NullableFailure) MarshalJSON() ([]byte, error) { 107 | return json.Marshal(v.value) 108 | } 109 | 110 | func (v *NullableFailure) UnmarshalJSON(src []byte) error { 111 | v.isSet = true 112 | return json.Unmarshal(src, &v.value) 113 | } 114 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 8 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 9 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 10 | github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= 11 | github.com/ipfs/go-cid v0.1.0 h1:YN33LQulcRHjfom/i25yoOZR4Telp1Hr/2RU3d0PnC0= 12 | github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= 13 | github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= 14 | github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= 15 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 16 | github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw= 17 | github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 18 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 19 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 20 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 21 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= 22 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= 23 | github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 24 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 25 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 26 | github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= 27 | github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 28 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 29 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 30 | github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= 31 | github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= 32 | github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= 33 | github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= 34 | github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM= 35 | github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= 36 | github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= 37 | github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= 38 | github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 39 | github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 40 | github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= 41 | github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= 42 | github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 43 | github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= 44 | github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 45 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 46 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 47 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 48 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 49 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 50 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 51 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 52 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 53 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 54 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 55 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 56 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 57 | go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= 58 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 59 | go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= 60 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 61 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= 62 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 63 | go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= 64 | go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 65 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 67 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 68 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 69 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= 70 | golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 71 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= 72 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 73 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 74 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 75 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 76 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 77 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 78 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 79 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= 80 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 81 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 82 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 83 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 84 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 85 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 86 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 87 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 88 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 89 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= 91 | golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 93 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 94 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 95 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 96 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 97 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 98 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 99 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 100 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= 101 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 102 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 103 | google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= 104 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 105 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 106 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 107 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 108 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 109 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 110 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 111 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= 112 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 113 | -------------------------------------------------------------------------------- /openapi/model_pin_results.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | ) 15 | 16 | // PinResults Response used for listing pin objects matching request 17 | // 18 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PinResults 19 | type PinResults struct { 20 | // The total number of pin objects that exist for passed query filters 21 | Count int32 `json:"count"` 22 | // An array of PinStatus results 23 | Results []PinStatus `json:"results"` 24 | } 25 | 26 | // NewPinResults instantiates a new PinResults object 27 | // This constructor will assign default values to properties that have it defined, 28 | // and makes sure properties required by API are set, but the set of arguments 29 | // will change when the set of required properties is changed 30 | // 31 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPinResults 32 | func NewPinResults(count int32, results []PinStatus) *PinResults { 33 | this := PinResults{} 34 | this.Count = count 35 | this.Results = results 36 | return &this 37 | } 38 | 39 | // NewPinResultsWithDefaults instantiates a new PinResults object 40 | // This constructor will only assign default values to properties that have it defined, 41 | // but it doesn't guarantee that properties required by API are set 42 | // 43 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPinResultsWithDefaults 44 | func NewPinResultsWithDefaults() *PinResults { 45 | this := PinResults{} 46 | return &this 47 | } 48 | 49 | // GetCount returns the Count field value 50 | func (o *PinResults) GetCount() int32 { 51 | if o == nil { 52 | var ret int32 53 | return ret 54 | } 55 | 56 | return o.Count 57 | } 58 | 59 | // GetCountOk returns a tuple with the Count field value 60 | // and a boolean to check if the value has been set. 61 | func (o *PinResults) GetCountOk() (*int32, bool) { 62 | if o == nil { 63 | return nil, false 64 | } 65 | return &o.Count, true 66 | } 67 | 68 | // SetCount sets field value 69 | func (o *PinResults) SetCount(v int32) { 70 | o.Count = v 71 | } 72 | 73 | // GetResults returns the Results field value 74 | func (o *PinResults) GetResults() []PinStatus { 75 | if o == nil { 76 | var ret []PinStatus 77 | return ret 78 | } 79 | 80 | return o.Results 81 | } 82 | 83 | // GetResultsOk returns a tuple with the Results field value 84 | // and a boolean to check if the value has been set. 85 | func (o *PinResults) GetResultsOk() (*[]PinStatus, bool) { 86 | if o == nil { 87 | return nil, false 88 | } 89 | return &o.Results, true 90 | } 91 | 92 | // SetResults sets field value 93 | func (o *PinResults) SetResults(v []PinStatus) { 94 | o.Results = v 95 | } 96 | 97 | func (o PinResults) MarshalJSON() ([]byte, error) { 98 | toSerialize := map[string]interface{}{} 99 | if true { 100 | toSerialize["count"] = o.Count 101 | } 102 | if true { 103 | toSerialize["results"] = o.Results 104 | } 105 | return json.Marshal(toSerialize) 106 | } 107 | 108 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullablePinResults 109 | type NullablePinResults struct { 110 | value *PinResults 111 | isSet bool 112 | } 113 | 114 | func (v NullablePinResults) Get() *PinResults { 115 | return v.value 116 | } 117 | 118 | func (v *NullablePinResults) Set(val *PinResults) { 119 | v.value = val 120 | v.isSet = true 121 | } 122 | 123 | func (v NullablePinResults) IsSet() bool { 124 | return v.isSet 125 | } 126 | 127 | func (v *NullablePinResults) Unset() { 128 | v.value = nil 129 | v.isSet = false 130 | } 131 | 132 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullablePinResults 133 | func NewNullablePinResults(val *PinResults) *NullablePinResults { 134 | return &NullablePinResults{value: val, isSet: true} 135 | } 136 | 137 | func (v NullablePinResults) MarshalJSON() ([]byte, error) { 138 | return json.Marshal(v.value) 139 | } 140 | 141 | func (v *NullablePinResults) UnmarshalJSON(src []byte) error { 142 | v.isSet = true 143 | return json.Unmarshal(src, &v.value) 144 | } 145 | -------------------------------------------------------------------------------- /openapi/model_failure_error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | ) 15 | 16 | // FailureError struct for FailureError 17 | // 18 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.FailureError 19 | type FailureError struct { 20 | // Mandatory string identifying the type of error 21 | Reason string `json:"reason"` 22 | // Optional, longer description of the error; may include UUID of transaction for support, links to documentation etc 23 | Details *string `json:"details,omitempty"` 24 | } 25 | 26 | // NewFailureError instantiates a new FailureError object 27 | // This constructor will assign default values to properties that have it defined, 28 | // and makes sure properties required by API are set, but the set of arguments 29 | // will change when the set of required properties is changed 30 | // 31 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewFailureError 32 | func NewFailureError(reason string) *FailureError { 33 | this := FailureError{} 34 | this.Reason = reason 35 | return &this 36 | } 37 | 38 | // NewFailureErrorWithDefaults instantiates a new FailureError object 39 | // This constructor will only assign default values to properties that have it defined, 40 | // but it doesn't guarantee that properties required by API are set 41 | // 42 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewFailureErrorWithDefaults 43 | func NewFailureErrorWithDefaults() *FailureError { 44 | this := FailureError{} 45 | return &this 46 | } 47 | 48 | // GetReason returns the Reason field value 49 | func (o *FailureError) GetReason() string { 50 | if o == nil { 51 | var ret string 52 | return ret 53 | } 54 | 55 | return o.Reason 56 | } 57 | 58 | // GetReasonOk returns a tuple with the Reason field value 59 | // and a boolean to check if the value has been set. 60 | func (o *FailureError) GetReasonOk() (*string, bool) { 61 | if o == nil { 62 | return nil, false 63 | } 64 | return &o.Reason, true 65 | } 66 | 67 | // SetReason sets field value 68 | func (o *FailureError) SetReason(v string) { 69 | o.Reason = v 70 | } 71 | 72 | // GetDetails returns the Details field value if set, zero value otherwise. 73 | func (o *FailureError) GetDetails() string { 74 | if o == nil || o.Details == nil { 75 | var ret string 76 | return ret 77 | } 78 | return *o.Details 79 | } 80 | 81 | // GetDetailsOk returns a tuple with the Details field value if set, nil otherwise 82 | // and a boolean to check if the value has been set. 83 | func (o *FailureError) GetDetailsOk() (*string, bool) { 84 | if o == nil || o.Details == nil { 85 | return nil, false 86 | } 87 | return o.Details, true 88 | } 89 | 90 | // HasDetails returns a boolean if a field has been set. 91 | func (o *FailureError) HasDetails() bool { 92 | if o != nil && o.Details != nil { 93 | return true 94 | } 95 | 96 | return false 97 | } 98 | 99 | // SetDetails gets a reference to the given string and assigns it to the Details field. 100 | func (o *FailureError) SetDetails(v string) { 101 | o.Details = &v 102 | } 103 | 104 | func (o FailureError) MarshalJSON() ([]byte, error) { 105 | toSerialize := map[string]interface{}{} 106 | if true { 107 | toSerialize["reason"] = o.Reason 108 | } 109 | if o.Details != nil { 110 | toSerialize["details"] = o.Details 111 | } 112 | return json.Marshal(toSerialize) 113 | } 114 | 115 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableFailureError 116 | type NullableFailureError struct { 117 | value *FailureError 118 | isSet bool 119 | } 120 | 121 | func (v NullableFailureError) Get() *FailureError { 122 | return v.value 123 | } 124 | 125 | func (v *NullableFailureError) Set(val *FailureError) { 126 | v.value = val 127 | v.isSet = true 128 | } 129 | 130 | func (v NullableFailureError) IsSet() bool { 131 | return v.isSet 132 | } 133 | 134 | func (v *NullableFailureError) Unset() { 135 | v.value = nil 136 | v.isSet = false 137 | } 138 | 139 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableFailureError 140 | func NewNullableFailureError(val *FailureError) *NullableFailureError { 141 | return &NullableFailureError{value: val, isSet: true} 142 | } 143 | 144 | func (v NullableFailureError) MarshalJSON() ([]byte, error) { 145 | return json.Marshal(v.value) 146 | } 147 | 148 | func (v *NullableFailureError) UnmarshalJSON(src []byte) error { 149 | v.isSet = true 150 | return json.Unmarshal(src, &v.value) 151 | } 152 | -------------------------------------------------------------------------------- /openapi/README.md: -------------------------------------------------------------------------------- 1 | # Go API client for openapi 2 | 3 | 4 | 5 | ## About this spec 6 | The IPFS Pinning Service API is intended to be an implementation-agnostic API: 7 | - For use and implementation by pinning service providers 8 | - For use in client mode by IPFS nodes and GUI-based applications 9 | 10 | > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** 11 | 12 | # Schemas 13 | This section describes the most important object types and conventions. 14 | 15 | A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). 16 | 17 | ## Identifiers 18 | ### cid 19 | [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. 20 | ### requestid 21 | Unique identifier of a pin request. 22 | 23 | When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. 24 | 25 | Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. 26 | 27 | ## Objects 28 | ### Pin object 29 | 30 | ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) 31 | 32 | The `Pin` object is a representation of a pin request. 33 | 34 | It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. 35 | 36 | ### Pin status response 37 | 38 | ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) 39 | 40 | The `PinStatus` object is a representation of the current state of a pinning operation. 41 | It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. 42 | 43 | ## The pin lifecycle 44 | 45 | ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) 46 | 47 | ### Creating a new pin object 48 | The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: 49 | - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future 50 | - `status` in `PinStatus` indicates the current state of a pin 51 | 52 | ### Checking status of in-progress pinning 53 | `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. 54 | 55 | In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. 56 | 57 | ### Replacing an existing pin object 58 | The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. 59 | 60 | ### Removing a pin object 61 | A pin object can be removed via `DELETE /pins/{requestid}`. 62 | 63 | 64 | ## Provider hints 65 | Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. 66 | 67 | The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. 68 | 69 | This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. 70 | 71 | ## Custom metadata 72 | Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. 73 | ### Pin metadata 74 | String keys and values passed in `Pin.meta` are persisted with the pin object. 75 | 76 | Potential uses: 77 | - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` 78 | - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) 79 | 80 | Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. 81 | 82 | ### Pin status info 83 | Additional `PinStatus.info` can be returned by pinning service. 84 | 85 | Potential uses: 86 | - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) 87 | - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead 88 | - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) 89 | - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire 90 | 91 | # Pagination and filtering 92 | Pin objects can be listed by executing `GET /pins` with optional parameters: 93 | 94 | - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. 95 | - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). 96 | - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. 97 | - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. 98 | - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. 99 | 100 | > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 101 | 102 | 103 | 104 | ## Overview 105 | This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI-spec](https://www.openapis.org/) from a remote server, you can easily generate an API client. 106 | 107 | - API version: 0.1.1 108 | - Package version: 1.0.0 109 | - Build package: org.openapitools.codegen.languages.GoClientExperimentalCodegen 110 | 111 | ## Installation 112 | 113 | Install the following dependencies: 114 | 115 | ```shell 116 | go get github.com/stretchr/testify/assert 117 | go get golang.org/x/oauth2 118 | go get golang.org/x/net/context 119 | ``` 120 | 121 | Put the package under your project folder and add the following in import: 122 | 123 | ```golang 124 | import sw "./openapi" 125 | ``` 126 | 127 | ## Configuration of Server URL 128 | 129 | Default configuration comes with `Servers` field that contains server objects as defined in the OpenAPI specification. 130 | 131 | ### Select Server Configuration 132 | 133 | For using other server than the one defined on index 0 set context value `sw.ContextServerIndex` of type `int`. 134 | 135 | ```golang 136 | ctx := context.WithValue(context.Background(), sw.ContextServerIndex, 1) 137 | ``` 138 | 139 | ### Templated Server URL 140 | 141 | Templated server URL is formatted using default variables from configuration or from context value `sw.ContextServerVariables` of type `map[string]string`. 142 | 143 | ```golang 144 | ctx := context.WithValue(context.Background(), sw.ContextServerVariables, map[string]string{ 145 | "basePath": "v2", 146 | }) 147 | ``` 148 | 149 | Note, enum values are always validated and all unused variables are silently ignored. 150 | 151 | ### URLs Configuration per Operation 152 | 153 | Each operation can use different server URL defined using `OperationServers` map in the `Configuration`. 154 | An operation is uniquely identifield by `"{classname}Service.{nickname}"` string. 155 | Similar rules for overriding default operation server index and variables applies by using `sw.ContextOperationServerIndices` and `sw.ContextOperationServerVariables` context maps. 156 | 157 | ``` 158 | ctx := context.WithValue(context.Background(), sw.ContextOperationServerIndices, map[string]int{ 159 | "{classname}Service.{nickname}": 2, 160 | }) 161 | ctx = context.WithValue(context.Background(), sw.ContextOperationServerVariables, map[string]map[string]string{ 162 | "{classname}Service.{nickname}": { 163 | "port": "8443", 164 | }, 165 | }) 166 | ``` 167 | 168 | ## Documentation for API Endpoints 169 | 170 | All URIs are relative to *https://pinning-service.example.com* 171 | 172 | Class | Method | HTTP request | Description 173 | ------------ | ------------- | ------------- | ------------- 174 | *PinsApi* | [**PinsGet**](docs/PinsApi.md#pinsget) | **Get** /pins | List pin objects 175 | *PinsApi* | [**PinsPost**](docs/PinsApi.md#pinspost) | **Post** /pins | Add pin object 176 | *PinsApi* | [**PinsRequestidDelete**](docs/PinsApi.md#pinsrequestiddelete) | **Delete** /pins/{requestid} | Remove pin object 177 | *PinsApi* | [**PinsRequestidGet**](docs/PinsApi.md#pinsrequestidget) | **Get** /pins/{requestid} | Get pin object 178 | *PinsApi* | [**PinsRequestidPost**](docs/PinsApi.md#pinsrequestidpost) | **Post** /pins/{requestid} | Replace pin object 179 | 180 | 181 | ## Documentation For Models 182 | 183 | - [Failure](docs/Failure.md) 184 | - [FailureError](docs/FailureError.md) 185 | - [Pin](docs/Pin.md) 186 | - [PinResults](docs/PinResults.md) 187 | - [PinStatus](docs/PinStatus.md) 188 | - [Status](docs/Status.md) 189 | 190 | 191 | ## Documentation For Authorization 192 | 193 | 194 | 195 | ### accessToken 196 | 197 | 198 | ## Documentation for Utility Methods 199 | 200 | Due to the fact that model structure members are all pointers, this package contains 201 | a number of utility functions to easily obtain pointers to values of basic types. 202 | Each of these functions takes a value of the given basic type and returns a pointer to it: 203 | 204 | * `PtrBool` 205 | * `PtrInt` 206 | * `PtrInt32` 207 | * `PtrInt64` 208 | * `PtrFloat` 209 | * `PtrFloat32` 210 | * `PtrFloat64` 211 | * `PtrString` 212 | * `PtrTime` 213 | 214 | ## Author 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package go_pinning_service_http_client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/pkg/errors" 10 | 11 | "github.com/ipfs/go-cid" 12 | "github.com/ipfs/go-pinning-service-http-client/openapi" 13 | "github.com/multiformats/go-multiaddr" 14 | "github.com/multiformats/go-multibase" 15 | 16 | logging "github.com/ipfs/go-log/v2" 17 | ) 18 | 19 | var logger = logging.Logger("pinning-service-http-client") 20 | 21 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.UserAgent 22 | const UserAgent = "go-pinning-service-http-client" 23 | 24 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.Client 25 | type Client struct { 26 | client *openapi.APIClient 27 | } 28 | 29 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.NewClient 30 | func NewClient(url, bearerToken string) *Client { 31 | config := openapi.NewConfiguration() 32 | config.UserAgent = UserAgent 33 | config.AddDefaultHeader("Authorization", "Bearer "+bearerToken) 34 | config.Servers = openapi.ServerConfigurations{ 35 | openapi.ServerConfiguration{ 36 | URL: url, 37 | }, 38 | } 39 | 40 | return &Client{client: openapi.NewAPIClient(config)} 41 | } 42 | 43 | // TODO: We should probably make sure there are no duplicates sent 44 | type lsSettings struct { 45 | cids []string 46 | name string 47 | status []Status 48 | before *time.Time 49 | after *time.Time 50 | limit *int32 51 | meta map[string]string 52 | } 53 | 54 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.LsOption 55 | type LsOption func(options *lsSettings) error 56 | 57 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.PinOpts 58 | var PinOpts = pinOpts{} 59 | 60 | type pinOpts struct { 61 | pinLsOpts 62 | pinAddOpts 63 | } 64 | 65 | type pinLsOpts struct{} 66 | 67 | func (pinLsOpts) FilterCIDs(cids ...cid.Cid) LsOption { 68 | return func(options *lsSettings) error { 69 | enc := getCIDEncoder() 70 | for _, c := range cids { 71 | options.cids = append(options.cids, c.Encode(enc)) 72 | } 73 | return nil 74 | } 75 | } 76 | 77 | const maxNameSize = 255 78 | 79 | func (pinLsOpts) FilterName(name string) LsOption { 80 | return func(options *lsSettings) error { 81 | if len(name) > maxNameSize { 82 | return fmt.Errorf("name cannot be longer than %d", maxNameSize) 83 | } 84 | options.name = name 85 | return nil 86 | } 87 | } 88 | 89 | func (pinLsOpts) FilterStatus(statuses ...Status) LsOption { 90 | return func(options *lsSettings) error { 91 | for _, s := range statuses { 92 | valid := false 93 | for _, existing := range validStatuses { 94 | if existing == s { 95 | valid = true 96 | break 97 | } 98 | } 99 | if !valid { 100 | return fmt.Errorf("invalid status %s", s) 101 | } 102 | } 103 | options.status = append(options.status, statuses...) 104 | return nil 105 | } 106 | } 107 | 108 | func (pinLsOpts) FilterBefore(t time.Time) LsOption { 109 | return func(options *lsSettings) error { 110 | options.before = &t 111 | return nil 112 | } 113 | } 114 | 115 | func (pinLsOpts) FilterAfter(t time.Time) LsOption { 116 | return func(options *lsSettings) error { 117 | options.after = &t 118 | return nil 119 | } 120 | } 121 | 122 | const recordLimit = 1000 123 | const defaultLimit = 10 124 | 125 | func (pinLsOpts) Limit(limit int) LsOption { 126 | return func(options *lsSettings) error { 127 | if limit > recordLimit { 128 | return fmt.Errorf("limit exceeded maximum record limit of %d", recordLimit) 129 | } 130 | limitCasted := int32(limit) 131 | options.limit = &limitCasted 132 | return nil 133 | } 134 | } 135 | 136 | func (pinLsOpts) LsMeta(meta map[string]string) LsOption { 137 | return func(options *lsSettings) error { 138 | options.meta = meta 139 | return nil 140 | } 141 | } 142 | 143 | type pinResults = openapi.PinResults 144 | 145 | func (c *Client) Ls(ctx context.Context, opts ...LsOption) (chan PinStatusGetter, chan error) { 146 | res := make(chan PinStatusGetter, 1) 147 | errs := make(chan error, 1) 148 | 149 | settings := new(lsSettings) 150 | for _, o := range opts { 151 | if err := o(settings); err != nil { 152 | close(res) 153 | errs <- err 154 | close(errs) 155 | return res, errs 156 | } 157 | } 158 | 159 | go func() { 160 | defer func() { 161 | if r := recover(); r != nil { 162 | var err error 163 | switch x := r.(type) { 164 | case string: 165 | err = fmt.Errorf("unexpected error while listing remote pins: %s", x) 166 | case error: 167 | err = fmt.Errorf("unexpected error while listing remote pins: %w", x) 168 | default: 169 | err = errors.New("unknown panic while listing remote pins") 170 | } 171 | errs <- err 172 | } 173 | close(errs) 174 | close(res) 175 | }() 176 | 177 | for { 178 | pinRes, err := c.lsInternal(ctx, settings) 179 | if err != nil { 180 | errs <- err 181 | return 182 | } 183 | 184 | results := pinRes.GetResults() 185 | for _, r := range results { 186 | select { 187 | case res <- &pinStatusObject{r}: 188 | case <-ctx.Done(): 189 | errs <- ctx.Err() 190 | return 191 | } 192 | } 193 | 194 | batchSize := len(results) 195 | if int(pinRes.Count) == batchSize { 196 | // no more batches 197 | return 198 | } 199 | 200 | // Better DX/UX for cases like https://github.com/application-research/estuary/issues/124 201 | if batchSize == 0 && int(pinRes.Count) != 0 { 202 | errs <- fmt.Errorf("invalid pinning service response: PinResults.count=%d but no PinResults.results", int(pinRes.Count)) 203 | return 204 | } 205 | 206 | oldestResult := results[batchSize-1] 207 | settings.before = &oldestResult.Created 208 | } 209 | }() 210 | 211 | return res, errs 212 | } 213 | 214 | func (c *Client) LsSync(ctx context.Context, opts ...LsOption) ([]PinStatusGetter, error) { 215 | resCh, errCh := c.Ls(ctx, opts...) 216 | 217 | var res []PinStatusGetter 218 | for r := range resCh { 219 | res = append(res, r) 220 | } 221 | 222 | return res, <-errCh 223 | } 224 | 225 | // Manual version of Ls that returns a single batch of results and int with total count 226 | func (c *Client) LsBatchSync(ctx context.Context, opts ...LsOption) ([]PinStatusGetter, int, error) { 227 | var res []PinStatusGetter 228 | 229 | settings := new(lsSettings) 230 | for _, o := range opts { 231 | if err := o(settings); err != nil { 232 | return nil, 0, err 233 | } 234 | } 235 | 236 | pinRes, err := c.lsInternal(ctx, settings) 237 | if err != nil { 238 | return nil, 0, err 239 | } 240 | 241 | results := pinRes.GetResults() 242 | for _, r := range results { 243 | res = append(res, &pinStatusObject{r}) 244 | } 245 | 246 | return res, int(pinRes.Count), nil 247 | } 248 | 249 | func (c *Client) lsInternal(ctx context.Context, settings *lsSettings) (pinResults, error) { 250 | getter := c.client.PinsApi.PinsGet(ctx) 251 | if len(settings.cids) > 0 { 252 | getter = getter.Cid(settings.cids) 253 | } 254 | if len(settings.status) > 0 { 255 | statuses := make([]openapi.Status, len(settings.status)) 256 | for i := 0; i < len(statuses); i++ { 257 | statuses[i] = openapi.Status(settings.status[i]) 258 | } 259 | getter = getter.Status(statuses) 260 | } 261 | if settings.limit == nil { 262 | getter = getter.Limit(defaultLimit) 263 | } else { 264 | getter = getter.Limit(*settings.limit) 265 | } 266 | if len(settings.name) > 0 { 267 | getter = getter.Name(settings.name) 268 | } 269 | if settings.before != nil { 270 | getter = getter.Before(*settings.before) 271 | } 272 | if settings.after != nil { 273 | getter = getter.After(*settings.after) 274 | } 275 | if settings.meta != nil { 276 | getter = getter.Meta(settings.meta) 277 | } 278 | 279 | // TODO: Ignoring HTTP Response OK? 280 | results, httpresp, err := getter.Execute() 281 | if err != nil { 282 | err := httperr(httpresp, err) 283 | return pinResults{}, err 284 | } 285 | 286 | return results, nil 287 | } 288 | 289 | // TODO: We should probably make sure there are no duplicates sent 290 | type addSettings struct { 291 | name string 292 | origins []string 293 | meta map[string]string 294 | } 295 | 296 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client.AddOption 297 | type AddOption func(options *addSettings) error 298 | 299 | type pinAddOpts struct{} 300 | 301 | func (pinAddOpts) WithName(name string) AddOption { 302 | return func(options *addSettings) error { 303 | if len(name) > maxNameSize { 304 | return fmt.Errorf("name cannot be longer than %d", maxNameSize) 305 | } 306 | options.name = name 307 | return nil 308 | } 309 | } 310 | 311 | func (pinAddOpts) WithOrigins(origins ...multiaddr.Multiaddr) AddOption { 312 | return func(options *addSettings) error { 313 | for _, o := range origins { 314 | options.origins = append(options.origins, o.String()) 315 | } 316 | return nil 317 | } 318 | } 319 | 320 | func (pinAddOpts) AddMeta(meta map[string]string) AddOption { 321 | return func(options *addSettings) error { 322 | options.meta = meta 323 | return nil 324 | } 325 | } 326 | 327 | func (c *Client) Add(ctx context.Context, cid cid.Cid, opts ...AddOption) (PinStatusGetter, error) { 328 | settings := new(addSettings) 329 | for _, o := range opts { 330 | if err := o(settings); err != nil { 331 | return nil, err 332 | } 333 | } 334 | 335 | adder := c.client.PinsApi.PinsPost(ctx) 336 | p := openapi.Pin{ 337 | Cid: cid.Encode(getCIDEncoder()), 338 | } 339 | 340 | if len(settings.origins) > 0 { 341 | p.SetOrigins(settings.origins) 342 | } 343 | if settings.meta != nil { 344 | p.SetMeta(settings.meta) 345 | } 346 | if len(settings.name) > 0 { 347 | p.SetName(settings.name) 348 | } 349 | 350 | result, httpresp, err := adder.Pin(p).Execute() 351 | if err != nil { 352 | err := httperr(httpresp, err) 353 | return nil, err 354 | } 355 | 356 | return &pinStatusObject{result}, nil 357 | } 358 | 359 | func (c *Client) GetStatusByID(ctx context.Context, pinID string) (PinStatusGetter, error) { 360 | getter := c.client.PinsApi.PinsRequestidGet(ctx, pinID) 361 | result, httpresp, err := getter.Execute() 362 | if err != nil { 363 | err := httperr(httpresp, err) 364 | return nil, err 365 | } 366 | 367 | return &pinStatusObject{result}, nil 368 | } 369 | 370 | func (c *Client) DeleteByID(ctx context.Context, pinID string) error { 371 | deleter := c.client.PinsApi.PinsRequestidDelete(ctx, pinID) 372 | httpresp, err := deleter.Execute() 373 | if err != nil { 374 | err := httperr(httpresp, err) 375 | return err 376 | } 377 | return nil 378 | } 379 | 380 | func (c *Client) Replace(ctx context.Context, pinID string, cid cid.Cid, opts ...AddOption) (PinStatusGetter, error) { 381 | settings := new(addSettings) 382 | for _, o := range opts { 383 | if err := o(settings); err != nil { 384 | return nil, err 385 | } 386 | } 387 | 388 | adder := c.client.PinsApi.PinsRequestidPost(ctx, pinID) 389 | p := openapi.Pin{ 390 | Cid: cid.Encode(getCIDEncoder()), 391 | } 392 | 393 | if len(settings.origins) > 0 { 394 | p.SetOrigins(settings.origins) 395 | } 396 | if settings.meta != nil { 397 | p.SetMeta(settings.meta) 398 | } 399 | if len(settings.name) > 0 { 400 | p.SetName(settings.name) 401 | } 402 | 403 | result, httpresp, err := adder.Pin(p).Execute() 404 | if err != nil { 405 | err := httperr(httpresp, err) 406 | return nil, err 407 | } 408 | 409 | return &pinStatusObject{result}, nil 410 | } 411 | 412 | func getCIDEncoder() multibase.Encoder { 413 | enc, err := multibase.NewEncoder(multibase.Base32) 414 | if err != nil { 415 | panic(err) 416 | } 417 | return enc 418 | } 419 | 420 | func httperr(resp *http.Response, e error) error { 421 | oerr, ok := e.(openapi.GenericOpenAPIError) 422 | if ok { 423 | ferr, ok := oerr.Model().(openapi.Failure) 424 | if ok { 425 | return errors.Wrapf(e, "reason: %q, details: %q", ferr.Error.GetReason(), ferr.Error.GetDetails()) 426 | } 427 | } 428 | 429 | if resp == nil { 430 | return errors.Wrapf(e, "empty response from remote pinning service") 431 | } 432 | 433 | return errors.Wrapf(e, "remote pinning service returned http error %d", resp.StatusCode) 434 | } 435 | -------------------------------------------------------------------------------- /openapi/docs/PinsApi.md: -------------------------------------------------------------------------------- 1 | # \PinsApi 2 | 3 | All URIs are relative to *https://pinning-service.example.com* 4 | 5 | Method | HTTP request | Description 6 | ------------- | ------------- | ------------- 7 | [**PinsGet**](PinsApi.md#PinsGet) | **Get** /pins | List pin objects 8 | [**PinsPost**](PinsApi.md#PinsPost) | **Post** /pins | Add pin object 9 | [**PinsRequestidDelete**](PinsApi.md#PinsRequestidDelete) | **Delete** /pins/{requestid} | Remove pin object 10 | [**PinsRequestidGet**](PinsApi.md#PinsRequestidGet) | **Get** /pins/{requestid} | Get pin object 11 | [**PinsRequestidPost**](PinsApi.md#PinsRequestidPost) | **Post** /pins/{requestid} | Replace pin object 12 | 13 | 14 | 15 | ## PinsGet 16 | 17 | > PinResults PinsGet(ctx).Cid(cid).Name(name).Status(status).Before(before).After(after).Limit(limit).Meta(meta).Execute() 18 | 19 | List pin objects 20 | 21 | 22 | 23 | ### Example 24 | 25 | ```go 26 | package main 27 | 28 | import ( 29 | "context" 30 | "fmt" 31 | "os" 32 | openapiclient "./openapi" 33 | ) 34 | 35 | func main() { 36 | cid := []string{"Inner_example"} // []string | Return pin objects responsible for pinning the specified CID(s); be aware that using longer hash functions introduces further constraints on the number of CIDs that will fit under the limit of 2000 characters per URL in browser contexts (optional) 37 | name := "name_example" // string | Return pin objects with names that contain provided value (case-insensitive, partial or full match) (optional) 38 | status := []Status{openapiclient.Status{}} // []Status | Return pin objects for pins with the specified status (optional) 39 | before := Get-Date // time.Time | Return results created (queued) before provided timestamp (optional) 40 | after := Get-Date // time.Time | Return results created (queued) after provided timestamp (optional) 41 | limit := 987 // int32 | Max records to return (optional) (default to 10) 42 | meta := map[string]string{ "Key" = "Value" } // map[string]string | Return pin objects that match specified metadata (optional) 43 | 44 | configuration := openapiclient.NewConfiguration() 45 | api_client := openapiclient.NewAPIClient(configuration) 46 | resp, r, err := api_client.PinsApi.PinsGet(context.Background(), ).Cid(cid).Name(name).Status(status).Before(before).After(after).Limit(limit).Meta(meta).Execute() 47 | if err != nil { 48 | fmt.Fprintf(os.Stderr, "Error when calling `PinsApi.PinsGet``: %v\n", err) 49 | fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) 50 | } 51 | // response from `PinsGet`: PinResults 52 | fmt.Fprintf(os.Stdout, "Response from `PinsApi.PinsGet`: %v\n", resp) 53 | } 54 | ``` 55 | 56 | ### Path Parameters 57 | 58 | 59 | 60 | ### Other Parameters 61 | 62 | Other parameters are passed through a pointer to a apiPinsGetRequest struct via the builder pattern 63 | 64 | 65 | Name | Type | Description | Notes 66 | ------------- | ------------- | ------------- | ------------- 67 | **cid** | [**[]string**](string.md) | Return pin objects responsible for pinning the specified CID(s); be aware that using longer hash functions introduces further constraints on the number of CIDs that will fit under the limit of 2000 characters per URL in browser contexts | 68 | **name** | **string** | Return pin objects with names that contain provided value (case-insensitive, partial or full match) | 69 | **status** | [**[]Status**](Status.md) | Return pin objects for pins with the specified status | 70 | **before** | **time.Time** | Return results created (queued) before provided timestamp | 71 | **after** | **time.Time** | Return results created (queued) after provided timestamp | 72 | **limit** | **int32** | Max records to return | [default to 10] 73 | **meta** | [**map[string]string**](string.md) | Return pin objects that match specified metadata | 74 | 75 | ### Return type 76 | 77 | [**PinResults**](PinResults.md) 78 | 79 | ### Authorization 80 | 81 | [accessToken](../README.md#accessToken) 82 | 83 | ### HTTP request headers 84 | 85 | - **Content-Type**: Not defined 86 | - **Accept**: application/json 87 | 88 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) 89 | [[Back to Model list]](../README.md#documentation-for-models) 90 | [[Back to README]](../README.md) 91 | 92 | 93 | ## PinsPost 94 | 95 | > PinStatus PinsPost(ctx).Pin(pin).Execute() 96 | 97 | Add pin object 98 | 99 | 100 | 101 | ### Example 102 | 103 | ```go 104 | package main 105 | 106 | import ( 107 | "context" 108 | "fmt" 109 | "os" 110 | openapiclient "./openapi" 111 | ) 112 | 113 | func main() { 114 | pin := openapiclient.Pin{Cid: "Cid_example", Name: "Name_example", Origins: []string{"Origins_example"), Meta: map[string]string{ "Key" = "Value" }} // Pin | 115 | 116 | configuration := openapiclient.NewConfiguration() 117 | api_client := openapiclient.NewAPIClient(configuration) 118 | resp, r, err := api_client.PinsApi.PinsPost(context.Background(), pin).Execute() 119 | if err != nil { 120 | fmt.Fprintf(os.Stderr, "Error when calling `PinsApi.PinsPost``: %v\n", err) 121 | fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) 122 | } 123 | // response from `PinsPost`: PinStatus 124 | fmt.Fprintf(os.Stdout, "Response from `PinsApi.PinsPost`: %v\n", resp) 125 | } 126 | ``` 127 | 128 | ### Path Parameters 129 | 130 | 131 | 132 | ### Other Parameters 133 | 134 | Other parameters are passed through a pointer to a apiPinsPostRequest struct via the builder pattern 135 | 136 | 137 | Name | Type | Description | Notes 138 | ------------- | ------------- | ------------- | ------------- 139 | **pin** | [**Pin**](Pin.md) | | 140 | 141 | ### Return type 142 | 143 | [**PinStatus**](PinStatus.md) 144 | 145 | ### Authorization 146 | 147 | [accessToken](../README.md#accessToken) 148 | 149 | ### HTTP request headers 150 | 151 | - **Content-Type**: application/json 152 | - **Accept**: application/json 153 | 154 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) 155 | [[Back to Model list]](../README.md#documentation-for-models) 156 | [[Back to README]](../README.md) 157 | 158 | 159 | ## PinsRequestidDelete 160 | 161 | > PinsRequestidDelete(ctx, requestid).Execute() 162 | 163 | Remove pin object 164 | 165 | 166 | 167 | ### Example 168 | 169 | ```go 170 | package main 171 | 172 | import ( 173 | "context" 174 | "fmt" 175 | "os" 176 | openapiclient "./openapi" 177 | ) 178 | 179 | func main() { 180 | requestid := "requestid_example" // string | 181 | 182 | configuration := openapiclient.NewConfiguration() 183 | api_client := openapiclient.NewAPIClient(configuration) 184 | resp, r, err := api_client.PinsApi.PinsRequestidDelete(context.Background(), requestid).Execute() 185 | if err != nil { 186 | fmt.Fprintf(os.Stderr, "Error when calling `PinsApi.PinsRequestidDelete``: %v\n", err) 187 | fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) 188 | } 189 | } 190 | ``` 191 | 192 | ### Path Parameters 193 | 194 | 195 | Name | Type | Description | Notes 196 | ------------- | ------------- | ------------- | ------------- 197 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 198 | **requestid** | **string** | | 199 | 200 | ### Other Parameters 201 | 202 | Other parameters are passed through a pointer to a apiPinsRequestidDeleteRequest struct via the builder pattern 203 | 204 | 205 | Name | Type | Description | Notes 206 | ------------- | ------------- | ------------- | ------------- 207 | 208 | 209 | ### Return type 210 | 211 | (empty response body) 212 | 213 | ### Authorization 214 | 215 | [accessToken](../README.md#accessToken) 216 | 217 | ### HTTP request headers 218 | 219 | - **Content-Type**: Not defined 220 | - **Accept**: application/json 221 | 222 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) 223 | [[Back to Model list]](../README.md#documentation-for-models) 224 | [[Back to README]](../README.md) 225 | 226 | 227 | ## PinsRequestidGet 228 | 229 | > PinStatus PinsRequestidGet(ctx, requestid).Execute() 230 | 231 | Get pin object 232 | 233 | 234 | 235 | ### Example 236 | 237 | ```go 238 | package main 239 | 240 | import ( 241 | "context" 242 | "fmt" 243 | "os" 244 | openapiclient "./openapi" 245 | ) 246 | 247 | func main() { 248 | requestid := "requestid_example" // string | 249 | 250 | configuration := openapiclient.NewConfiguration() 251 | api_client := openapiclient.NewAPIClient(configuration) 252 | resp, r, err := api_client.PinsApi.PinsRequestidGet(context.Background(), requestid).Execute() 253 | if err != nil { 254 | fmt.Fprintf(os.Stderr, "Error when calling `PinsApi.PinsRequestidGet``: %v\n", err) 255 | fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) 256 | } 257 | // response from `PinsRequestidGet`: PinStatus 258 | fmt.Fprintf(os.Stdout, "Response from `PinsApi.PinsRequestidGet`: %v\n", resp) 259 | } 260 | ``` 261 | 262 | ### Path Parameters 263 | 264 | 265 | Name | Type | Description | Notes 266 | ------------- | ------------- | ------------- | ------------- 267 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 268 | **requestid** | **string** | | 269 | 270 | ### Other Parameters 271 | 272 | Other parameters are passed through a pointer to a apiPinsRequestidGetRequest struct via the builder pattern 273 | 274 | 275 | Name | Type | Description | Notes 276 | ------------- | ------------- | ------------- | ------------- 277 | 278 | 279 | ### Return type 280 | 281 | [**PinStatus**](PinStatus.md) 282 | 283 | ### Authorization 284 | 285 | [accessToken](../README.md#accessToken) 286 | 287 | ### HTTP request headers 288 | 289 | - **Content-Type**: Not defined 290 | - **Accept**: application/json 291 | 292 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) 293 | [[Back to Model list]](../README.md#documentation-for-models) 294 | [[Back to README]](../README.md) 295 | 296 | 297 | ## PinsRequestidPost 298 | 299 | > PinStatus PinsRequestidPost(ctx, requestid).Pin(pin).Execute() 300 | 301 | Replace pin object 302 | 303 | 304 | 305 | ### Example 306 | 307 | ```go 308 | package main 309 | 310 | import ( 311 | "context" 312 | "fmt" 313 | "os" 314 | openapiclient "./openapi" 315 | ) 316 | 317 | func main() { 318 | requestid := "requestid_example" // string | 319 | pin := openapiclient.Pin{Cid: "Cid_example", Name: "Name_example", Origins: []string{"Origins_example"), Meta: map[string]string{ "Key" = "Value" }} // Pin | 320 | 321 | configuration := openapiclient.NewConfiguration() 322 | api_client := openapiclient.NewAPIClient(configuration) 323 | resp, r, err := api_client.PinsApi.PinsRequestidPost(context.Background(), requestid, pin).Execute() 324 | if err != nil { 325 | fmt.Fprintf(os.Stderr, "Error when calling `PinsApi.PinsRequestidPost``: %v\n", err) 326 | fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) 327 | } 328 | // response from `PinsRequestidPost`: PinStatus 329 | fmt.Fprintf(os.Stdout, "Response from `PinsApi.PinsRequestidPost`: %v\n", resp) 330 | } 331 | ``` 332 | 333 | ### Path Parameters 334 | 335 | 336 | Name | Type | Description | Notes 337 | ------------- | ------------- | ------------- | ------------- 338 | **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. 339 | **requestid** | **string** | | 340 | 341 | ### Other Parameters 342 | 343 | Other parameters are passed through a pointer to a apiPinsRequestidPostRequest struct via the builder pattern 344 | 345 | 346 | Name | Type | Description | Notes 347 | ------------- | ------------- | ------------- | ------------- 348 | 349 | **pin** | [**Pin**](Pin.md) | | 350 | 351 | ### Return type 352 | 353 | [**PinStatus**](PinStatus.md) 354 | 355 | ### Authorization 356 | 357 | [accessToken](../README.md#accessToken) 358 | 359 | ### HTTP request headers 360 | 361 | - **Content-Type**: application/json 362 | - **Accept**: application/json 363 | 364 | [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) 365 | [[Back to Model list]](../README.md#documentation-for-models) 366 | [[Back to README]](../README.md) 367 | 368 | -------------------------------------------------------------------------------- /openapi/model_pin.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | ) 15 | 16 | // Pin Pin object 17 | // 18 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.Pin 19 | type Pin struct { 20 | // Content Identifier (CID) to be pinned recursively 21 | Cid string `json:"cid"` 22 | // Optional name for pinned data; can be used for lookups later 23 | Name *string `json:"name,omitempty"` 24 | // Optional list of multiaddrs known to provide the data 25 | Origins *[]string `json:"origins,omitempty"` 26 | // Optional metadata for pin object 27 | Meta *map[string]string `json:"meta,omitempty"` 28 | } 29 | 30 | // NewPin instantiates a new Pin object 31 | // This constructor will assign default values to properties that have it defined, 32 | // and makes sure properties required by API are set, but the set of arguments 33 | // will change when the set of required properties is changed 34 | // 35 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPin 36 | func NewPin(cid string) *Pin { 37 | this := Pin{} 38 | this.Cid = cid 39 | return &this 40 | } 41 | 42 | // NewPinWithDefaults instantiates a new Pin object 43 | // This constructor will only assign default values to properties that have it defined, 44 | // but it doesn't guarantee that properties required by API are set 45 | // 46 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPinWithDefaults 47 | func NewPinWithDefaults() *Pin { 48 | this := Pin{} 49 | return &this 50 | } 51 | 52 | // GetCid returns the Cid field value 53 | func (o *Pin) GetCid() string { 54 | if o == nil { 55 | var ret string 56 | return ret 57 | } 58 | 59 | return o.Cid 60 | } 61 | 62 | // GetCidOk returns a tuple with the Cid field value 63 | // and a boolean to check if the value has been set. 64 | func (o *Pin) GetCidOk() (*string, bool) { 65 | if o == nil { 66 | return nil, false 67 | } 68 | return &o.Cid, true 69 | } 70 | 71 | // SetCid sets field value 72 | func (o *Pin) SetCid(v string) { 73 | o.Cid = v 74 | } 75 | 76 | // GetName returns the Name field value if set, zero value otherwise. 77 | func (o *Pin) GetName() string { 78 | if o == nil || o.Name == nil { 79 | var ret string 80 | return ret 81 | } 82 | return *o.Name 83 | } 84 | 85 | // GetNameOk returns a tuple with the Name field value if set, nil otherwise 86 | // and a boolean to check if the value has been set. 87 | func (o *Pin) GetNameOk() (*string, bool) { 88 | if o == nil || o.Name == nil { 89 | return nil, false 90 | } 91 | return o.Name, true 92 | } 93 | 94 | // HasName returns a boolean if a field has been set. 95 | func (o *Pin) HasName() bool { 96 | if o != nil && o.Name != nil { 97 | return true 98 | } 99 | 100 | return false 101 | } 102 | 103 | // SetName gets a reference to the given string and assigns it to the Name field. 104 | func (o *Pin) SetName(v string) { 105 | o.Name = &v 106 | } 107 | 108 | // GetOrigins returns the Origins field value if set, zero value otherwise. 109 | func (o *Pin) GetOrigins() []string { 110 | if o == nil || o.Origins == nil { 111 | var ret []string 112 | return ret 113 | } 114 | return *o.Origins 115 | } 116 | 117 | // GetOriginsOk returns a tuple with the Origins field value if set, nil otherwise 118 | // and a boolean to check if the value has been set. 119 | func (o *Pin) GetOriginsOk() (*[]string, bool) { 120 | if o == nil || o.Origins == nil { 121 | return nil, false 122 | } 123 | return o.Origins, true 124 | } 125 | 126 | // HasOrigins returns a boolean if a field has been set. 127 | func (o *Pin) HasOrigins() bool { 128 | if o != nil && o.Origins != nil { 129 | return true 130 | } 131 | 132 | return false 133 | } 134 | 135 | // SetOrigins gets a reference to the given []string and assigns it to the Origins field. 136 | func (o *Pin) SetOrigins(v []string) { 137 | o.Origins = &v 138 | } 139 | 140 | // GetMeta returns the Meta field value if set, zero value otherwise. 141 | func (o *Pin) GetMeta() map[string]string { 142 | if o == nil || o.Meta == nil { 143 | var ret map[string]string 144 | return ret 145 | } 146 | return *o.Meta 147 | } 148 | 149 | // GetMetaOk returns a tuple with the Meta field value if set, nil otherwise 150 | // and a boolean to check if the value has been set. 151 | func (o *Pin) GetMetaOk() (*map[string]string, bool) { 152 | if o == nil || o.Meta == nil { 153 | return nil, false 154 | } 155 | return o.Meta, true 156 | } 157 | 158 | // HasMeta returns a boolean if a field has been set. 159 | func (o *Pin) HasMeta() bool { 160 | if o != nil && o.Meta != nil { 161 | return true 162 | } 163 | 164 | return false 165 | } 166 | 167 | // SetMeta gets a reference to the given map[string]string and assigns it to the Meta field. 168 | func (o *Pin) SetMeta(v map[string]string) { 169 | o.Meta = &v 170 | } 171 | 172 | func (o Pin) MarshalJSON() ([]byte, error) { 173 | toSerialize := map[string]interface{}{} 174 | if true { 175 | toSerialize["cid"] = o.Cid 176 | } 177 | if o.Name != nil { 178 | toSerialize["name"] = o.Name 179 | } 180 | if o.Origins != nil { 181 | toSerialize["origins"] = o.Origins 182 | } 183 | if o.Meta != nil { 184 | toSerialize["meta"] = o.Meta 185 | } 186 | return json.Marshal(toSerialize) 187 | } 188 | 189 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullablePin 190 | type NullablePin struct { 191 | value *Pin 192 | isSet bool 193 | } 194 | 195 | func (v NullablePin) Get() *Pin { 196 | return v.value 197 | } 198 | 199 | func (v *NullablePin) Set(val *Pin) { 200 | v.value = val 201 | v.isSet = true 202 | } 203 | 204 | func (v NullablePin) IsSet() bool { 205 | return v.isSet 206 | } 207 | 208 | func (v *NullablePin) Unset() { 209 | v.value = nil 210 | v.isSet = false 211 | } 212 | 213 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullablePin 214 | func NewNullablePin(val *Pin) *NullablePin { 215 | return &NullablePin{value: val, isSet: true} 216 | } 217 | 218 | func (v NullablePin) MarshalJSON() ([]byte, error) { 219 | return json.Marshal(v.value) 220 | } 221 | 222 | func (v *NullablePin) UnmarshalJSON(src []byte) error { 223 | v.isSet = true 224 | return json.Unmarshal(src, &v.value) 225 | } 226 | -------------------------------------------------------------------------------- /openapi/model_pin_status.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | "time" 15 | ) 16 | 17 | // PinStatus Pin object with status 18 | // 19 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PinStatus 20 | type PinStatus struct { 21 | // Globally unique identifier of the pin request; can be used to check the status of ongoing pinning, or pin removal 22 | Requestid string `json:"requestid"` 23 | Status Status `json:"status"` 24 | // Immutable timestamp indicating when a pin request entered a pinning service; can be used for filtering results and pagination 25 | Created time.Time `json:"created"` 26 | Pin Pin `json:"pin"` 27 | // List of multiaddrs designated by pinning service for transferring any new data from external peers 28 | Delegates []string `json:"delegates"` 29 | // Optional info for PinStatus response 30 | Info *map[string]string `json:"info,omitempty"` 31 | } 32 | 33 | // NewPinStatus instantiates a new PinStatus object 34 | // This constructor will assign default values to properties that have it defined, 35 | // and makes sure properties required by API are set, but the set of arguments 36 | // will change when the set of required properties is changed 37 | // 38 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPinStatus 39 | func NewPinStatus(requestid string, status Status, created time.Time, pin Pin, delegates []string) *PinStatus { 40 | this := PinStatus{} 41 | this.Requestid = requestid 42 | this.Status = status 43 | this.Created = created 44 | this.Pin = pin 45 | this.Delegates = delegates 46 | return &this 47 | } 48 | 49 | // NewPinStatusWithDefaults instantiates a new PinStatus object 50 | // This constructor will only assign default values to properties that have it defined, 51 | // but it doesn't guarantee that properties required by API are set 52 | // 53 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewPinStatusWithDefaults 54 | func NewPinStatusWithDefaults() *PinStatus { 55 | this := PinStatus{} 56 | return &this 57 | } 58 | 59 | // GetRequestid returns the Requestid field value 60 | func (o *PinStatus) GetRequestid() string { 61 | if o == nil { 62 | var ret string 63 | return ret 64 | } 65 | 66 | return o.Requestid 67 | } 68 | 69 | // GetRequestidOk returns a tuple with the Requestid field value 70 | // and a boolean to check if the value has been set. 71 | func (o *PinStatus) GetRequestidOk() (*string, bool) { 72 | if o == nil { 73 | return nil, false 74 | } 75 | return &o.Requestid, true 76 | } 77 | 78 | // SetRequestid sets field value 79 | func (o *PinStatus) SetRequestid(v string) { 80 | o.Requestid = v 81 | } 82 | 83 | // GetStatus returns the Status field value 84 | func (o *PinStatus) GetStatus() Status { 85 | if o == nil { 86 | var ret Status 87 | return ret 88 | } 89 | 90 | return o.Status 91 | } 92 | 93 | // GetStatusOk returns a tuple with the Status field value 94 | // and a boolean to check if the value has been set. 95 | func (o *PinStatus) GetStatusOk() (*Status, bool) { 96 | if o == nil { 97 | return nil, false 98 | } 99 | return &o.Status, true 100 | } 101 | 102 | // SetStatus sets field value 103 | func (o *PinStatus) SetStatus(v Status) { 104 | o.Status = v 105 | } 106 | 107 | // GetCreated returns the Created field value 108 | func (o *PinStatus) GetCreated() time.Time { 109 | if o == nil { 110 | var ret time.Time 111 | return ret 112 | } 113 | 114 | return o.Created 115 | } 116 | 117 | // GetCreatedOk returns a tuple with the Created field value 118 | // and a boolean to check if the value has been set. 119 | func (o *PinStatus) GetCreatedOk() (*time.Time, bool) { 120 | if o == nil { 121 | return nil, false 122 | } 123 | return &o.Created, true 124 | } 125 | 126 | // SetCreated sets field value 127 | func (o *PinStatus) SetCreated(v time.Time) { 128 | o.Created = v 129 | } 130 | 131 | // GetPin returns the Pin field value 132 | func (o *PinStatus) GetPin() Pin { 133 | if o == nil { 134 | var ret Pin 135 | return ret 136 | } 137 | 138 | return o.Pin 139 | } 140 | 141 | // GetPinOk returns a tuple with the Pin field value 142 | // and a boolean to check if the value has been set. 143 | func (o *PinStatus) GetPinOk() (*Pin, bool) { 144 | if o == nil { 145 | return nil, false 146 | } 147 | return &o.Pin, true 148 | } 149 | 150 | // SetPin sets field value 151 | func (o *PinStatus) SetPin(v Pin) { 152 | o.Pin = v 153 | } 154 | 155 | // GetDelegates returns the Delegates field value 156 | func (o *PinStatus) GetDelegates() []string { 157 | if o == nil { 158 | var ret []string 159 | return ret 160 | } 161 | 162 | return o.Delegates 163 | } 164 | 165 | // GetDelegatesOk returns a tuple with the Delegates field value 166 | // and a boolean to check if the value has been set. 167 | func (o *PinStatus) GetDelegatesOk() (*[]string, bool) { 168 | if o == nil { 169 | return nil, false 170 | } 171 | return &o.Delegates, true 172 | } 173 | 174 | // SetDelegates sets field value 175 | func (o *PinStatus) SetDelegates(v []string) { 176 | o.Delegates = v 177 | } 178 | 179 | // GetInfo returns the Info field value if set, zero value otherwise. 180 | func (o *PinStatus) GetInfo() map[string]string { 181 | if o == nil || o.Info == nil { 182 | var ret map[string]string 183 | return ret 184 | } 185 | return *o.Info 186 | } 187 | 188 | // GetInfoOk returns a tuple with the Info field value if set, nil otherwise 189 | // and a boolean to check if the value has been set. 190 | func (o *PinStatus) GetInfoOk() (*map[string]string, bool) { 191 | if o == nil || o.Info == nil { 192 | return nil, false 193 | } 194 | return o.Info, true 195 | } 196 | 197 | // HasInfo returns a boolean if a field has been set. 198 | func (o *PinStatus) HasInfo() bool { 199 | if o != nil && o.Info != nil { 200 | return true 201 | } 202 | 203 | return false 204 | } 205 | 206 | // SetInfo gets a reference to the given map[string]string and assigns it to the Info field. 207 | func (o *PinStatus) SetInfo(v map[string]string) { 208 | o.Info = &v 209 | } 210 | 211 | func (o PinStatus) MarshalJSON() ([]byte, error) { 212 | toSerialize := map[string]interface{}{} 213 | if true { 214 | toSerialize["requestid"] = o.Requestid 215 | } 216 | if true { 217 | toSerialize["status"] = o.Status 218 | } 219 | if true { 220 | toSerialize["created"] = o.Created 221 | } 222 | if true { 223 | toSerialize["pin"] = o.Pin 224 | } 225 | if true { 226 | toSerialize["delegates"] = o.Delegates 227 | } 228 | if o.Info != nil { 229 | toSerialize["info"] = o.Info 230 | } 231 | return json.Marshal(toSerialize) 232 | } 233 | 234 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullablePinStatus 235 | type NullablePinStatus struct { 236 | value *PinStatus 237 | isSet bool 238 | } 239 | 240 | func (v NullablePinStatus) Get() *PinStatus { 241 | return v.value 242 | } 243 | 244 | func (v *NullablePinStatus) Set(val *PinStatus) { 245 | v.value = val 246 | v.isSet = true 247 | } 248 | 249 | func (v NullablePinStatus) IsSet() bool { 250 | return v.isSet 251 | } 252 | 253 | func (v *NullablePinStatus) Unset() { 254 | v.value = nil 255 | v.isSet = false 256 | } 257 | 258 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullablePinStatus 259 | func NewNullablePinStatus(val *PinStatus) *NullablePinStatus { 260 | return &NullablePinStatus{value: val, isSet: true} 261 | } 262 | 263 | func (v NullablePinStatus) MarshalJSON() ([]byte, error) { 264 | return json.Marshal(v.value) 265 | } 266 | 267 | func (v *NullablePinStatus) UnmarshalJSON(src []byte) error { 268 | v.isSet = true 269 | return json.Unmarshal(src, &v.value) 270 | } 271 | -------------------------------------------------------------------------------- /openapi/configuration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "context" 14 | "fmt" 15 | "net/http" 16 | "strings" 17 | ) 18 | 19 | // contextKeys are used to identify the type of value in the context. 20 | // Since these are string, it is possible to get a short description of the 21 | // context key for logging and debugging using key.String(). 22 | 23 | type contextKey string 24 | 25 | func (c contextKey) String() string { 26 | return "auth " + string(c) 27 | } 28 | 29 | var ( 30 | // ContextOAuth2 takes an oauth2.TokenSource as authentication for the request. 31 | // 32 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextOAuth2 33 | ContextOAuth2 = contextKey("token") 34 | 35 | // ContextBasicAuth takes BasicAuth as authentication for the request. 36 | // 37 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextBasicAuth 38 | ContextBasicAuth = contextKey("basic") 39 | 40 | // ContextAccessToken takes a string oauth2 access token as authentication for the request. 41 | // 42 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextAccessToken 43 | ContextAccessToken = contextKey("accesstoken") 44 | 45 | // ContextAPIKeys takes a string apikey as authentication for the request 46 | // 47 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextAPIKeys 48 | ContextAPIKeys = contextKey("apiKeys") 49 | 50 | // ContextHttpSignatureAuth takes HttpSignatureAuth as authentication for the request. 51 | // 52 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextHttpSignatureAuth 53 | ContextHttpSignatureAuth = contextKey("httpsignature") 54 | 55 | // ContextServerIndex uses a server configuration from the index. 56 | // 57 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextServerIndex 58 | ContextServerIndex = contextKey("serverIndex") 59 | 60 | // ContextOperationServerIndices uses a server configuration from the index mapping. 61 | // 62 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextOperationServerIndices 63 | ContextOperationServerIndices = contextKey("serverOperationIndices") 64 | 65 | // ContextServerVariables overrides a server configuration variables. 66 | // 67 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextServerVariables 68 | ContextServerVariables = contextKey("serverVariables") 69 | 70 | // ContextOperationServerVariables overrides a server configuration variables using operation specific values. 71 | // 72 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ContextOperationServerVariables 73 | ContextOperationServerVariables = contextKey("serverOperationVariables") 74 | ) 75 | 76 | // BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth 77 | // 78 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.BasicAuth 79 | type BasicAuth struct { 80 | UserName string `json:"userName,omitempty"` 81 | Password string `json:"password,omitempty"` 82 | } 83 | 84 | // APIKey provides API key based authentication to a request passed via context using ContextAPIKey 85 | // 86 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.APIKey 87 | type APIKey struct { 88 | Key string 89 | Prefix string 90 | } 91 | 92 | // ServerVariable stores the information about a server variable 93 | // 94 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ServerVariable 95 | type ServerVariable struct { 96 | Description string 97 | DefaultValue string 98 | EnumValues []string 99 | } 100 | 101 | // ServerConfiguration stores the information about a server 102 | // 103 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ServerConfiguration 104 | type ServerConfiguration struct { 105 | URL string 106 | Description string 107 | Variables map[string]ServerVariable 108 | } 109 | 110 | // ServerConfigurations stores multiple ServerConfiguration items 111 | // 112 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.ServerConfigurations 113 | type ServerConfigurations []ServerConfiguration 114 | 115 | // Configuration stores the configuration of the API client 116 | // 117 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.Configuration 118 | type Configuration struct { 119 | Host string `json:"host,omitempty"` 120 | Scheme string `json:"scheme,omitempty"` 121 | DefaultHeader map[string]string `json:"defaultHeader,omitempty"` 122 | UserAgent string `json:"userAgent,omitempty"` 123 | Debug bool `json:"debug,omitempty"` 124 | Servers ServerConfigurations 125 | OperationServers map[string]ServerConfigurations 126 | HTTPClient *http.Client 127 | } 128 | 129 | // NewConfiguration returns a new Configuration object 130 | // 131 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewConfiguration 132 | func NewConfiguration() *Configuration { 133 | cfg := &Configuration{ 134 | DefaultHeader: make(map[string]string), 135 | UserAgent: "OpenAPI-Generator/1.0.0/go", 136 | Debug: false, 137 | Servers: ServerConfigurations{ 138 | { 139 | URL: "https://pinning-service.example.com", 140 | Description: "No description provided", 141 | }, 142 | }, 143 | OperationServers: map[string]ServerConfigurations{}, 144 | } 145 | return cfg 146 | } 147 | 148 | // AddDefaultHeader adds a new HTTP header to the default header in the request 149 | func (c *Configuration) AddDefaultHeader(key string, value string) { 150 | c.DefaultHeader[key] = value 151 | } 152 | 153 | // URL formats template on a index using given variables 154 | func (sc ServerConfigurations) URL(index int, variables map[string]string) (string, error) { 155 | if index < 0 || len(sc) <= index { 156 | return "", fmt.Errorf("index %v out of range %v", index, len(sc)-1) 157 | } 158 | server := sc[index] 159 | url := server.URL 160 | 161 | // go through variables and replace placeholders 162 | for name, variable := range server.Variables { 163 | if value, ok := variables[name]; ok { 164 | found := bool(len(variable.EnumValues) == 0) 165 | for _, enumValue := range variable.EnumValues { 166 | if value == enumValue { 167 | found = true 168 | } 169 | } 170 | if !found { 171 | return "", fmt.Errorf("the variable %s in the server URL has invalid value %v. Must be %v", name, value, variable.EnumValues) 172 | } 173 | url = strings.Replace(url, "{"+name+"}", value, -1) 174 | } else { 175 | url = strings.Replace(url, "{"+name+"}", variable.DefaultValue, -1) 176 | } 177 | } 178 | return url, nil 179 | } 180 | 181 | // ServerURL returns URL based on server settings 182 | func (c *Configuration) ServerURL(index int, variables map[string]string) (string, error) { 183 | return c.Servers.URL(index, variables) 184 | } 185 | 186 | func getServerIndex(ctx context.Context) (int, error) { 187 | si := ctx.Value(ContextServerIndex) 188 | if si != nil { 189 | if index, ok := si.(int); ok { 190 | return index, nil 191 | } 192 | return 0, reportError("Invalid type %T should be int", si) 193 | } 194 | return 0, nil 195 | } 196 | 197 | func getServerOperationIndex(ctx context.Context, endpoint string) (int, error) { 198 | osi := ctx.Value(ContextOperationServerIndices) 199 | if osi != nil { 200 | if operationIndices, ok := osi.(map[string]int); !ok { 201 | return 0, reportError("Invalid type %T should be map[string]int", osi) 202 | } else { 203 | index, ok := operationIndices[endpoint] 204 | if ok { 205 | return index, nil 206 | } 207 | } 208 | } 209 | return getServerIndex(ctx) 210 | } 211 | 212 | func getServerVariables(ctx context.Context) (map[string]string, error) { 213 | sv := ctx.Value(ContextServerVariables) 214 | if sv != nil { 215 | if variables, ok := sv.(map[string]string); ok { 216 | return variables, nil 217 | } 218 | return nil, reportError("ctx value of ContextServerVariables has invalid type %T should be map[string]string", sv) 219 | } 220 | return nil, nil 221 | } 222 | 223 | func getServerOperationVariables(ctx context.Context, endpoint string) (map[string]string, error) { 224 | osv := ctx.Value(ContextOperationServerVariables) 225 | if osv != nil { 226 | if operationVariables, ok := osv.(map[string]map[string]string); !ok { 227 | return nil, reportError("ctx value of ContextOperationServerVariables has invalid type %T should be map[string]map[string]string", osv) 228 | } else { 229 | variables, ok := operationVariables[endpoint] 230 | if ok { 231 | return variables, nil 232 | } 233 | } 234 | } 235 | return getServerVariables(ctx) 236 | } 237 | 238 | // ServerURLWithContext returns a new server URL given an endpoint 239 | func (c *Configuration) ServerURLWithContext(ctx context.Context, endpoint string) (string, error) { 240 | sc, ok := c.OperationServers[endpoint] 241 | if !ok { 242 | sc = c.Servers 243 | } 244 | 245 | if ctx == nil { 246 | return sc.URL(0, nil) 247 | } 248 | 249 | index, err := getServerOperationIndex(ctx, endpoint) 250 | if err != nil { 251 | return "", err 252 | } 253 | 254 | variables, err := getServerOperationVariables(ctx, endpoint) 255 | if err != nil { 256 | return "", err 257 | } 258 | 259 | return sc.URL(index, variables) 260 | } 261 | -------------------------------------------------------------------------------- /openapi/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "encoding/json" 14 | "time" 15 | ) 16 | 17 | // PtrBool is a helper routine that returns a pointer to given integer value. 18 | // 19 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrBool 20 | func PtrBool(v bool) *bool { return &v } 21 | 22 | // PtrInt is a helper routine that returns a pointer to given integer value. 23 | // 24 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrInt 25 | func PtrInt(v int) *int { return &v } 26 | 27 | // PtrInt32 is a helper routine that returns a pointer to given integer value. 28 | // 29 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrInt32 30 | func PtrInt32(v int32) *int32 { return &v } 31 | 32 | // PtrInt64 is a helper routine that returns a pointer to given integer value. 33 | // 34 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrInt64 35 | func PtrInt64(v int64) *int64 { return &v } 36 | 37 | // PtrFloat32 is a helper routine that returns a pointer to given float value. 38 | // 39 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrFloat32 40 | func PtrFloat32(v float32) *float32 { return &v } 41 | 42 | // PtrFloat64 is a helper routine that returns a pointer to given float value. 43 | // 44 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrFloat64 45 | func PtrFloat64(v float64) *float64 { return &v } 46 | 47 | // PtrString is a helper routine that returns a pointer to given string value. 48 | // 49 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrString 50 | func PtrString(v string) *string { return &v } 51 | 52 | // PtrTime is helper routine that returns a pointer to given Time value. 53 | // 54 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.PtrTime 55 | func PtrTime(v time.Time) *time.Time { return &v } 56 | 57 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableBool 58 | type NullableBool struct { 59 | value *bool 60 | isSet bool 61 | } 62 | 63 | func (v NullableBool) Get() *bool { 64 | return v.value 65 | } 66 | 67 | func (v *NullableBool) Set(val *bool) { 68 | v.value = val 69 | v.isSet = true 70 | } 71 | 72 | func (v NullableBool) IsSet() bool { 73 | return v.isSet 74 | } 75 | 76 | func (v *NullableBool) Unset() { 77 | v.value = nil 78 | v.isSet = false 79 | } 80 | 81 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableBool 82 | func NewNullableBool(val *bool) *NullableBool { 83 | return &NullableBool{value: val, isSet: true} 84 | } 85 | 86 | func (v NullableBool) MarshalJSON() ([]byte, error) { 87 | return json.Marshal(v.value) 88 | } 89 | 90 | func (v *NullableBool) UnmarshalJSON(src []byte) error { 91 | v.isSet = true 92 | return json.Unmarshal(src, &v.value) 93 | } 94 | 95 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableInt 96 | type NullableInt struct { 97 | value *int 98 | isSet bool 99 | } 100 | 101 | func (v NullableInt) Get() *int { 102 | return v.value 103 | } 104 | 105 | func (v *NullableInt) Set(val *int) { 106 | v.value = val 107 | v.isSet = true 108 | } 109 | 110 | func (v NullableInt) IsSet() bool { 111 | return v.isSet 112 | } 113 | 114 | func (v *NullableInt) Unset() { 115 | v.value = nil 116 | v.isSet = false 117 | } 118 | 119 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableInt 120 | func NewNullableInt(val *int) *NullableInt { 121 | return &NullableInt{value: val, isSet: true} 122 | } 123 | 124 | func (v NullableInt) MarshalJSON() ([]byte, error) { 125 | return json.Marshal(v.value) 126 | } 127 | 128 | func (v *NullableInt) UnmarshalJSON(src []byte) error { 129 | v.isSet = true 130 | return json.Unmarshal(src, &v.value) 131 | } 132 | 133 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableInt32 134 | type NullableInt32 struct { 135 | value *int32 136 | isSet bool 137 | } 138 | 139 | func (v NullableInt32) Get() *int32 { 140 | return v.value 141 | } 142 | 143 | func (v *NullableInt32) Set(val *int32) { 144 | v.value = val 145 | v.isSet = true 146 | } 147 | 148 | func (v NullableInt32) IsSet() bool { 149 | return v.isSet 150 | } 151 | 152 | func (v *NullableInt32) Unset() { 153 | v.value = nil 154 | v.isSet = false 155 | } 156 | 157 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableInt32 158 | func NewNullableInt32(val *int32) *NullableInt32 { 159 | return &NullableInt32{value: val, isSet: true} 160 | } 161 | 162 | func (v NullableInt32) MarshalJSON() ([]byte, error) { 163 | return json.Marshal(v.value) 164 | } 165 | 166 | func (v *NullableInt32) UnmarshalJSON(src []byte) error { 167 | v.isSet = true 168 | return json.Unmarshal(src, &v.value) 169 | } 170 | 171 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableInt64 172 | type NullableInt64 struct { 173 | value *int64 174 | isSet bool 175 | } 176 | 177 | func (v NullableInt64) Get() *int64 { 178 | return v.value 179 | } 180 | 181 | func (v *NullableInt64) Set(val *int64) { 182 | v.value = val 183 | v.isSet = true 184 | } 185 | 186 | func (v NullableInt64) IsSet() bool { 187 | return v.isSet 188 | } 189 | 190 | func (v *NullableInt64) Unset() { 191 | v.value = nil 192 | v.isSet = false 193 | } 194 | 195 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableInt64 196 | func NewNullableInt64(val *int64) *NullableInt64 { 197 | return &NullableInt64{value: val, isSet: true} 198 | } 199 | 200 | func (v NullableInt64) MarshalJSON() ([]byte, error) { 201 | return json.Marshal(v.value) 202 | } 203 | 204 | func (v *NullableInt64) UnmarshalJSON(src []byte) error { 205 | v.isSet = true 206 | return json.Unmarshal(src, &v.value) 207 | } 208 | 209 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableFloat32 210 | type NullableFloat32 struct { 211 | value *float32 212 | isSet bool 213 | } 214 | 215 | func (v NullableFloat32) Get() *float32 { 216 | return v.value 217 | } 218 | 219 | func (v *NullableFloat32) Set(val *float32) { 220 | v.value = val 221 | v.isSet = true 222 | } 223 | 224 | func (v NullableFloat32) IsSet() bool { 225 | return v.isSet 226 | } 227 | 228 | func (v *NullableFloat32) Unset() { 229 | v.value = nil 230 | v.isSet = false 231 | } 232 | 233 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableFloat32 234 | func NewNullableFloat32(val *float32) *NullableFloat32 { 235 | return &NullableFloat32{value: val, isSet: true} 236 | } 237 | 238 | func (v NullableFloat32) MarshalJSON() ([]byte, error) { 239 | return json.Marshal(v.value) 240 | } 241 | 242 | func (v *NullableFloat32) UnmarshalJSON(src []byte) error { 243 | v.isSet = true 244 | return json.Unmarshal(src, &v.value) 245 | } 246 | 247 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableFloat64 248 | type NullableFloat64 struct { 249 | value *float64 250 | isSet bool 251 | } 252 | 253 | func (v NullableFloat64) Get() *float64 { 254 | return v.value 255 | } 256 | 257 | func (v *NullableFloat64) Set(val *float64) { 258 | v.value = val 259 | v.isSet = true 260 | } 261 | 262 | func (v NullableFloat64) IsSet() bool { 263 | return v.isSet 264 | } 265 | 266 | func (v *NullableFloat64) Unset() { 267 | v.value = nil 268 | v.isSet = false 269 | } 270 | 271 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableFloat64 272 | func NewNullableFloat64(val *float64) *NullableFloat64 { 273 | return &NullableFloat64{value: val, isSet: true} 274 | } 275 | 276 | func (v NullableFloat64) MarshalJSON() ([]byte, error) { 277 | return json.Marshal(v.value) 278 | } 279 | 280 | func (v *NullableFloat64) UnmarshalJSON(src []byte) error { 281 | v.isSet = true 282 | return json.Unmarshal(src, &v.value) 283 | } 284 | 285 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableString 286 | type NullableString struct { 287 | value *string 288 | isSet bool 289 | } 290 | 291 | func (v NullableString) Get() *string { 292 | return v.value 293 | } 294 | 295 | func (v *NullableString) Set(val *string) { 296 | v.value = val 297 | v.isSet = true 298 | } 299 | 300 | func (v NullableString) IsSet() bool { 301 | return v.isSet 302 | } 303 | 304 | func (v *NullableString) Unset() { 305 | v.value = nil 306 | v.isSet = false 307 | } 308 | 309 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableString 310 | func NewNullableString(val *string) *NullableString { 311 | return &NullableString{value: val, isSet: true} 312 | } 313 | 314 | func (v NullableString) MarshalJSON() ([]byte, error) { 315 | return json.Marshal(v.value) 316 | } 317 | 318 | func (v *NullableString) UnmarshalJSON(src []byte) error { 319 | v.isSet = true 320 | return json.Unmarshal(src, &v.value) 321 | } 322 | 323 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NullableTime 324 | type NullableTime struct { 325 | value *time.Time 326 | isSet bool 327 | } 328 | 329 | func (v NullableTime) Get() *time.Time { 330 | return v.value 331 | } 332 | 333 | func (v *NullableTime) Set(val *time.Time) { 334 | v.value = val 335 | v.isSet = true 336 | } 337 | 338 | func (v NullableTime) IsSet() bool { 339 | return v.isSet 340 | } 341 | 342 | func (v *NullableTime) Unset() { 343 | v.value = nil 344 | v.isSet = false 345 | } 346 | 347 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewNullableTime 348 | func NewNullableTime(val *time.Time) *NullableTime { 349 | return &NullableTime{value: val, isSet: true} 350 | } 351 | 352 | func (v NullableTime) MarshalJSON() ([]byte, error) { 353 | return v.value.MarshalJSON() 354 | } 355 | 356 | func (v *NullableTime) UnmarshalJSON(src []byte) error { 357 | v.isSet = true 358 | return json.Unmarshal(src, &v.value) 359 | } 360 | -------------------------------------------------------------------------------- /openapi/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * IPFS Pinning Service API 3 | * 4 | * ## About this spec The IPFS Pinning Service API is intended to be an implementation-agnostic API: - For use and implementation by pinning service providers - For use in client mode by IPFS nodes and GUI-based applications > **Note**: while ready for implementation, this spec is still a work in progress! 🏗️ **Your input and feedback are welcome and valuable as we develop this API spec. Please join the design discussion at [github.com/ipfs/pinning-services-api-spec](https://github.com/ipfs/pinning-services-api-spec).** # Schemas This section describes the most important object types and conventions. A full list of fields and schemas can be found in the `schemas` section of the [YAML file](https://github.com/ipfs/pinning-services-api-spec/blob/master/ipfs-pinning-service.yaml). ## Identifiers ### cid [Content Identifier (CID)](https://docs.ipfs.io/concepts/content-addressing/) points at the root of a DAG that is pinned recursively. ### requestid Unique identifier of a pin request. When a pin is created, the service responds with unique `requestid` that can be later used for pin removal. When the same `cid` is pinned again, a different `requestid` is returned to differentiate between those pin requests. Service implementation should use UUID, `hash(accessToken,Pin,PinStatus.created)`, or any other opaque identifier that provides equally strong protection against race conditions. ## Objects ### Pin object ![pin object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pin.png) The `Pin` object is a representation of a pin request. It includes the `cid` of data to be pinned, as well as optional metadata in `name`, `origins`, and `meta`. ### Pin status response ![pin status response object](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/pinstatus.png) The `PinStatus` object is a representation of the current state of a pinning operation. It includes the original `pin` object, along with the current `status` and globally unique `requestid` of the entire pinning request, which can be used for future status checks and management. Addresses in the `delegates` array are peers delegated by the pinning service for facilitating direct file transfers (more details in the provider hints section). Any additional vendor-specific information is returned in optional `info`. ## The pin lifecycle ![pinning service objects and lifecycle](https://bafybeideck2fchyxna4wqwc2mo67yriokehw3yujboc5redjdaajrk2fjq.ipfs.dweb.link/lifecycle.png) ### Creating a new pin object The user sends a `Pin` object to `POST /pins` and receives a `PinStatus` response: - `requestid` in `PinStatus` is the identifier of the pin operation, which can can be used for checking status, and removing the pin in the future - `status` in `PinStatus` indicates the current state of a pin ### Checking status of in-progress pinning `status` (in `PinStatus`) may indicate a pending state (`queued` or `pinning`). This means the data behind `Pin.cid` was not found on the pinning service and is being fetched from the IPFS network at large, which may take time. In this case, the user can periodically check pinning progress via `GET /pins/{requestid}` until pinning is successful, or the user decides to remove the pending pin. ### Replacing an existing pin object The user can replace an existing pin object via `POST /pins/{requestid}`. This is a shortcut for removing a pin object identified by `requestid` and creating a new one in a single API call that protects against undesired garbage collection of blocks common to both pins. Useful when updating a pin representing a huge dataset where most of blocks did not change. The new pin object `requestid` is returned in the `PinStatus` response. The old pin object is deleted automatically. ### Removing a pin object A pin object can be removed via `DELETE /pins/{requestid}`. ## Provider hints Pinning of new data can be accelerated by providing a list of known data sources in `Pin.origins`, and connecting at least one of them to pinning service nodes at `PinStatus.delegates`. The most common scenario is a client putting its own IPFS node's multiaddrs in `Pin.origins`, and then directly connecting to every multiaddr returned by a pinning service in `PinStatus.delegates` to initiate transfer. This ensures data transfer starts immediately (without waiting for provider discovery over DHT), and direct dial from a client works around peer routing issues in restrictive network topologies such as NATs. ## Custom metadata Pinning services are encouraged to add support for additional features by leveraging the optional `Pin.meta` and `PinStatus.info` fields. While these attributes can be application- or vendor-specific, we encourage the community at large to leverage these attributes as a sandbox to come up with conventions that could become part of future revisions of this API. ### Pin metadata String keys and values passed in `Pin.meta` are persisted with the pin object. Potential uses: - `Pin.meta[app_id]`: Attaching a unique identifier to pins created by an app enables filtering pins per app via `?meta={\"app_id\":}` - `Pin.meta[vendor_policy]`: Vendor-specific policy (for example: which region to use, how many copies to keep) Note that it is OK for a client to omit or ignore these optional attributes; doing so should not impact the basic pinning functionality. ### Pin status info Additional `PinStatus.info` can be returned by pinning service. Potential uses: - `PinStatus.info[status_details]`: more info about the current status (queue position, percentage of transferred data, summary of where data is stored, etc); when `PinStatus.status=failed`, it could provide a reason why a pin operation failed (e.g. lack of funds, DAG too big, etc.) - `PinStatus.info[dag_size]`: the size of pinned data, along with DAG overhead - `PinStatus.info[raw_size]`: the size of data without DAG overhead (eg. unixfs) - `PinStatus.info[pinned_until]`: if vendor supports time-bound pins, this could indicate when the pin will expire # Pagination and filtering Pin objects can be listed by executing `GET /pins` with optional parameters: - When no filters are provided, the endpoint will return a small batch of the 10 most recently created items, from the latest to the oldest. - The number of returned items can be adjusted with the `limit` parameter (implicit default is 10). - If the value in `PinResults.count` is bigger than the length of `PinResults.results`, the client can infer there are more results that can be queried. - To read more items, pass the `before` filter with the timestamp from `PinStatus.created` found in the oldest item in the current batch of results. Repeat to read all results. - Returned results can be fine-tuned by applying optional `after`, `cid`, `name`, `status`, or `meta` filters. > **Note**: pagination by the `created` timestamp requires each value to be globally unique. Any future considerations to add support for bulk creation must account for this. 5 | * 6 | * API version: 0.1.1 7 | * Generated by: OpenAPI Generator (https://openapi-generator.tech) 8 | */ 9 | 10 | package openapi 11 | 12 | import ( 13 | "bytes" 14 | "context" 15 | "encoding/json" 16 | "encoding/xml" 17 | "errors" 18 | "fmt" 19 | "io" 20 | "log" 21 | "mime/multipart" 22 | "net/http" 23 | "net/http/httputil" 24 | "net/url" 25 | "os" 26 | "path/filepath" 27 | "reflect" 28 | "regexp" 29 | "strings" 30 | "time" 31 | 32 | "golang.org/x/oauth2" 33 | ) 34 | 35 | var ( 36 | jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`) 37 | xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`) 38 | ) 39 | 40 | // APIClient manages communication with the IPFS Pinning Service API API v0.1.1 41 | // In most cases there should be only one, shared, APIClient. 42 | // 43 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.APIClient 44 | type APIClient struct { 45 | cfg *Configuration 46 | common service // Reuse a single struct instead of allocating one for each service on the heap. 47 | 48 | // API Services 49 | 50 | PinsApi *PinsApiService 51 | } 52 | 53 | type service struct { 54 | client *APIClient 55 | } 56 | 57 | // NewAPIClient creates a new API client. Requires a userAgent string describing your application. 58 | // optionally a custom http.Client to allow for advanced features such as caching. 59 | // 60 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.NewAPIClient 61 | func NewAPIClient(cfg *Configuration) *APIClient { 62 | if cfg.HTTPClient == nil { 63 | cfg.HTTPClient = http.DefaultClient 64 | } 65 | 66 | c := &APIClient{} 67 | c.cfg = cfg 68 | c.common.client = c 69 | 70 | // API Services 71 | c.PinsApi = (*PinsApiService)(&c.common) 72 | 73 | return c 74 | } 75 | 76 | // selectHeaderContentType select a content type from the available list. 77 | func selectHeaderContentType(contentTypes []string) string { 78 | if len(contentTypes) == 0 { 79 | return "" 80 | } 81 | if contains(contentTypes, "application/json") { 82 | return "application/json" 83 | } 84 | return contentTypes[0] // use the first content type specified in 'consumes' 85 | } 86 | 87 | // selectHeaderAccept join all accept types and return 88 | func selectHeaderAccept(accepts []string) string { 89 | if len(accepts) == 0 { 90 | return "" 91 | } 92 | 93 | if contains(accepts, "application/json") { 94 | return "application/json" 95 | } 96 | 97 | return strings.Join(accepts, ",") 98 | } 99 | 100 | // contains is a case insenstive match, finding needle in a haystack 101 | func contains(haystack []string, needle string) bool { 102 | for _, a := range haystack { 103 | if strings.EqualFold(a, needle) { 104 | return true 105 | } 106 | } 107 | return false 108 | } 109 | 110 | // parameterToString convert interface{} parameters to string, using a delimiter if format is provided. 111 | func parameterToString(obj interface{}, collectionFormat string) string { 112 | var delimiter string 113 | 114 | switch collectionFormat { 115 | case "pipes": 116 | delimiter = "|" 117 | case "ssv": 118 | delimiter = " " 119 | case "tsv": 120 | delimiter = "\t" 121 | case "csv": 122 | delimiter = "," 123 | } 124 | 125 | if reflect.TypeOf(obj).Kind() == reflect.Slice { 126 | return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") 127 | } else if t, ok := obj.(time.Time); ok { 128 | return t.Format(time.RFC3339Nano) 129 | } 130 | 131 | return fmt.Sprintf("%v", obj) 132 | } 133 | 134 | // callAPI do the request. 135 | func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { 136 | if c.cfg.Debug { 137 | dump, err := httputil.DumpRequestOut(request, true) 138 | if err != nil { 139 | return nil, err 140 | } 141 | log.Printf("\n%s\n", string(dump)) 142 | } 143 | 144 | resp, err := c.cfg.HTTPClient.Do(request) 145 | if err != nil { 146 | return resp, err 147 | } 148 | 149 | if c.cfg.Debug { 150 | dump, err := httputil.DumpResponse(resp, true) 151 | if err != nil { 152 | return resp, err 153 | } 154 | log.Printf("\n%s\n", string(dump)) 155 | } 156 | return resp, err 157 | } 158 | 159 | // Allow modification of underlying config for alternate implementations and testing 160 | // Caution: modifying the configuration while live can cause data races and potentially unwanted behavior 161 | func (c *APIClient) GetConfig() *Configuration { 162 | return c.cfg 163 | } 164 | 165 | // prepareRequest build the request 166 | func (c *APIClient) prepareRequest( 167 | ctx context.Context, 168 | path string, method string, 169 | postBody interface{}, 170 | headerParams map[string]string, 171 | queryParams url.Values, 172 | formParams url.Values, 173 | formFileName string, 174 | fileName string, 175 | fileBytes []byte) (localVarRequest *http.Request, err error) { 176 | 177 | var body *bytes.Buffer 178 | 179 | // Detect postBody type and post. 180 | if postBody != nil { 181 | contentType := headerParams["Content-Type"] 182 | if contentType == "" { 183 | contentType = detectContentType(postBody) 184 | headerParams["Content-Type"] = contentType 185 | } 186 | 187 | body, err = setBody(postBody, contentType) 188 | if err != nil { 189 | return nil, err 190 | } 191 | } 192 | 193 | // add form parameters and file if available. 194 | if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { 195 | if body != nil { 196 | return nil, errors.New("cannot specify postBody and multipart form at the same time") 197 | } 198 | body = &bytes.Buffer{} 199 | w := multipart.NewWriter(body) 200 | 201 | for k, v := range formParams { 202 | for _, iv := range v { 203 | if strings.HasPrefix(k, "@") { // file 204 | err = addFile(w, k[1:], iv) 205 | if err != nil { 206 | return nil, err 207 | } 208 | } else { // form value 209 | w.WriteField(k, iv) 210 | } 211 | } 212 | } 213 | if len(fileBytes) > 0 && fileName != "" { 214 | w.Boundary() 215 | //_, fileNm := filepath.Split(fileName) 216 | part, err := w.CreateFormFile(formFileName, filepath.Base(fileName)) 217 | if err != nil { 218 | return nil, err 219 | } 220 | _, err = part.Write(fileBytes) 221 | if err != nil { 222 | return nil, err 223 | } 224 | } 225 | 226 | // Set the Boundary in the Content-Type 227 | headerParams["Content-Type"] = w.FormDataContentType() 228 | 229 | // Set Content-Length 230 | headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 231 | w.Close() 232 | } 233 | 234 | if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { 235 | if body != nil { 236 | return nil, errors.New("cannot specify postBody and x-www-form-urlencoded form at the same time") 237 | } 238 | body = &bytes.Buffer{} 239 | body.WriteString(formParams.Encode()) 240 | // Set Content-Length 241 | headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) 242 | } 243 | 244 | // Setup path and query parameters 245 | url, err := url.Parse(path) 246 | if err != nil { 247 | return nil, err 248 | } 249 | 250 | // Override request host, if applicable 251 | if c.cfg.Host != "" { 252 | url.Host = c.cfg.Host 253 | } 254 | 255 | // Override request scheme, if applicable 256 | if c.cfg.Scheme != "" { 257 | url.Scheme = c.cfg.Scheme 258 | } 259 | 260 | // Adding Query Param 261 | query := url.Query() 262 | for k, v := range queryParams { 263 | for _, iv := range v { 264 | query.Add(k, iv) 265 | } 266 | } 267 | 268 | // Encode the parameters. 269 | url.RawQuery = query.Encode() 270 | 271 | // Generate a new request 272 | if body != nil { 273 | localVarRequest, err = http.NewRequest(method, url.String(), body) 274 | } else { 275 | localVarRequest, err = http.NewRequest(method, url.String(), nil) 276 | } 277 | if err != nil { 278 | return nil, err 279 | } 280 | 281 | // add header parameters, if any 282 | if len(headerParams) > 0 { 283 | headers := http.Header{} 284 | for h, v := range headerParams { 285 | headers.Set(h, v) 286 | } 287 | localVarRequest.Header = headers 288 | } 289 | 290 | // Add the user agent to the request. 291 | localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) 292 | 293 | if ctx != nil { 294 | // add context to the request 295 | localVarRequest = localVarRequest.WithContext(ctx) 296 | 297 | // Walk through any authentication. 298 | 299 | // OAuth2 authentication 300 | if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { 301 | // We were able to grab an oauth2 token from the context 302 | var latestToken *oauth2.Token 303 | if latestToken, err = tok.Token(); err != nil { 304 | return nil, err 305 | } 306 | 307 | latestToken.SetAuthHeader(localVarRequest) 308 | } 309 | 310 | // Basic HTTP Authentication 311 | if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { 312 | localVarRequest.SetBasicAuth(auth.UserName, auth.Password) 313 | } 314 | 315 | // AccessToken Authentication 316 | if auth, ok := ctx.Value(ContextAccessToken).(string); ok { 317 | localVarRequest.Header.Add("Authorization", "Bearer "+auth) 318 | } 319 | } 320 | 321 | for header, value := range c.cfg.DefaultHeader { 322 | localVarRequest.Header.Add(header, value) 323 | } 324 | return localVarRequest, nil 325 | } 326 | 327 | func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { 328 | if len(b) == 0 { 329 | return nil 330 | } 331 | if s, ok := v.(*string); ok { 332 | *s = string(b) 333 | return nil 334 | } 335 | if xmlCheck.MatchString(contentType) { 336 | if err = xml.Unmarshal(b, v); err != nil { 337 | return err 338 | } 339 | return nil 340 | } 341 | if jsonCheck.MatchString(contentType) { 342 | if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas 343 | if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok { // make sure it has UnmarshalJSON defined 344 | if err = unmarshalObj.UnmarshalJSON(b); err != nil { 345 | return err 346 | } 347 | } else { 348 | return errors.New("unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined") 349 | } 350 | } else if err = json.Unmarshal(b, v); err != nil { // simple model 351 | return err 352 | } 353 | return nil 354 | } 355 | return errors.New("undefined response type") 356 | } 357 | 358 | // Add a file to the multipart request 359 | func addFile(w *multipart.Writer, fieldName, path string) error { 360 | file, err := os.Open(path) 361 | if err != nil { 362 | return err 363 | } 364 | defer file.Close() 365 | 366 | part, err := w.CreateFormFile(fieldName, filepath.Base(path)) 367 | if err != nil { 368 | return err 369 | } 370 | _, err = io.Copy(part, file) 371 | 372 | return err 373 | } 374 | 375 | // Prevent trying to import "fmt" 376 | func reportError(format string, a ...interface{}) error { 377 | return fmt.Errorf(format, a...) 378 | } 379 | 380 | // Set request body from an interface{} 381 | func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { 382 | if bodyBuf == nil { 383 | bodyBuf = &bytes.Buffer{} 384 | } 385 | 386 | if reader, ok := body.(io.Reader); ok { 387 | _, err = bodyBuf.ReadFrom(reader) 388 | } else if b, ok := body.([]byte); ok { 389 | _, err = bodyBuf.Write(b) 390 | } else if s, ok := body.(string); ok { 391 | _, err = bodyBuf.WriteString(s) 392 | } else if s, ok := body.(*string); ok { 393 | _, err = bodyBuf.WriteString(*s) 394 | } else if jsonCheck.MatchString(contentType) { 395 | err = json.NewEncoder(bodyBuf).Encode(body) 396 | } else if xmlCheck.MatchString(contentType) { 397 | err = xml.NewEncoder(bodyBuf).Encode(body) 398 | } 399 | 400 | if err != nil { 401 | return nil, err 402 | } 403 | 404 | if bodyBuf.Len() == 0 { 405 | err = fmt.Errorf("invalid body type %s", contentType) 406 | return nil, err 407 | } 408 | return bodyBuf, nil 409 | } 410 | 411 | // detectContentType method is used to figure out `Request.Body` content type for request header 412 | func detectContentType(body interface{}) string { 413 | contentType := "text/plain; charset=utf-8" 414 | kind := reflect.TypeOf(body).Kind() 415 | 416 | switch kind { 417 | case reflect.Struct, reflect.Map, reflect.Ptr: 418 | contentType = "application/json; charset=utf-8" 419 | case reflect.String: 420 | contentType = "text/plain; charset=utf-8" 421 | default: 422 | if b, ok := body.([]byte); ok { 423 | contentType = http.DetectContentType(b) 424 | } else if kind == reflect.Slice { 425 | contentType = "application/json; charset=utf-8" 426 | } 427 | } 428 | 429 | return contentType 430 | } 431 | 432 | // Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go 433 | type cacheControl map[string]string 434 | 435 | func parseCacheControl(headers http.Header) cacheControl { 436 | cc := cacheControl{} 437 | ccHeader := headers.Get("Cache-Control") 438 | for _, part := range strings.Split(ccHeader, ",") { 439 | part = strings.Trim(part, " ") 440 | if part == "" { 441 | continue 442 | } 443 | if strings.ContainsRune(part, '=') { 444 | keyval := strings.Split(part, "=") 445 | cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") 446 | } else { 447 | cc[part] = "" 448 | } 449 | } 450 | return cc 451 | } 452 | 453 | // CacheExpires helper function to determine remaining time before repeating a request. 454 | // 455 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.CacheExpires 456 | func CacheExpires(r *http.Response) time.Time { 457 | // Figure out when the cache expires. 458 | var expires time.Time 459 | now, err := time.Parse(time.RFC1123, r.Header.Get("date")) 460 | if err != nil { 461 | return time.Now() 462 | } 463 | respCacheControl := parseCacheControl(r.Header) 464 | 465 | if maxAge, ok := respCacheControl["max-age"]; ok { 466 | lifetime, err := time.ParseDuration(maxAge + "s") 467 | if err != nil { 468 | expires = now 469 | } else { 470 | expires = now.Add(lifetime) 471 | } 472 | } else { 473 | expiresHeader := r.Header.Get("Expires") 474 | if expiresHeader != "" { 475 | expires, err = time.Parse(time.RFC1123, expiresHeader) 476 | if err != nil { 477 | expires = now 478 | } 479 | } 480 | } 481 | return expires 482 | } 483 | 484 | // GenericOpenAPIError Provides access to the body, error and model on returned errors. 485 | // 486 | // Deprecated: use github.com/ipfs/boxo/pinning/remote/client/openapi.GenericOpenAPIError 487 | type GenericOpenAPIError struct { 488 | body []byte 489 | error string 490 | model interface{} 491 | } 492 | 493 | // Error returns non-empty string if there was an error. 494 | func (e GenericOpenAPIError) Error() string { 495 | return e.error 496 | } 497 | 498 | // Body returns the raw bytes of the response 499 | func (e GenericOpenAPIError) Body() []byte { 500 | return e.body 501 | } 502 | 503 | // Model returns the unpacked model of the error 504 | func (e GenericOpenAPIError) Model() interface{} { 505 | return e.model 506 | } 507 | --------------------------------------------------------------------------------